Esta anotação descreve como usar as macros de conversão de MBCS/Unicode que são definidos no AFXPRIV.H. essas macros são mais úteis se seu aplicativo promoções diretamente com a API OLE ou por algum motivo, muitas vezes precisa converter entre Unicode e MBCS.
Visão geral
No MFC 3. x, foi usado um DLL especial (MFCANS32.DLL) para converter automaticamente entre Unicode e MBCS quando eram chamados de interfaces OLE. Esta DLL foi uma camada quase transparente que permitia aplicativos OLE a ser escrito como se as interfaces e APIs OLE MBCS, mesmo que eles sejam sempre Unicode (exceto no Macintosh). Enquanto essa camada era conveniente e aplicações para rapidamente ser portados de Win16 a Win32 permitidas (MFC, Microsoft Word, Microsoft Excel e VBA, são apenas algumas das aplicações do Microsoft que usavam essa tecnologia), ele também teve um desempenho significativo, por vezes, bater. Por este motivo, 4. x MFC não usa esta DLL e em vez disso fala diretamente para as interfaces OLE do Unicode. Para fazer isso, MFC precisa converter para Unicode em MBCS ao fazer uma chamada para uma interface de OLE e muitas vezes precisa converter MBCS de Unicode ao implementar uma interface OLE. Para lidar com isso com eficiência e facilidade, um número de macros foram criado para facilitar essa conversão.
Um dos maiores obstáculos da criação como um conjunto de macros é a alocação de memória. Porque as seqüências de caracteres não podem ser convertidas no lugar, nova memória para armazenar os resultados convertidos deve ser alocada. Isso poderia ter sido feito com o código semelhante ao seguinte:
/ / Nós queremos converter uma Cadeia de caracteres MBCS no lpszA
int nLen = MultiByteToWideChar (CP_ACP, 0, lpszA, -1, NULL, NULL);
LPWSTR lpszW = novo WCHAR [nLen];
MultiByteToWideChar (CP_ACP, 0, lpszA, -1, lpszW, nLen);
/ / usá-lo para chamar OLE aqui
pI->SomeFunctionThatNeedsUnicode(lpszW);
/ / livre a Cadeia de caracteres
Excluir [] lpszW
Essa abordagem como uma série de problemas. O principal problema é que é um monte de código para escrever, testar e depurar. Algo que era uma chamada de função simples, agora é muito mais complexa. Além disso, há um significativo tempo de execução sobrecarga ao fazê-lo. Memória deve ser alocada no heap e liberados cada vez que uma conversão é feita. Finalmente, o código acima precisaria ter apropriado #ifdefs adicionado para compilações de Unicode e Macintosh (que não requerem esta conversão ocorra).
A solução que nós viemos acima com é criar algumas macros que 1) máscara a diferença entre as várias plataformas e 2) usar um esquema de alocação de memória eficiente e 3) são fácil de inserir em existente código-fonte. Aqui está um exemplo de uma das definições:
# define A2W(lpa) (\
nbsp; (Lpa (LPCSTR) = = &NULL)? NULO: (\
_convert = (strlen (lpa) + 1), \
AfxA2WHelper((LPWSTR) alloca(_convert*2), lpa, _convert) \
)\
)
Usando esta macro em vez do código acima e as coisas são muito mais simples:
/ / usá-lo para chamar OLE aqui
USES_CONVERSION;
pI->SomeFunctionThatNeedsUnicode(T2OLE(lpszA))
Há chamadas extras onde conversão é necessário, mas usando as macros é simples e eficaz.
A implementação de cada macro usa a função _alloca() para alocar memória de pilha em vez da pilha. Alocação de memória da pilha é muito mais rápido que alocar memória no heap, e a memória é liberada automaticamente quando a função é encerrada. Além disso, as macros Evite chamar MultiByteToWideChar (ou WideCharToMultiByte) mais de uma vez. Isso é feito por alocar a memória um pouco mais do que o necessário. Sabemos que um MBC converterá no máximo um WCHAR e que, para cada WCHAR , teremos um máximo de dois bytes do MBC. Por alocar um pouco mais do que necessário, mas sempre o suficiente para lidar com a conversão a segunda chamada segunda chamada para a função de conversão é evitada. A chamada para a função de auxiliar AfxA2Whelper reduz o número de verificações extras de argumento que deve ser feito para executar a conversão (isso resulta em código mais pequeno, que não se chamado MultiByteToWideChar diretamente).
Em ordem para as macros ter espaço para armazenar o comprimento temporário, é necessário declarar uma variável local chamada _convert que faz isso em cada função que usa as macros de conversão. Isso é feito por chamar a macro de USES_CONVERSION como visto acima no exemplo.
Há genérico conversão macros e macros específicas de OLE. Estes dois conjuntos diferentes de macro são discutidos abaixo. Todas as macros de residirem em AFXPRIV.H.
Macros de conversão de genéricos
As macros de conversão genérico formam o mecanismo subjacente. O exemplo de macro e a implementação mostrada na seção anterior, A2W, é um desse macro "genérica". Ele não tem nenhuma relação ao OLE especificamente. O conjunto de genéricos macros está abaixo:
A2CW (LPCSTR) - gt; (LPCWSTR)
A2W (LPCSTR) - > (LPWSTR)
W2CA (LPCWSTR) - > (LPCSTR)
W2A (LPCWSTR) - > (LPSTR)
Além de fazer conversões de texto, também existem macros e funções auxiliar para converter OLE, TEXTMETRIC, DEVMODEe BSTRalocado seqüências de caracteres. Essas macros estão além do escopo desta discussão – referir-se a AFXPRIV.H para obter mais informações sobre essas macros.
OLE de conversão Macros
As macros de conversão de OLE são projetadas especificamente para manuseamento de funções que esperam OLESTR caracteres. Se você examinar os cabeçalhos OLE, você vai ver muitas referências a LPCOLESTR e OLECHAR. Esses tipos são usados para se referir ao tipo de caracteres utilizados em interfaces OLE de uma forma que não é específico para a plataforma. OLECHAR mapeia para char em plataformas Win16 e Macintosh e WCHAR em Win32.
Para manter o número de # ifdef diretivas no código MFC a um mínimo, temos uma macro similar para cada conversão que onde seqüências de caracteres OLE estão envolvidas. As seguintes macros são mais comumente usadas:
T2COLE (LPCTSTR) - gt; (LPCOLESTRRESFILENAME)
T2OLE (LPCTSTR) - > (LPOLESTR)
OLE2CT (LPCOLESTRRESFILENAME) - > (LPCTSTR)
OLE2T (LPCOLESTRRESFILENAME) - > (LPCSTR)
Novamente existem macros similares para fazer TEXTMETRIC, DEVMODE, OLE e BSTRalocado seqüências de caracteres. Consulte AFXPRIV.H para obter mais informações.
Outras considerações
Não use as macros em um loop forte. Por exemplo, você não deseja escrever o seguinte tipo de código:
privatevoid BadIterateCode(LPCTSTR lpsz)
{
USES_CONVERSION;
para (int ii = 0; ii lt; 10000; ii + +)
pI - > SomeMethod (ii, T2COLE(lpsz));
}
O código acima poderia resultar &na alocação de megabytes de memória on the pilha dependendo de que o conteúdo da Cadeia de caracteres lpsz é! nbsp; Ele também leva tempo para converter a Cadeia de caracteres para cada iteração do loop. Em vez disso, mova tais conversões constantes fora do loop:
privatevoid MuchBetterIterateCode(LPCTSTR lpsz)
{
USES_CONVERSION;
LPCOLESTR lpszT = T2COLE(lpsz);
para (int ii = 0; ii lt; 10000; ii + +)
pI - > SomeMethod (ii, lpszT);
}
Se a Cadeia de caracteres não é constante, então encapsular a chamada de método em uma função. Isso permitirá que o buffer de conversão ser liberado a cada hora. Por exemplo:
void CallSomeMethod (int ii, LPCTSTR lpsz)
{
USES_CONVERSION;
pI-gt;SomeMethod (ii, T2COLE(lpsz));
}
void MuchBetterIterateCode2 (LPCTSTR lpszArray)
{
para (int ii = 0; ii < 10000; ii + +)
CallSomeMethod (ii, lpszArray[ii]);
}
Nunca retorne o resultado de uma das macros, a menos que o valor de retorno implica fazer uma cópia dos dados antes do retorno. Por exemplo, esse código é ruim:
LPTSTR BadConvert(ISomeInterface* pI)
{
USES_CONVERSION;
LPOLESTR lpsz = NULL;
pI-gt;GetFileName(&lpsz);
LPTSTR lpszT = OLE2T(lpsz);
CoMemFree(lpsz);
retornar lpszT; / / bad! retornando alloca memória
}
O código acima poderia ser corrigido alterando o valor de retorno para algo que copia o valor:
CString BetterConvert(ISomeInterface* pI)
{
USES_CONVERSION;
LPOLESTR lpsz = NULL;
pI-gt;GetFileName(&lpsz);
LPTSTR lpszT = OLE2T(lpsz);
CoMemFree(lpsz);
retornar lpszT; / / CString faz cópia
}
As macros são fáceis de usar e fácil de inserir em seu código, mas como você pode dizer de advertências acima, você precisa ter cuidado ao usá-los.
Técnico anotações por número |nbsp; &Notas técnicas por categoria