Partilhar via


TN059: usando macros de conversão MBCS/Unicode MFC

Dica

A nota técnica a seguir não foi atualizada desde que ela foi incluída pela primeira vez na documentação online.Como resultado, alguns procedimentos e tópicos podem estar incorretos ou expirados.Para obter as informações mais recentes, é recomendável que você procure o tópico de interesse no índice de documentação online.

Essa observação descreve como usar macros para a conversão de MBCS/Unicode, que são definidos em AFXPRIV.H. Macros esses são os mais úteis se seu aplicativo trata diretamente apis OLE ou por alguma razão, geralmente necessidades de conversão entre Unicode e MBCS.

Visão Geral

Em MFC 3.x, uma DLL especial foi usado MFCANS32.DLL () para converter automaticamente entre Unicode e MBCS quando as interfaces OLE eram chamadas. Este DLL era uma camada transparente quase que permite que os aplicativos OLE sejam gravados como se as APIs e as interfaces OLE eram MBCS, mesmo que sejam sempre Unicode (exceto em Macintosh). Quando essa camada foi aplicativos convenientes e pode ser movido rapidamente de Win16 ao Win32 (MFC o, o Microsoft Word, Microsoft Excel, e VBA, são apenas alguns dos aplicativos Microsoft que usava essa tecnologia), tinha uma ocorrência às vezes de desempenho significativa. Por esse motivo, o MFC 4.x não usa este DLL e não fala em vez de diretamente às interfaces OLE Unicode. Para fazer isso, o MFC precisa da conversão para Unicode a MBCS ao fazer uma chamada a uma interface OLE, e geralmente às necessidades conversão em MBCS Unicode ao implementar uma interface OLE. Para tratar eficiente e facilmente isso, um número de macros foram projetados para facilitar essa conversão.

Um dos obstáculos os maiores de criar esse conjunto de macros é alocação de memória. Como as cadeias de caracteres não podem ser convertido no lugar, a nova memória para armazenar os resultados da conversão deve ser atribuída. Isso pode ter sido feita com o código semelhante ao seguinte:

// we want to convert an MBCS string in lpszA
int nLen = MultiByteToWideChar(CP_ACP, 0,lpszA, -1, NULL, NULL);
LPWSTR lpszW = new WCHAR[nLen];
MultiByteToWideChar(CP_ACP, 0, 
   lpszA, -1, lpszW, nLen);
// use it to call OLE here
pI->SomeFunctionThatNeedsUnicode(lpszW);
// free the string
delete[] lpszW;

Essa abordagem como um número de problemas. O problema é maior que é muito código para escrever, teste, e depuração. Algo que era uma chamada de função simples, agora é muito mais complexo. Além disso, há uma sobrecarga significativa de tempo de execução dessa forma. A memória tem que ser atribuída no heap e ser liberada cada vez que uma conversão é feita. Finalmente, o código anterior precisará ter adicionado #ifdefs apropriado para as construções Unicode e Macintosh (que não exigem essa conversão ocorre).

A solução que nós viemos superior com macros que é criar alguns 1) mascarar a diferença entre as várias plataformas, e 2) use um esquema de alocação de memória eficientes, e 3) é fácil de ser inserida no código-fonte existente. Eis um exemplo de uma das definições:

#define A2W(lpa) (\
    ((LPCSTR)lpa == NULL) ? NULL : (\
          _convert = (strnlen(lpa)+1),\
        AfxA2WHelper((LPWSTR) alloca(_convert*2), 
      lpa, _convert)\
    )\
)

Usando esta macro em vez de código acima e itens é muito mais simples:

// use it to call OLE here
USES_CONVERSION;
pI->SomeFunctionThatNeedsUnicode(T2OLE(lpszA));

Há as chamadas adicionais em que a conversão é necessária, mas usar macros é simples e eficiente.

A implementação de cada macro usa a função de _alloca() para alocar memória da pilha em vez do heap. Alocar memória da pilha é muito mais rápida do que atribuindo a memória no heap, e a memória é liberada automaticamente quando a função é saída. Além disso, as macros impedem MultiByteToWideChar chame (ou) WideCharToMultiBytemais de uma vez. Isso é feito atribuindo um pouco mais memória que é necessário. Aprendemos que um MBC se converterá no máximo em um WCHAR e que para cada WCHAR nós teremos um máximo de dois bytes do MBC. Atribuindo um pouco mais do que o necessário, mas sempre suficiente para controlar a conversão a chamada de segundo segunda chamada à função de conversão é evitada. A chamada para a função AfxA2Whelper auxiliar reduz o número de envios do argumento que devem ser feitas a fim de executar a conversão (isso resulta em código, menor do que se ele MultiByteToWideChar chamado diretamente).

Para que as macros têm espaço armazenando um comprimento temporário, é necessário declarar uma variável local chamada _convert o que fazer isso em cada função que usa macros de conversão. Isso é feito chamando a macro de USES_CONVERSION como consultado no exemplo acima.

Há dois macros genéricas de conversão e um macros específicos do. Esses dois conjuntos macro diferentes são discutidos em. Todos os macros residem em. AFXPRIV.H.

Macros genéricas de conversão

Macros genéricas de conversão formam o mecanismo subjacente. O exemplo e a implementação macro mostrados na seção anterior, A2W, é um como uma macro “genérico. Não está relacionada ao OLE especificamente. O conjunto de macros genéricas é listado abaixo:

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

Além de executar conversões de texto, também há macros e o auxiliar funções convertendo TEXTMETRIC, DEVMODE, BSTR, e cadeias de caracteres atribuídas OLE. Esses são macros além do escopo desta discussão – consulte AFXPRIV.H para obter mais informações sobre esses macros.

Macros de conversão OLE

Macros OLE de conversão são criados especificamente para controlar as funções que esperam caracteres de OLESTR . Se você examina os cabeçalhos OLE, você verá muitas referências a LPCOLESTR e a OLECHAR. Esses tipos são usados para fazer referência ao tipo de caracteres usados em interfaces OLE em um modo que não é específica à plataforma. Mapas deOLECHAR a char em plataformas de Win16 e Macintosh e a WCHAR no Win32.

Para manter o número de políticas de #ifdef no código de MFC a um mínimo temos uma macro semelhante para cada conversão onde OLE cadeias de caracteres é envolvida. Os seguintes macros são usados com mais frequência:

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

Além disso, há macros semelhantes para fazer TEXTMETRIC, DEVMODE, BSTR, e cadeias de caracteres atribuídas OLE. Consulte AFXPRIV.H para obter mais informações.

Outras considerações

Não use macros em um loop estreito. Por exemplo, você não quiser escrever o seguinte tipo de código:

void BadIterateCode(LPCTSTR lpsz)
{
   USES_CONVERSION;
   for (int ii = 0; ii < 10000; ii++)
      pI->SomeMethod(ii, T2COLE(lpsz));
}

O código anterior pode resultar em megabytes atribuir de memória na pilha dependendo do que o conteúdo da cadeia de caracteres lpsz são! Também leva tempo converter a cadeia de caracteres para cada iteração do loop. Em vez disso, mova tais conversões constantes fora do loop:

void MuchBetterIterateCode(LPCTSTR lpsz)
{
   USES_CONVERSION;
   LPCOLESTR lpszT = T2COLE(lpsz);
   for (int ii = 0; ii < 10000; ii++)
      pI->SomeMethod(ii, lpszT);
}

Se a cadeia de caracteres não é constante, então encapsular a chamada do método em uma função. Isso permitirá que o buffer de conversão é liberado cada vez. Por exemplo:

void CallSomeMethod(int ii, LPCTSTR lpsz)
{
   USES_CONVERSION;
   pI->SomeMethod(ii, T2COLE(lpsz));
}

void MuchBetterIterateCode2(LPCTSTR* lpszArray)
{
   for (int ii = 0; ii < 10000; ii++)
      CallSomeMethod(ii, lpszArray[ii]);
}

Nunca retornar o resultado de um de macros, a menos que o valor de retorno implique a fatura de uma cópia dos dados antes de retorno. Por exemplo, esse código é ruim:

LPTSTR BadConvert(ISomeInterface* pI)
{
   USES_CONVERSION;
   LPOLESTR lpsz = NULL;
   pI->GetFileName(&lpsz);
   LPTSTR lpszT = OLE2T(lpsz);
   CoMemFree(lpsz);
   return lpszT; // bad! returning alloca memory
}

O código anterior poderia ser solucionado alterando o valor de retorno a algo que copia o valor:

CString BetterConvert(ISomeInterface* pI)
{
   USES_CONVERSION;
   LPOLESTR lpsz = NULL;
   pI->GetFileName(&lpsz);
   LPTSTR lpszT = OLE2T(lpsz);
   CoMemFree(lpsz);
   return lpszT; // CString makes copy
}

Macros são fáceis de usar e fáceis de inseri-lo em seu código, mas como você pode saber das advertências acima, você precisa ter cuidado para usá-las.

Consulte também

Outros recursos

Observações técnicas por número

Observações técnicas por categoria