Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Создание эффективных приложений для Windows Джеффри Рихтер 2004 (Книга).pdf
Скачиваний:
375
Добавлен:
15.06.2014
Размер:
8.44 Mб
Скачать

и др.) всегда записываются в Unicode Если в программе не определяется макрос UNICODE, Windows 98 и Windows 2000 сами проводят нужные преобразования Например, если при компиляции исходного модуля UNICODE не определен, вызов LoadString на самом деле приводит к вызову LoadStringA, которая читает строку из ресурсов и преобразует ее в ANSI. Затем Вашей программе возвращается ANSIпредставление строки

Текстовые файлы

Текстовых файлов в кодировке Unicode пока очень мало. Ни в одном текстовом файле, поставляемом с операционными системами или другими программными продуктами Microsoft, не используется Unicode. Думаю, однако, что эта тенденция изменится в будущем — пусть даже в отдаленном Например, программа Notepad в Windows 2000 позволяет создавать или открывать как Unicode-, так и ANSI-файлы. Посмотрите на

ее диалоговое окно Save Аs (рис. 2-2) и обратите внимание на предлагаемые форматы текстовых файлов.

Рис. 2-2. Диалоговое окно Save As программы Notepad в Windows 2000

Многим приложениям, которые открывают и обрабатывают текстовые файлы (например, компиляторам), было бы удобнее, если после открытия файла можно было бы определить, содержит он символы в ANSI или в Unicode. B этом может помочь функция IsTextUnicode

DWORD IsTextUnicode(CONST PVOID pvBuffer, int cb, PINT pResult);

Проблема с текстовыми файлами в том, что не существует четких и строгих правил относительно их содержимого. Это крайне затрудняет определение того, содержит файл символы в ANSI или в Unicode Поэтому IsTextUnicode применяет набор статистических и детерминистских методов для того, чтобы сделать взвешенное предположение о содержимом буфера. Поскольку тут больше алхимии, чем точной науки,

нет гарантий, что Вы не получите неверные результаты от IsTextUnicode.

Первый ее парамегр, pvBuffer, указывает на буфер, подлежащий проверке. При этом используется указатель типа void, поскольку неизвестно, в какой кодировке данный массив символов.

Параметр сb определяет число байтов в буфере, на который указываетр pvBuffer Так как содержимое буфера не известно, сb - счетчик именно байтов, а не символов. Заметьте: вовсе не обязательно задавать всю длину буфера. Но чем больше байтов проанализирует функция, тем больше шансов получить правильный результат.

Параметр pResult — это адрес целочисленной переменной, которую надо инициализировать перед вызовом функции. Ее значение сообщает, какие тесты должна провести IsTextUnicode. Если pResult равен NULL, функция IsTextUnicode делает все проверки. (Подробнее об этом см. документацию Platform SDK.)

Функция возвращает TRUE, если считает, что буфер содержит текст в Unicode, и FALSE

— в ином случае. Да-да, она возвращает именно булево значение, хотя в прототипе указано DWORD. Если через целочисленную переменную, на которую указывает pResuIt, были запрошены лишь определенные тесты, функция (перед возвратом управления) устанавливает ее биты в соответствии с результатами этих тестов.

WINDOWS 98:

В Windows 98 функция IsTextUnicode по сути не реализована и просто возвращает FALSE; последующий вызов GetLastError дает код ошибки

ERRORCALL_NOT_IMPLEMENTED.

Применение функции IsTextUnicode иллюстрирует программа-пример FileRev (см. главу

17).

Перекодировка строк из Unicode в ANSI и обратно

Windows-функция MultiByteToWideChar преобразует мультибайтовые символы строки в широкобайтовые:

int MultiBytoToWideChar( UINT uCodePage,

DWORD dwFlags,

PCSTR pMultiByteStr, int cchMultiByte, PWSTR pWideCharStr, int cchWideChar);

Параметр uCodePage задает номер кодовой страницы, связанной с мультибайтовой строкой. Параметр dwFlags влияет на преобразование букв с диакритическими знаками. Обычно эти флаги не используются, и dwFlags равен 0. Параметр pMultiByteStr указывает на преобразуемую строку, a cchMultiByte определяет ее длину в байтах Функция самостоятельно определяет длину строки, если cchMultiByte равен -1.

Unicode-версия строки, полученная в результате преобразования, записывается в буфер по адресу, указанному в pWideCharStr. Максимальный размер этого буфера (в символах) задается в параметре cchWideCbar. Если он равен 0, функция ничего не преобразует, а просто возвращает размер буфера, необходимого для сохранения результата преобразования. Обычно конверсия мультибайтовой строки в ее Unicode-эквивалент проходит так:

1. Вызывают MultiByteToWideChar, передавая NULL в параметре pWideCharStr и 0 в

параметре cchWideChar.

2.Выделяют блок памяти, достаточный для сохранения преобразованной строки. Его размер получают из предыдущего вызова MultiByteToWideChar.

3.Снова вызывают MultiByteToWideChar, на этот раз передавая адрес выделенно го буфера в параметре pWideCharStr, а размер буфера, полученный при первом обращении к этой функции, — в параметре cchWideChar.

4.Работают с полученной строкой.

5.Освобождают блок памяти, занятый Unicode-строкой.

Обратное преобразование выполняет функция WideCharToMultiByte

int WideCharToMultiByte( UINT uCodePage,

DWORD dwFlags, PCWSTR pWideCharStr, int cchWideChar, PSTR pMultiByteStr, int cchMultiByte, PCSTR pDefaultChar,

PBOOL pfUsedDefaultChar);

Она очень похожа на MultiByteToWideChar. И опять uCodePage определяет кодовую страницу для строки — результата преобразования Дополнительный контроль над процессом преобразования дает параметр dwFlags. Его флаги влияют на символы с диакритическими знаками и на символы, которые система не может преобразовать. Такой уровень контроля обычно не нужен, и dwFlags приравнивается 0

Пapaметр pWideCharStr указывает адрес преобразуемой строки, a cchWideChar задает ее длину в символах. Функция сама определяет длину исходной строки, если cchWideChar равен -1.

Мультибайтовый вариант строки, полученный в результате преобразования, записывается в буфер, на который указывает pMultiByteStr, Параметр cchMultiByte определяет максимальный размер этого буфера в байтах Передав нулевое значение в ccbMultiByte, Вы заставите функцию сообщить размер буфера, требуемого для записи результата. Обычно конверсия широкобайтовой строки в мультибайтовую проходит в той же последовательности, что и при обратном преобразовании

Очевидно, Вы заметили, что WideCharToMultiByte принимает на два параметра больше,

чем MultiByteToWideCbar, это pDefauItChar pfUsedDefaultChar. Функция

WideCharToMultiByte использует их, только если встречает широкий символ, не представленный в кодовой странице, на которую ссылается uCodePage Если его преобразование невозможно, функция берет символ, на который указывает pDefaultChar. Если этот параметр равен NULL (как обычно и бывает), функция использует системный символ по умолчанию. Таким символом обычно служит знак вопроса, что при операциях с именами файлов очень опасно, поскольку он является и символом подстановки.

Параметр pfUsedDefaultChar указывает на переменную типа BOOL, которую функция устанавливает как TRUE, если хоть один символ из широкосимвольной строки не преобразован в свой мультибайтовый эквивалент. Если же все символы преобразованы успешно, функция устанавливает переменную как FALSE. Обычно Вы передаете NULL в этом параметре.

Подробнее эти функции и их применение описаны в документации Platform SDK.

Эти две функции позволяют легко создавать ANSI- и Unicode-версии других функций, работающих со строками. Например, у Вас есть DLL, содержащая функцию, которая переставляет все символы строки в обратном порядке Unicode-версию этой функции можно было бы написать следующим образом.

BOOL StringReverseW(PWSTR pWidoCharStr) {

// получаем указатель на последний символ в строке

PWSTR pEndOfStr = pWideCharStr + wcslen(pWideCharStr) - 1;

wchar_t cCharT;

//повторяем, пока не дойдем до середины строки while (pWideCharStr < pEndOfStr) {

//записываем символ во временную переменную cCharT = *pWideCharStr;

//помещаем последний символ на место первого

*pWideCharStr = *pEndOfStr;

//копируем символ из временной переменной на место последнего символа

*pEndOfStr = cCharT;

//продвигаемся на 1 символ вправо

pWideCharStr++ж

//продвигаемся на 1 символ влево pEndOfStr--;

}

//строка обращена; сообщаем об успешном завершении return(TRUE);

}

ANSI-версию этой функции можно написать так, чтобы она вообще ничем не занималась, а просто преобразовывала ANSI-строку в Unicode, передавала ее в функцию StringReverseW и конвертировала обращенную строку снова в ANSI. Тогда функция должна выглядеть примерно так:

BOOL StringReverseA(PSTR pMultiByteStr) { PWSTR pWideCharStr;

int nLenOfWideCharStr; BOOL fOk = FALSE;

//вычисляем количество символов, необходимых

//для хранения широкосимвольной версии строки nLenOfWideCharStr = MultiRyteToWideChar(CP_ACP, 0, pMultiByteStr, -1, NULL, 0);

//Выделяем память из стандартной кучи процесса,

//достаточную для хранения широкосимвольной строки,

//Не забудьте, что MultiByteToWideChar возвращает

//количество символов, а не байтов, поэтому мы должны

//умножить это число на размер широкого символа.

pWideCharStr = HeapAlloc(GetProcessHeap(), 0, nLenOfWideCharStr * sizeof(WCHAR));