Показать сообщение отдельно
  #1  
Старый 06.04.2021, 11:01
anna_sidorova anna_sidorova вне форума
Прохожий
 
Регистрация: 06.04.2021
Сообщения: 3
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию Крякозябры вместо русских символов в Windows 10 - при опции Использовать Юникод

Здравствуйте!



Есть программный код на Delphi 7, нормально работает под Windows XP/Vista/7/8/8.1 и до определенных пор на Windows 10. Работает практически при любых языковых настройках - т. к. для борьбы с крякозябрами на англоязычных XP/7 использовала

SetThreadLocale(1049)
RUSSIAN_CHARSET - в кодировке компонентов, шрифт Arial вместо стандартного MS Sans Serif
и прочие ухищрения, что нашла в Сети - таким образом, добилась того, что всё нормально работает практически под любой Windows - при любых языковых настройках (даже если англоязычная Windows и основной язык - французский)

Однако, в последних версиях Windows 10 в языковых настройках появилась опция

"Бета-версия: Использовать Юникод (UTC-8) для поддержки языка во всем мире"/"Use Unicode UTF-8 for worldwide language support" - которая в некоторых случаях включена по умолчанию (кроме того, после её отключения - чтобы изменения вступили в силу - компьютер нужно перезагружать). Если эта опция включена - в программе вместо русских букв отображаются крякозябры и никакие ухищрения не помогают это исправить - кроме отключения данной галочки. Мне нужно - чтобы программа нормально отображала русские буквы - независимо от состояния данной галочки.

Как я понимаю (возможно, ошибаюсь) - нужно как-то перехватывать WinAPI-метод из Kernel32.dll GetACP. В нормальном состоянии эта функция должна возвращать 1251. Она и возвращает 1251 в том числе на Windows 10 - при отключении этой галочки. При включении галочки данная функция возвращает 65001 и программа отображается с крякозябрами.

Что пробовала:

1) Перехват функции GetACP - с помощью сплайсинга. Запускаю программу под отладчиком, нахожу адрес процедуры GetACP - в начало этого кода ставлю jmp на свою, правильную функцию, которая возвращает требуемое значение 1251.

Результат такой - всё хорошо, функция GetACP теперь возвращает правильное значение 1251 (вместо 65001) - однако, в программе вообще ничего не меняется. Всё равно всё отображается с крякозябрами.

2) Пыталась использовать недокументированную функцию

SetCPGlobal(1251);

После этого GetACP возвращает правильное значение. Проблема только в том, что работает эта недокументированная функция только на Windows XP - но на XP и без неё всё нормально работает. На Windows 7 и Windows 10 - при попытке использовать данную функцию - при запуске программы выходит сообщение

Точка входа в процедуру SetCPGlobal не найдена в библиотеке Kernel32.dll

и программа завершает свою работу

3) Пыталась найти - где же функция GetACP получает значение 65001 - чтобы прописать по этому адресу 1251 (как говорят на форумах, это адрес переменной gAnsiCodePage в модуле KernelBase.dll). Нашла адрес - область, откуда берётся это значение, там как раз записано значение 65001. Перезаписываю данную область памяти в значение 1251 с помощью ассемблерной вставки - после этого функция GetACP возвращает значение 1251. На Windows 7:

..............................
MyGetACP := GetProcAddressInDll('KernelBase.dll', 'GetACP');
z := ReadMemoryDword(1+integer(Addr(MyGetACP)));
WriteMemoryDword(z, 1251); //rewrite value of variable - where keeping GetACP
ShowMessage('GetACP: '+inttostr(GetACP)) //на Windows 7 работает
..............................

На Windows 10 же (где и требуется решить вопрос с крякозябрами) получается совсем по-другому. Как только пытаюсь перезаписать значение данной ячейки в 1251 - тут же появляется ошибка

Exception EAccessViolation in module KernelBase.dll at 000F69ED. Access violation at address 76D269ED in module 'KernelBase.dll'. Read of address 00000002.

и программа вылетает. При этом перезапись ячейки памяти делаю как полагается - перед перезаписью устанавливаю признак PAGE_EXECUTE_READWRITE для перезаписываемой области памяти: VirtualProtect(pointer(a), 16, PAGE_EXECUTE_READWRITE, OldProtect)

Пробовала в качестве экспериментов записывать в эту ячейку значения 1252, 65001 (то есть исходное значение) и даже 9999 - всё отрабатывает нормально (но потом в ходе работы программы возникают ошибки). Если же записать 1251 - программа вылетает сразу.


Возникает вопрос - что делать, чтобы программа работала на Windows 10 без крякозябр вместо русских букв при включенной опции "Бета-версия: Использовать Юникод (UTC-8) для поддержки языка во всем мире". Варианты перейти с Delphi 7 на другую, более новую версию - не предлагать (очень много старого кода придётся переписывать, который при переписывании может начать глючить и т. д.) Варианты с TntComponents и JEDI тоже не подойдут - т. к. программа содержит гигантское количество старого программного кода - где используются стандартные компоненты TLabel, TButton, TEdit - даже если новый код писать на JEDI - надо чтобы старый код и старые формы работали без крякозябр.

Как правильно перехватить GetACP, чтобы она всегда возвращала значение 1251? Как заставить программу работать без крякозябр? Дело ведь в GetACP - туда надо копать или в чем можем быть дело?



С уважением, Сидорова А. П.
Ответить с цитированием