Esta nota describe cómo utilizar las macros de conversión MBCS y Unicode que se definen en AFXPRIV.H. estas macros son más útiles si sus acuerdos de aplicación directamente con la API de OLE o por alguna razón, a menudo necesita convertir entre MBCS y Unicode.
Visión general
En MFC 3.x, utilizó una DLL especial (MFCANS32.DLL) para convertir automáticamente entre MBCS y Unicode cuando fueron llamadas interfaces OLE. Esta DLL es una capa casi transparente que permite aplicaciones OLE a escribirse como si la API OLE e interfaces fueron MBCS, aunque siempre son Unicode (excepto en Macintosh). Mientras esta capa era conveniente y permitió las aplicaciones rápidamente ser portado de Win16 a Win32 (MFC, Microsoft Word, Microsoft Excel y VBA, son sólo algunas de las aplicaciones de Microsoft que utilizan esta tecnología), también tuvo una actuación a veces importante éxito. Por esta razón, MFC 4.x no utiliza este archivo DLL y en cambio habla directamente a las interfaces OLE de Unicode. Para hacer esto, MFC necesita convertir a Unicode para MBCS al realizar una llamada a una interfaz OLE y a menudo necesita convertir en MBCS de Unicode cuando se implementa una interfaz OLE. A fin de tratar este eficaz y sencilla, se crearon una serie de macros para facilitar esta conversión.
Uno de los mayores obstáculos de crear conjuntos de macros es la asignación de memoria. Debido a que las cadenas no se puede convertir en el lugar, se debe asignar nueva memoria para guardar los resultados convertidos. Esto se podría haber hecho con código similar al siguiente:
/ / queremos convertir una cadena MBCS en lpszA
int nLen = MultiByteToWideChar (CP_ACP, 0, lpszA, -1, NULL, NULL);
LPWSTR lpszW = WCHAR nuevo [nLen];
MultiByteToWideChar (CP_ACP, 0, lpszA, -1, lpszW, nLen);
/ / uso llamar aquí OLE
pI->SomeFunctionThatNeedsUnicode(lpszW);
/ / liberar la cadena
eliminar [] lpszW
Este enfoque como una serie de problemas. El principal problema es que es un montón de código para escribir, probar y depurar. Algo que fue llamada a una función simple, ahora es mucho más compleja. Además, hay un considerable tiempo de ejecución carga en hacerlo. Memoria tiene que ser asignados en el montón y liberados cada vez que se realiza una conversión. Finalmente, el código anterior sería necesario tener adecuada #ifdefs añadido para Unicode y Macintosh construye (que no requiere esta conversión tendrá lugar).
La solución que propusimos es crear algunas macros que 1) máscara la diferencia entre las diversas plataformas y 2) utilizar un esquema de asignación de memoria eficiente y 3) son fáciles de insertar en el código fuente. Este es un ejemplo de una de las definiciones:
# define A2W(lpa) (\
nbsp; ¿(Lpa (LPCSTR) == &NULL)? NULO: (\
_convert = (strlen (lpa) + 1), \
AfxA2WHelper((LPWSTR) alloca(_convert*2), lpa, _convert) \
)\
)
Mediante esta macro en lugar del código anterior y las cosas son mucho más simples:
/ / uso llamar aquí OLE
USES_CONVERSION;
pI->SomeFunctionThatNeedsUnicode(T2OLE(lpszA))
Hay llamadas adicionales donde conversión es necesaria, pero el uso de las macros es simple y efectiva.
La aplicación de cada macro utiliza la función _alloca() para asignar la memoria de la pila en lugar del montón. Asignación de memoria de la pila es mucho más rápido que la asignación de memoria en la pila y la memoria se libera automáticamente cuando se cierra la función. Además, las macros evitar llamar a MultiByteToWideChar (o WideCharToMultiByte) más de una vez. Esto se realiza mediante la asignación de memoria un poco más de lo necesario. Sabemos que un MBC convertirá en a lo sumo una WCHAR y que para cada WCHAR tendremos un máximo de dos bytes MBC. Asignando un poco más de lo necesario, pero siempre lo suficiente para manejar la conversión de la segunda llamada segundo se evita la llamada a la función de conversión. La llamada a la función auxiliar AfxA2Whelper reduce el número de empuja argumento que deben realizarse a fin de realizar la conversión (Esto resulta en código más pequeño, que si llama MultiByteToWideChar directamente).
En orden a las macros tener espacio para almacenar la longitud temporal, es necesario declarar una variable local llamada _convert que hace esto en cada función que utiliza las macros de conversión. Esto se realiza invocando la macro USES_CONVERSION visto anteriormente en el ejemplo.
Existen las macros de conversión genérica y macros específicas de OLE. Estos dos conjuntos diferentes de macro se examinan a continuación. Todas las macros residen en AFXPRIV.H.
Macros de conversión genérica
Las macros de conversión genérica forman el mecanismo subyacente. El ejemplo de macro y la aplicación se muestra en la sección anterior, A2W, es una dicha macro "genérica". Tiene ninguna relación con OLE específicamente. A continuación se muestra el conjunto de macros genéricos:
A2CW (LPCSTR) - gt; (LPCWSTR)
A2W (LPCSTR) - > (LPWSTR)
W2CA (LPCWSTR) - > (LPCSTR)
W2A (LPCWSTR) - > (LPSTR)
Además de hacer conversiones de texto, también existen macros y funciones auxiliares para convertir TEXTMETRIC, DEVMODE, BSTRy OLE asignan cadenas. Estas macros están fuera del alcance de este debate, consulte AFXPRIV.H para obtener más información sobre macros.
OLE las Macros de conversión
Las macros de conversión OLE están diseñadas específicamente para el manejo de las funciones que esperan OLESTR caracteres. Si examina los encabezados OLE verá muchas referencias a LPCOLESTR y OLECHAR. Estos tipos se utilizan para referirse al tipo de caracteres que se utilizan en interfaces OLE de una manera que no es específico de la plataforma. Mapas OLECHAR a char en plataformas Win16 y Macintosh y WCHAR en Win32.
A fin de mantener el número de directivas # ifdef en el código MFC al mínimo tenemos una macro similar para cada conversión que cuando se trata de cadenas OLE. Más comúnmente se utilizan las siguientes macros:
T2COLE (LPCTSTR) - gt; (LPCOLESTR)
T2OLE (LPCTSTR) - > (LPOLESTR)
OLE2CT (LPCOLESTR) - > (LPCTSTR)
OLE2T (LPCOLESTR) - > (LPCSTR)
Nuevamente existen macros similares para hacer TEXTMETRIC, DEVMODE, BSTRy OLE asignan cadenas. Consulte AFXPRIV.H para obtener más información.
Otras consideraciones
No utilizar las macros en un bucle apretado. Por ejemplo, no desea escribir el siguiente tipo de código:
void BadIterateCode(LPCTSTR lpsz)
{
USES_CONVERSION;
para (int ii = 0; ii lt; 10000; ii ++)
pI - > SomeMethod (ii, T2COLE(lpsz));
}
El código a&nterior podría asignar megabytes de memoria en la pila dependiendo de lo que el contenido de la cadena lpsz es! nbsp; También toma tiempo para convertir la cadena para cada iteración del bucle. En su lugar mover esas conversiones constantes fuera del bucle:
void MuchBetterIterateCode(LPCTSTR lpsz)
{
USES_CONVERSION;
LPCOLESTR lpszT = T2COLE(lpsz);
para (int ii = 0; ii lt; 10000; ii ++)
pI - > SomeMethod ii (lpszT);
}
Si la cadena no es constante, luego encapsular la llamada a un método en una función. Esto permitirá que el búfer de conversión ser liberados cada vez. Por ejemplo:
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 devolver el resultado de una de las macros, a menos que el valor de retorno implica realizar una copia de los datos antes de la devolución. Por ejemplo, este código es malo:
LPTSTR BadConvert(ISomeInterface* pI)
{
USES_CONVERSION;
LPOLESTR lpsz = NULL;
pI-gt;GetFileName(&lpsz);
LPTSTR lpszT = OLE2T(lpsz);
CoMemFree(lpsz);
Return lpszT; / / mal! volviendo alloca memoria
}
El código anterior pudieron solucionarse cambiando el valor de retorno a algo que se copiará el valor:
CString BetterConvert(ISomeInterface* pI)
{
USES_CONVERSION;
LPOLESTR lpsz = NULL;
pI-gt;GetFileName(&lpsz);
LPTSTR lpszT = OLE2T(lpsz);
CoMemFree(lpsz);
Return lpszT; / / CString hace copia
}
Las macros son fáciles de usar y fácil de insertar en el código, pero como puede decir de las salvedades anteriores, necesita tener cuidado cuando usarlos.
&Notas técnicas por número |nbsp; Notas técnicas por categoría