Windows для профессионалов

       

Перекодировка строк из 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));

if (pWideCharStr == NULL)
return(fOk);

// преобразуем нультибайтовую строку в широкосимвольную
MultiByteToWideChar(CP_ACP, 0, pMulti8yteStr, -1, pWideCharStr, nLenOfWideCharStr);

// вызываем широкосимвольную версию этой функции для выполнения настоящей работы
fOk = StnngReverseW(pWideCharStr);

if (fOk} {
// преобразуем широкосимвольную строку обратно в мультибайтовую
WideCharToMultiByte(CP_ACP, 0, pWideCharStr, -1, pMultiByteStr, strlen(pMultiByteStr), NULL, NULL);
}

// освобождаем память, выделенную под широкобайтовую строку
HeapFree(GetProcessHeap(), 0, pWideCharStr);

return(fOk),
}

И, наконец, в заголовочном файле, поставляемом вместе с DLL, прототипы этих функций были бы такими:

BOOL StringReverseW (PWSTR pWideCharStr);
BOOL StringReverseA (PSTR pMultiByteStr);

#ifdef UNICODE
#define StnngReverse StringReverseW
#else
#define StringRevcrsc StringReverseA
#endif // UNICODE


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