Хвалёный Уникод не работает

Общие вопросы, не зависящие от языка реализации.

Модераторы: Duncon, Hawk, Romeo, Eugie

programisto
Сообщения: 12
Зарегистрирован: 11 авг 2009, 16:24

Текст в Уникоде отображается в Комбобоксе и Ричедите неправильно. Combobox съедает значки над буквами, а Richedit заменяет нетривиальные буквы вопросительными значками. Английские буквы отображаются правильно. TextOutW отображает весь текст правильно.
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

Наверно caм что-то делаешь неправильно.
Поумнеть несложно, куда труднее от дури избавиться.
Eugie
Сообщения: 708
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

Чтобы контролы правильно отрисовывали Unicode-строки, должны выполняться несколько условий:
- версия ОС должна поддерживать Unicode (для современных версий Windows выполняется автоматически);
- само приложение должно быть скомпилировано с поддержкой Unicode (это важно, т.к. почти все функции WinAPI, принимающие строки в качестве параметров, существуют в 2 версиях - ANSI и WideChar(Unicode) - вот почему, кстати, TextOutW работает нормально);
- шрифт контрола должен поддерживать соответствующий набор символов. Например, по умолчанию часто используется растровый MS Sans Serif - естественно, не стоит ждать, что он корректно отобразит иероглифы :)
programisto
Сообщения: 12
Зарегистрирован: 11 авг 2009, 16:24

Decoder писал(а):Наверно caм что-то делаешь неправильно.
Вот и хочу знать, что я делаю неправильно.

Пишу командой SendMessageW.

Что ещё нужно для счастья?
Eugie
Сообщения: 708
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

См здесь:
http://msdn.microsoft.com/en-us/library ... S.85).aspx (особенности поддержки Unicode для RichEdit)
http://www.codeguru.com/cpp/misc/misc/w ... php/c10251 (пример внедрения Unicode в ANSI приложение)
programisto
Сообщения: 12
Зарегистрирован: 11 авг 2009, 16:24

Eugie писал(а):Чтобы контролы правильно отрисовывали Unicode-строки, должны выполняться несколько условий:
- версия ОС должна поддерживать Unicode (для современных версий Windows выполняется автоматически);
- само приложение должно быть скомпилировано с поддержкой Unicode (это важно, т.к. почти все функции WinAPI, принимающие строки в качестве параметров, существуют в 2 версиях - ANSI и WideChar(Unicode) - вот почему, кстати, TextOutW работает нормально);
- шрифт контрола должен поддерживать соответствующий набор символов. Например, по умолчанию часто используется растровый MS Sans Serif - естественно, не стоит ждать, что он корректно отобразит иероглифы :)
Работаю в Висте.

Программа на Ассемблере. Пользуюсь правильной функцией для вывода -
SendMessageW.

А почему Sans Sherif не отобразит иероглифы? Для Sans Sherif Уникод другой?
Иероглифы мне рисовать и не нужно, только несколько европейских
кодировок да кириллицу.
Как сменить фонт? Я пытался в комбобоксе применять следующие эвиваленты команд C:

hDC = GetDC(hComboBox);
SelectObject(hDC, hFont);

Причём hFont применялся в других объектах и работает правильно (в том числе правильно пишет Уникод). Но в комбобоксе ничего не изменилось - ни фонт, ни отображение Уникода.
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Как сменить фонт? Я пытался в комбобоксе применять следующие эвиваленты команд C:

hDC = GetDC(hComboBox);
SelectObject(hDC, hFont);

Это неправильно.
Передавать окну значение hFont нужно через сообщение WM_SETFONT.

SelectObject(hDC, hFont); нужно применять лишь в том случае, когда ты сам выполняешь отрисовку данного контрола в обработчике сообщения WM_PAINT.
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

Здесь ещё играет роль кодировка самой строки.
Если в С++ написать код:

Код: Выделить всё

LPWSTR wszText = L"Привет всем!";
то компилятор сам преобразует данную строку в кодировку UNICODE.
Если строка изначально была представлена как массив однобайтовых символов, то её нужно будет преобразовать в UNICODE с помощью функции MultibyteToWideChar. Причём исходная строка должна быть записана в кодировке Windows-1251, а не в кодировке OEM (DOS-866). Вполне возможно что исходный текст программы был набран в кодировке OEM (если код писался не в Visual Studio, а в другом редакторе).
Поумнеть несложно, куда труднее от дури избавиться.
Eugie
Сообщения: 708
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

А почему Sans Sherif не отобразит иероглифы? Для Sans Sherif Уникод другой?
Дело в том, что растровые шрифты не поддерживают Unicode. Они разработаны для 8-битной кодировки символов, поэтому никак не могут отображать полный набор Unicode. Грубо говоря, растровый шрифт - это набор битмапов для какого-то конкретного набора символов (character set), причем не более 255. Современные шрифты TrueType и OpenType - это скорее программа на спец. языке, каждый символ представляет что-то типа метафайла для отрисовщика. Такая технология позволяет "красиво" масштабировать шрифт, вращать и т.д. - короче, делает его device independent. И главное, в контескте вашего вопроса, снимает ограничение на размер набора символов. Но из практических соображений даже TT/OT шрифты не поддерживает полный набор символов Unicode. Запустите замечательную программу "Таблица символов" и поиграйтесь с параметрами Набор символов и Группировка - увидите сами.

Если вам достаточно только кириллицы и расширенного набора латиницы с диакритическми знаками, вам подойдет практически любой TT/OT шрифт.
Как сменить фонт?
Собственно, WinMain ответил. Могу только добавить, что если контролы лежат на диалоговом окне, для которого установлены стили DS_SETFONT либо DS_SHELLFONT, оно само рассылает сообщение WM_SETFONT дочерним окнам, используя шрифт, указанный в секции FONT шаблона диалога (обычно это системный растровый шрифт). В этом случае нужно устанавливать нужный шрифт для контрола в обработчике сообщения WM_INITDIALOG.

Еще совет: не пытайтесь самостоятельно обрабатывать WM_PAINT для стандартных контролов. Не буду объяснять почему, просто поверьте на слово :)
programisto
Сообщения: 12
Зарегистрирован: 11 авг 2009, 16:24

Eugie писал(а):См здесь:
http://msdn.microsoft.com/en-us/library ... S.85).aspx (особенности поддержки Unicode для RichEdit)
http://www.codeguru.com/cpp/misc/misc/w ... php/c10251 (пример внедрения Unicode в ANSI приложение)
Прочитал первую ссылку. Заменил класс "RichEdit20A" на "RichEdit20W" - ничего не изменилось.
--------------------------------------------------------------------------------
Добавлено сообщение
--------------------------------------------------------------------------------
Decoder писал(а):Здесь ещё играет роль кодировка самой строки.
Если в С++ написать код:

Код: Выделить всё

LPWSTR wszText = L"Привет всем!";
то компилятор сам преобразует данную строку в кодировку UNICODE.
Если строка изначально была представлена как массив однобайтовых символов, то её нужно будет преобразовать в UNICODE с помощью функции MultibyteToWideChar. Причём исходная строка должна быть записана в кодировке Windows-1251, а не в кодировке OEM (DOS-866). Вполне возможно что исходный текст программы был набран в кодировке OEM (если код писался не в Visual Studio, а в другом редакторе).
Я явно преобразовывал при помощи MultibyteToWideChar. Переводилось правильно, так как TextOutW выводит правильно. Программа новая, не набиралась в ДОСе.
--------------------------------------------------------------------------------
Добавлено сообщение
--------------------------------------------------------------------------------
WinMain писал(а):Это неправильно.
Передавать окну значение hFont нужно через сообщение WM_SETFONT.

SelectObject(hDC, hFont); нужно применять лишь в том случае, когда ты сам выполняешь отрисовку данного контрола в обработчике сообщения WM_PAINT.
WM_SETFONT правильно устанавливает фонт. Однако выводится Уникод всё равно неправильно, съедает значок над буквой. Тот же фонт при помощи TextOutW выводится правильно.
Ответить