Как я могу проверить мое приложение Windows для правильной обработки Unicode? - PullRequest
12 голосов
/ 20 июня 2011

Я не могу использовать предварительно упакованные строковые библиотеки Unicode, такие как ICU, потому что они увеличивают размер двоичного файла до безумной степени (это программа 200 КБ; ICU составляет 16 МБ +!).

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

Существуют ли такие инструменты, как Fuzzers, для безопасности, но для Unicode? То есть выбрасывать символы вне Базовой многоязычной плоскости в мой код и следить за тем, чтобы все обрабатывалось правильно как UTF-16?

(О, и очевидно, что кроссплатформенное решение работает, хотя большинство кроссплатформенных решений должны поддерживать как UTF-8, так и UTF-16)

РЕДАКТИРОВАТЬ : Также обратите внимание на вещи, которые менее очевидны, чем суррогатные пары UTF-16, такие как знаки акцента!

Ответы [ 2 ]

3 голосов
/ 20 июня 2011

Некоторые вещи для проверки:

  • Убедитесь, что вместо вручения WM_CHAR вы обрабатываете WM_UNICHAR:

    WM_UNICHARсообщение такое же, как WM_CHAR, за исключением того, что используется UTF-32.Он предназначен для отправки или публикации символов Unicode в окнах ANSI, а может обрабатывать символы дополнительной плоскости Unicode .

  • Do not предположим, что символ i th имеет индекс i.Это, очевидно, не так, и если вам случится использовать этот факт, скажем, для разбиения строки пополам, то вы можете испортить ее.

  • Не говорите пользователю(в строке состояния или что-то), что пользователь имеет N символов только потому, что массив символов имеет длину N.

2 голосов
/ 09 ноября 2016

Неправильный ответ

Используйте WM_UNICHAR, он обрабатывает UTF-32 и может обрабатывать символы дополнительной плоскости Unicode.

Хотя это почти правда, но полная истина выглядит так:

  1. WM_UNICHAR - это хак, разработанный для ANSI Windows для получения символов Unicode. Создайте окно Unicode, и вы никогда его не получите.
  2. Создайте окно ANSI, и вы будете удивлены, что оно все еще не работает должным образом. Уловка в том, что когда окно создано, вы получаете WM_UNICHAR с 0xffff, на который вы должны отреагировать, вернув 1 (стандартная оконная процедура вернет 0). Не сделайте этого, и вы никогда не увидите WM_UNICHAR снова. Хорошо, что официальная документация этого не говорит.
  3. Запустите вашу программу в системе, которая по загадочным причинам не поддерживает 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 бит кода ключа. Что очень хорошо для всего в BMP, но в противном случае отстой.

Я проверил это как с помощью кодов Alt-клавиатуры, так и путем создания пользовательской раскладки клавиатуры, которая генерирует кодовые точки вне BMP. В любом случае принимается только один WM_CHAR, содержащий младшие 16 бит символа. Старшие 16 бит просто выбрасываются.

Чтобы ваша программа работала на 100% правильно с Юникодом, вы, очевидно, должны использовать диспетчер методов ввода (ImmGetCompositionStringW), что является неприятным и плохо документированным. Лично для меня это просто означает: «Хорошо, винт это». Но если вы заинтересованы в том, чтобы быть на 100% корректным, посмотрите на исходный код любого редактора, использующего Scintilla (ссылка на строку) , который делает именно это и работает отлично.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...