Как я могу проверить приложение Windows для правильной обработки Unicode?
Я не могу использовать предварительно упакованные строковые библиотеки Unicode, такие как ICU, потому что они взорвали размер двоичного файла до безумной степени (это программа 200k, ICU - 16 МБ +!).
Я использую встроенный тип строки wchar_t
для всех уже, но я хочу, чтобы я не делал ничего глупого с точки зрения выполнения итераций в строках или таких вещей.
Существуют ли такие инструменты, как Fuzzers, для безопасности, но для Unicode? То есть, выкидывайте символы вне базовой многоязычной плоскости в свой код и гарантируйте, что все будет правильно обрабатываться как UTF-16?
(О, и, очевидно, кросс-платформенное решение работает, хотя большинство кросс-платформенных вещей должны поддерживать как UTF-8, так и UTF-16)
EDIT. Также обратите внимание на вещи, которые менее очевидны, чем суррогатные пары UTF-16 - такие вещи, как знаки акцента!
Ответы
Ответ 1
Некоторые вещи для проверки:
-
Убедитесь, что вместо передачи WM_CHAR
вы обрабатываете WM_UNICHAR
:
Сообщение WM_UNICHAR
совпадает с WM_CHAR
, за исключением того, что использует UTF-32. Он предназначен для отправки или отправки символов Unicode в ANSI-окна, а - для обработки символов Unicode Additional Plane.
-
Do not предположим, что символ я th находится в индексе i
. Очевидно, это не так, и если вам случится использовать этот факт, скажем, сломав строку пополам, тогда вы можете испортить ее.
-
Не указывайте пользователю (в строке состояния или что-то еще), что пользователь имеет N символов только потому, что массив символов имеет длину N.
Ответ 2
Неверный ответ
Используйте WM_UNICHAR
, он обрабатывает UTF-32 и может обрабатывать символы дополнительной плоскости Unicode.
Пока это почти так, но полная правда выглядит так:
-
WM_UNICHAR
- это взлом, предназначенный для ANSI Windows для получения символов Unicode. Создайте окно Unicode, и вы его никогда не получите.
- Создайте окно ANSI, и вы будете удивлены, что он по-прежнему не работает должным образом. Уловка заключается в том, что при создании окна вы получаете
WM_UNICHAR
с 0xffff
, с которым вы должны реагировать, возвращая 1 (по умолчанию процедура окна возвращает 0). Не получится, и вы больше никогда не увидите WM_UNICHAR
. Хорошая работа, о которой не говорится в официальной документации.
- Запустите программу в системе, которая по таинственным причинам не поддерживает
WM_UNICHAR
(например, мою систему Windows 7 64), и она все равно не будет работать, даже если вы все сделаете правильно.
Теоретически правильный ответ
Нет ничего, на что нужно обратить внимание или обратить внимание.
Скомпилируйте с помощью UNICODE
или явным образом создайте свой оконный класс, а также свое окно, используя функцию "W
", и используйте WM_CHAR
, как если бы это было наиболее естественным делом. Это. Это действительно самая естественная вещь.
WM_CHAR
использует UTF-16 (за исключением случаев, когда он отсутствует, например, в Windows 2000). Конечно, один символ UTF-16 не может представлять кодовые точки вне BMP, но это не проблема, потому что вы просто получаете два сообщения WM_CHAR
, содержащие суррогатную пару. Он полностью прозрачен для вашего приложения, вам не нужно ничего делать особо. Любая функция Windows API, которая принимает широкую строку символов, тоже с удовольствием примет эти суррогаты.
Единственное, о чем нужно знать, это то, что теперь длина символа строки (очевидно) больше не просто число 16-битных слов. Но это было неправильное предположение, во всяком случае.
Печальная правда
В действительности, во многих (большинство? все?) системах вы получаете только одно сообщение WM_CHAR
с wParam
, содержащим младшие 16 бит key code. Что является могучим штрафом для чего-либо в BMP, но отстой в противном случае.
Я проверил это как с помощью кодов клавиш Alt-keypad, так и с созданием пользовательской раскладки клавиатуры, которая генерирует кодовые точки вне BMP. В любом случае принимается только один WM_CHAR
, содержащий младшие 16 бит символа. Верхние 16 бит просто выбрасываются.
Чтобы ваша программа правильно работала с Unicode на 100%, вы, очевидно, должны использовать диспетчер методов ввода (ImmGetCompositionStringW
), что является неприятным и плохо документированным. Для меня лично это просто означает: "ОК, винт". Но если вы заинтересованы в том, чтобы быть на 100% правильным, посмотрите исходный код любого редактора, используя Scintilla (ссылка на строку), которая делает именно это и работает отлично.