Delphi 7 - Почему Windows 7 меняет кодировку символов во время выполнения? - PullRequest
6 голосов
/ 31 марта 2010

У меня есть форма delphi 7:

Форма http://i44.tinypic.com/13ymott.jpg

и мой код:

Код http://i44.tinypic.com/x1gh9c.jpg

когда я запускаю эту форму в Windows 7, я вижу:

Windows7Form http://i41.tinypic.com/riglzl.jpg

Во время разработки у формы были полированные буквы в первой метке, но они не имеют их во время выполнения. Это выглядит нормально на Vista или Windows XP. Когда я устанавливаю заголовок второй метки в коде, все работает нормально и символы правильно кодируются.

Первые 5 кодов верхней метки в Windows 7: 65 97 69 101 83

Первые 5 кодов верхней метки в Windows Vista / XP: 165 185 202 234 140

Первые 5 кодов нижней метки в каждой системе: 165 185 202 234 140

Windows 7 меняет кодировку, почему? Настройки моей системы вроде бы в порядке. В панели управления установлен правильный язык для приложений, не поддерживающих Юникод.

EDIT

Эта проблема связана не только с метками на формах, но и с FastReport (где переключение на EASTERN_CHARSET решает проблему) или с доступом к Microsoft Excel через интерфейс COM.

Ответы [ 4 ]

2 голосов
/ 02 апреля 2010

Вы столкнулись с тем, что я считаю "ошибкой" в методах TWriter.WriteString и TWriter.ReadString. Эти два метода внутренне используются Delphi для перемещения вашего TLabel.Caption из реального живого объекта во время разработки в файл DFM, а затем обратно в живой объект во время выполнения.

Если вы посмотрите на код для упомянутых двух подпрограмм, вы заметите (я полагаю, в шоке), что фактический материал, который входит в поток, конвертируется в Unicode с использованием кодовой страницы операционной системы по умолчанию! Это прекрасно и прекрасно, если кодовая страница, используемая на компьютере разработчика, точно совпадает с кодовой страницей, используемой на тестовой машине, и, вероятно, они не совпадают, и, скорее всего, вы получаете ошибку. Обратите внимание, что значение EASTEUROPEAN_CHARSET, которое вы устанавливаете для подписи в форме, не имеет абсолютно никакого значения, поскольку метод TWriter.WriteString не имеет представления об этом!

У меня есть отчет об ошибке по этому вопросу на КК, он был там много лет ... Они, вероятно, думают, что это "нарочно", но я не думаю, что это очень хороший дизайн.

Решение, которое я бы рекомендовал, - это быстрый переход на Delphi 2010. Я разработчик Delphi в Румынии, и у меня было много проблем с такими вещами, но теперь это все в прошлом, потому что Delphi 2010 - это UNICODE, поэтому мне больше не нужно беспокоиться о преобразованиях кодовых страниц.

Если вы не можете переключиться на Delphi 2010, возможно, вы захотите «взломать» файл Classes.pas и изменить процедуру TReader.ReadString, чтобы всегда выполнять преобразование с использованием ВАШЕЙ кодовой страницы, а не системы по умолчанию.

2 голосов
/ 31 марта 2010

Я воспроизвел поведение в Delphi 2010 в Win XP.

procedure Button1Click(Sender : TObject);
begin
  ShowMessage(AnsiString(Label1.Caption));
end;

В этой ситуации преобразование Label1.Caption в AnsiString выполняется через WideCharToMultiByte (Windows API).

API имеет следующее примечание:

Кодовые страницы ANSI могут отличаться на разных компьютерах, или может быть поменял на один компьютер, ведущий к повреждению данных. Для большинства последовательные результаты, приложения следует использовать Unicode, например UTF-8 или UTF-16 вместо конкретного кода страница, если унаследованные стандарты или данные форматы не позволяют использовать Unicode. Если использование Unicode невозможно, приложения должны пометить данные поток с соответствующей кодировкой имя, когда протоколы позволяют это. HTML и XML-файлы позволяют теги, но текст файлов нет.

Итак, мое лучшее предположение заключается в том, что разница в поведении обусловлена ​​тем фактом, что в вашей версии Windows 7 активная кодовая страница отличается от используемой на ваших Vista / XP станциях.

Мне все еще нужно найти, как получить активную кодовую страницу в системе ... Я думаю, что она определяется в региональных настройках панели управления. Но мне все еще нужно это проверить ...

1 голос
/ 01 апреля 2010

Ответы на этот вопрос решают мою проблему:

GetThreadLocale возвращает значение, отличное от GetUserDefaultLCID?

Одно решение:

Странная вещь, которую мы обнаружили, заключается в том, что переключение на другие региональные настройки через панель управления, а затем переключение обратно в NZ решает проблему. Мне было бы любопытно узнать, разрешит ли это тот же обходной путь для вас, просто чтобы убедиться, что мы видим одно и то же явление.

и второй:

initialization
  SetThreadLocale(LOCALE_USER_DEFAULT);
  GetFormatSettings;

Оба решения отлично работают, и проблема с приложением исчезает.

0 голосов
/ 31 марта 2010

Проверьте свойство Font.Charset метки. Хотя я не знаю, как это изменилось (было ли оно предварительно создано для какого-нибудь мастера?) - оно может отличаться от системного.

...