TN059: Использование MFC многобайтовых Кодировок и Юникода Преобразование макросов

В настоящей записке описывается, как использовать макросы для многобайтовых Кодировок и Юникода преобразования, которые определяются в AFXPRIV.H. Эти макросы являются наиболее полезными, если ваше приложение сделки непосредственно с OLE API или по каким-либо причинам, часто необходимо конвертировать между Юникода и многобайтовых Кодировок.

Обзор

В MFC 3.x, используется специальный DLL (MFCANS32.DLL) для автоматического преобразования Юникода и многобайтовых Кодировок при вызове интерфейсов OLE. Эта библиотека DLL было почти прозрачный слой, который позволяет приложениям OLE для записи как будто OLE API и интерфейсы MBCS, даже если они всегда Unicode (за исключением на Macintosh). В то время как этот уровень был удобен и позволяет приложениям быстро будут портирована из Win16 Win32 (MFC, Microsoft Word, Microsoft Excel и VBA, являются лишь некоторыми из приложения Microsoft, которые использовали эту технологию), кроме того, иногда значительное увеличение производительности хит. По этой причине MFC 4.x не использует эту библиотеку DLL и вместо этого переговоров непосредственно к интерфейсам Unicode OLE. Чтобы сделать это, MFC необходимо преобразовать в Юникод для многобайтовых Кодировок, когда вызов к интерфейс OLE и часто необходимо преобразовать в многобайтовой Кодировки Юникод при реализации интерфейса OLE. Для того чтобы справиться с этим легко и эффективно, макросы, созданы для того, чтобы облегчить это преобразование.

Одним из крупнейших препятствий на пути создания такого набора макросов является выделение памяти. Так как строки не могут быть преобразованы в месте, новые память для хранения преобразованных результатов должны быть выделены. Это можно было бы сделать с кодом следующим:

/ / Мы хотим преобразовать Многобайтовой строки в lpszA
int nLen = MultiByteToWideChar (CP_ACP, 0, lpszA, -1, NULL, значение NULL);
LPWSTR lpszW = новый WCHAR [nLen];
MultiByteToWideChar (CP_ACP, 0, lpszA, -1, lpszW, nLen);
/ / использовать для вызова OLE здесь
Пи >SomeFunctionThatNeedsUnicode(lpszW);
/ / освободить строку
Удаление lpszW]

Этот подход как целого ряда проблем. Основная проблема заключается в том, что это много кода для написания, тестирования и отладки. То, что вызов простой функции, в настоящее время намного более сложным. Кроме того накладные расходы в этом существует значительный во время выполнения. Память должна быть в куче и освободил каждый раз, когда выполняется преобразование. И наконец, приведенный выше код будет необходимо иметь соответствующие #ifdefs добавлена для Unicode и Macintosh построений (которые не требуют это преобразование занять место).

Решение, которое мы пришли вверх с необходимо создать некоторые макросы, которые 1) маски разницу между различными платформами и 2) использование схемы распределения эффективной памяти и 3) легко вставить в существующих исходный код. Вот пример одного из определений:

# define A2W(lpa) (\
 nbsp;  (МПУ (LPCSTR) == &NULL)? ЗНАЧЕНИЕ NULL: (\
           _convert = (strlen (ЛПА) + 1), \
        AfxA2WHelper((LPWSTR) alloca(_convert*2), МПУ, _convert) \
    )\
)

Используя этот макрос вместо того, чтобы приведенный выше код и вещи намного проще:

/ / использовать для вызова OLE здесь
USES_CONVERSION;
Пи >SomeFunctionThatNeedsUnicode(T2OLE(lpszA))

Есть дополнительные вызовы, где преобразование не требуется, но с помощью макросов простых и эффективных.

Реализация каждого макроса использует функцию _alloca() для выделения памяти из стека вместо того кучи. Выделение памяти из стека гораздо быстрее, чем выделения памяти в куче, и память освобождается автоматически после выхода из функции. Кроме того, макросы избегать вызова MultiByteToWideChar (или WideCharToMultiByte) более чем один раз. Это делается путем выделения больше памяти, чем это необходимо. Мы знаем что MBC преобразует в более одного типа WCHAR и что для каждого типа WCHAR мы будем иметь более двух MBC байт. Путем выделения чуть больше, чем необходимо, но всегда достаточно для обработки преобразования второй вызов второй вызов функции преобразования избегается. Вызов вспомогательной функции AfxA2Whelper уменьшает количество толкает аргумент, что должно быть сделано для выполнения преобразования (это приводит к меньше кода, чем если она прямо под названием MultiByteToWideChar ).

В целях для макросов иметь пространство для хранения временной длина, необходимо объявить локальную переменную, называемый _convert, который делает это в каждой функции, которая использует преобразование макросов. Это делается путем вызова макроса USES_CONVERSION , как показано выше в примере.

Существует общий Преобразование макросов и конкретных макросов OLE. Ниже рассматриваются эти два набора различных макросов. Все макросы находятся в AFXPRIV.H.

Универсальный Преобразование макросов

Общий Преобразование макросов формируют основной механизм. Пример макроса и осуществления, показано в предыдущем разделе, A2W, является одним из таких «общий» макрос. Она не имеет отношения к Оле специально. Ниже приводится набор общих макросов:

 A2CW (LPCSTR) - gt; (LPCWSTR)
A2W (LPCSTR) - > (LPWSTR)
W2CA (LPCWSTR) - > (LPCSTR)
W2A (LPCWSTR) - > (LPSTR)

Помимо делает преобразования текста, есть также макросы и вспомогательные функции для преобразования TEXTMETRIC, DEVMODE, BSTRи OLE выделенных строк. Эти макросы выходят за рамки этой дискуссии — называть AFXPRIV.H для получения дополнительной информации об этих макросов.

OLE Преобразование макросов

Преобразование макросов OLE предназначены специально для обработки функций, которые ожидают OLESTR символов. Если вы просмотрите заголовки OLE, вы увидите множество ссылок на LPCOLESTR и OLECHAR. Эти типы используются для обозначения типа персонажей, используемые в интерфейсах OLE таким образом, чтобы не характерен для платформы. OLECHAR карты для данных типа char в Win16 и Macintosh платформах и WCHAR в Win32.

Чтобы число директив # ifdef в код MFC к минимуму у нас есть аналогичные макрос для каждого преобразования, когда речь идет о строк OLE. Наиболее часто используются следующие макросы:

T2COLE (LPCTSTR) - gt; (LPCOLESTR)
T2OLE (LPCTSTR) - > (LPOLESTR)
OLE2CT (LPCOLESTR) - > (LPCTSTR)
OLE2T (LPCOLESTR) - > (LPCSTR)

Опять же макросы для этого TEXTMETRIC, DEVMODE, BSTRи OLE выделенных строк. Обратитесь к AFXPRIV.H для получения дополнительной информации.

Прочие соображения

Не используйте макросы в непрерывном цикле. К примеру не требуется написать следующий тип кода:

void BadIterateCode(LPCTSTR lpsz)
{
USES_CONVERSION;
для (внутренне ii = 0; ii lt; 10000; ii ++)
Пи - > SomeMethod (ii, T2COLE(lpsz));
}

Приведенный выше код может привести к выделению мегабайт памяти в стеке в зависимости от содержимого строки lpsz —!   Это также время для преобразования строки для каждой итерации цикла. Вместо этого переместите такие постоянные преобразования выход из цикла:

void MuchBetterIterateCode(LPCTSTR lpsz)
{
USES_CONVERSION;
LPCOLESTR lpszT = T2COLE(lpsz);
для (внутренне ii = 0; ii lt; 10000; ii ++)
Пи - > SomeMethod (ii, lpszT);
}

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

void CallSomeMethod (int ii, LPCTSTR lpsz)
{
USES_CONVERSION;
Пи gt;SomeMethod (ii, T2COLE(lpsz));
}

void MuchBetterIterateCode2 (LPCTSTR * lpszArray)
{
для (внутренне ii = 0; ii < 10000; ii ++)
CallSomeMethod (ii, lpszArray[ii]);
}

Не возвращать в результате одного из макросов, пока возвращаемое значение подразумевает, что делает копию данных перед возвращением. Например этот код плохо:

LPTSTR BadConvert(ISomeInterface* pI)
{
USES_CONVERSION;
LPOLESTR lpsz = NULL;
Пи gt;GetFileName(&lpsz);
LPTSTR lpszT = OLE2T(lpsz);
CoMemFree(lpsz);
возвращение lpszT; / / плохо! возвращение alloca памяти
}

Приведенный выше код можно исправить, изменив значение для что-то которое копирует значение:

CString BetterConvert(ISomeInterface* pI)
{
USES_CONVERSION;
LPOLESTR lpsz = NULL;
Пи gt;GetFileName(&lpsz);
LPTSTR lpszT = OLE2T(lpsz);
CoMemFree(lpsz);
возвращение lpszT; / / CString производит копирование
}

Макросы просты в использовании и легко вставлять в свой код, но как вы можете сказать от выше оговорками, вам нужно быть осторожным при их использовании.

Технические примечания по номеру |nbsp; Технические примечания по категориям

Index