Windows

       

Создание программ, способных использовать и ANSI, и Unicode


Неплохая мысль — заранее подготовить свое приложение к Unicode, даже если Вы пока не планируете работать с этой кодировкой. Вот главное, что для этого нужно:

  • привыкайте к тому, что текстовые строки — это массивы символов, а не массивы байтов или значений типа char;
  • используйте универсальные типы данных (вроде TCHAR или PTSTR) для текстовых символов и строк;
  • используйте явные типы данных (вроде BYTE или PBYTE) для байтов, указателей на байты и буферов данных;
  • применяйте макрос _TEXT для определения символьных и строковых литералов;
  • предусмотрите возможность глобальных замен (например, PSTR на PTSTR);
  • модифицируйте логику строковой арифметики. Например, функции обычно принимают размер буфера в символах, а не в байтах Это значит, что вместо sizeof(szBuffer) Вы должны передавать (sizeof(szBuffer) / sizeof(TCHAR)). Но блок памяти для строки известной длины выделяется в байтах, а не символах, т. e. вместо malloc(nCharacters) нужно использовать malloc(nCbaracters *sizeof(TCHAR)) Из всего, что я перечислил, это запомнить труднее всего — если Вы ошибетесь, компилятор не выдаст никаких предупреждений.
  • Разрабатывая программы-примеры для первого издания книги, я сначала написал их так, что они компилировались только с использованием ANSI. Но, дойдя до этой главы (она была тогда в конце), понял, что Unicode лучше, и решил написать примеры, которые показывали бы, как легко создавать программы, компилируемые с применением и Unicode, и ANSI. B конце концов я преобразовал все программы-примеры так, чтобы их можно было компилировать в расчете на любой из этих стандартов.

    Конверсия всех программ заняла примерно 4 часа — неплохо, особенно если учесть, что у меня совсем не было опыта в этом деле.

    В Windows есть набор функций для работы с Unicode-строками. Эти функции перечислены ниже.

    Функция Описание
    lstrcat

    Выполняет конкатенацию строк
    lstrcmp Сравнивает две строки с учетом регистра букв
    lstrcmpi Сравнивает две строки без учета регистра букв
    lstrcpy Копирует строку в другой участок памяти
    lstrlen Возвращает длину строки в символах
    <


    Они реализованы как макросы, вызывающие либо Unicode-, либо ANSI-версию функции в зависимости от того, определен ли UNICODE при компиляции исходного модуля Например, если UNICODE не определен, lstrcat раскрывается в lstrcatA, определен — в lstrcatW.

    Строковые функции lstrcmp и lstrcmpi ведут себя не так, как их аналоги из библиотеки С (strcmp, strcmpi, wcscmp и wcscmpf), которые просто сравнивают кодовые позиции в символах строк. Игнорируя фактические символы, они сравнивают числовое значение каждого символа первой строки с числовым значением символа второй

    строки. Но lstrcmp и lstrcmpi реализованы через вызовы Windows-функции CompareString;

    int CompareString(
    LCID lcid,
    DWORD fdwStyle,
    PCWSTR pString1,
    int cch1,
    PCWSTR pString2,
    int cch2);

    Она сравнивает две Unicode-строки. Первый параметр задаст так называемый идентификаторлокализации (locale ID, LCID) — 32-битное значение, определяющее конкретный язык. С помощью этого идентификатора CompareString сравнивает строки с учетом значения конкретных символов в данном языке. Так что она действует куда осмысленнее, чем функции библиотеки С.

    Когда любая из функций семейства lstrcmp вызывает CompareString, в первом параметре передается результат вызова Windows-функции GetThreadLocale.

    LCID GetThreadLocale();

    Она возвращает уже упомянутый идентификатор, который назначается потоку в момент его создания.

    Второй параметр функции CompareString указывает флаги, модифицирующие метод сравнения строк. Допустимые флаги перечислены в следующей таблице.

    Флаг Действие
    NORM_IGNORECASE Различия в регистре букв игнорируются
    NORM_IGNOREKANATYPE Различия между знаками хираганы и катаканы игнорируются
    NORM_IGNORENONSPACE Знаки, отличные от пробелов, игнорируются
    NORM_IGNORESYMBOLS Символы, отличные от алфавитно-цифровых, игнорируются
    NORM_IGNOREWIDTH Разница между одно- и двухбайтовым представлением одного
    и того же символа игнорируется
    SORT_STRINGSORT Знаки препинания обрабатываются так же, как и символы, от-
    личные от алфавитно-цифровых
    Вызывая CompareString, функция lstrcmp передает в параметре fdwStyle нуль, а lstrcmpi — флаг NORM_IGNORECASE. Остальные четыре параметра определяют две строки и их длину. Если cch1 равен -1, функция считает, что строка pString2 завершается нулевым символом, и автоматически вычисляет ее длину. То же относится и к параметрам cch2 wpString2.

    Многие функции С-библиотеки с Unicode-строками толком не работают. Так, tolower и toupper неправильно преобразуют регистр букв со знаками ударения. Поэтому для Unicode-строк лучше использовать соответствующие Windows-функции. К тому же они корректно работают и с ANSI-строками.

    Первые две функции:

    PTSTR CharLower(PTSTR pszStnng);
    PTSTR CharUpper(PTSTR pszString);

    преобразуют либо отдельный символ, либо целую строку с нулевым символом в конце. Чтобы преобразовать всю строку, просто передайте ее адрес. Но, преобразуя отдельный символ, Вы должны передать его так:


    Содержание раздела