Cette note décrit comment utiliser les macros de conversion de MBCS/Unicode qui sont définis dans AFXPRIV.H. ces macros sont plus utiles si les offres de votre demande directement avec l'API OLE ou pour une raison quelconque, doit souvent convertir entre Unicode et MBCS.
Vue d'ensemble
Dans les MFC 3.x, a utilisé une DLL particulière (MFCANS32.DLL) pour convertir automatiquement entre Unicode et MBCS lorsque les interfaces OLE ont été appelés. Cette DLL est une couche presque transparente qui permet des applications OLE être écrit comme si les API OLE et les interfaces ont été MBCS, même si elles sont toujours Unicode (sauf sur Macintosh). Alors que cette couche est commode et accueilli les demandes être rapidement porté de Win16 pour Win32 (MFC, Microsoft Word, Microsoft Excel et VBA, sont quelques-unes des applications Microsoft qui utilise cette technologie), il avait également un rendement parfois important a frappé. Pour cette raison, les MFC 4.x n'utilise pas cette DLL et parle plutôt directement aux interfaces OLE Unicode. Pour ce faire, MFC doit convertir en Unicode pour MBCS lorsqu'un appel à une interface OLE et doit souvent convertir en MBCS de Unicode lors de l'implémentation d'une interface OLE. Afin de traiter cela efficacement et facilement, un certain nombre de macros ont été créé pour faciliter cette conversion.
Un des plus grands obstacles de la création d'un tel ensemble de macros est l'allocation de mémoire. Parce que les chaînes ne peut pas être convertis en place, nouveau mémoire pour contenir les résultats convertis doit être attribué. Cela aurait pu être fait avec un code semblable au suivant:
/ / Nous voulons convertir une chaîne MBCS dans lpszA
nLen int = MultiByteToWideChar (CP_ACP, 0, lpszA, -1, NULL, NULL) ;
LPWSTR lpszW = nouveau WCHAR [nLen] ;
MultiByteToWideChar (CP_ACP, 0, lpszA, -1, lpszW, nLen) ;
/ / l'utiliser pour appeler OLE ici
pI-> ;SomeFunctionThatNeedsUnicode(lpszW) ;
/ / libérer la chaîne
delete [] lpszW
Cette approche comme un certain nombre de problèmes. Le principal problème est que c'est beaucoup de code à écrire, tester et déboguer. Quelque chose qui était un appel de fonction simple, est maintenant beaucoup plus complexe. En outre, il y a une exécution des frais généraux en faisant. Mémoire doit être alloué sur le tas et libérée chaque fois qu'une conversion est effectuée. Enfin, le code ci-dessus doit avoir lieu #ifdefs ajoutés pour les versions Unicode et Macintosh (qui ne nécessitent pas cette conversion aura lieu).
La solution que nous avons est de créer des macros qui 1) masque la différence entre les différentes plates-formes et utilisation 2) un régime d'allocation de mémoire efficace et 3) sont facile à insérer dans l'existant de code source. Voici un exemple de l'une des définitions:
# define A2W(lpa) (\
nbsp ; (APL (LPCSTR) == &NULL) ? NULL: (\
_convert = (strlen (APL) + 1), \
AfxA2WHelper((LPWSTR) alloca(_convert*2), APL, _convert) \
)\
)
À l'aide de cette macro au lieu du code ci-dessus et les choses sont beaucoup plus simple:
/ / l'utiliser pour appeler OLE ici
USES_CONVERSION ;
pI-> ;SomeFunctionThatNeedsUnicode(T2OLE(lpszA))
Il y a des appels supplémentaires où la conversion est nécessaire, mais en utilisant les macros est simple et efficace.
La mise en œuvre de chaque macro utilise la fonction _alloca() pour allouer de la mémoire de la pile au lieu du tas. Allocation de mémoire de la pile est beaucoup plus rapide que l'allocation de mémoire sur le tas, et la mémoire est automatiquement libérée lorsque la fonction est sortie. En outre, les macros éviter d'appeler MultiByteToWideChar (ou WideCharToMultiByte) plus d'une fois. Cela se fait en attribuant un peu plus de mémoire que nécessaire. Nous savons qu'un MBC convertira en tout au plus un WCHAR et que nous aurons un maximum de deux octets MBC pour chaque WCHAR . En consacrant un peu plus que nécessaire, mais toujours assez pour gérer la conversion du deuxième appel deuxième appel à la fonction de conversion est évité. L'appel à la fonction d'assistance AfxA2Whelper réduit le nombre de pushes argument qui doit être fait afin d'effectuer la conversion (il en résulte dans le plus petit code, que si elle appelée MultiByteToWideChar directement).
Dans l'ordonnance pour les macros disposer d'espace pour stocker l'une durée temporaire, il est nécessaire de déclarer une variable locale appelée _convert qui fait cela dans chaque fonction qui utilise les macros de conversion. Cela se fait en invoquant la macro USES_CONVERSION , comme vu dans l'exemple.
Il y a des macros génériques de conversion et macros spécifiques OLE. Ces deux ensembles différents de macro sont discutées ci-dessous. Toutes les macros se trouvent dans AFXPRIV.H.
Macros de Conversion générique
Les macros de conversion générique forment le mécanisme sous-jacent. L'exemple de macro et de la mise en œuvre dans la section précédente, A2W, est un tel macro « générique ». Il n'a expressément aucun lien OLE. L'ensemble des macros génériques est ci-dessous :
A2CW (LPCSTR) - gt ; (LPCWSTR)
A2W (LPCSTR) - > (LPWSTR)
W2CA (LPCWSTR) - > (LPCSTR)
W2A (LPCWSTR) - > (LPSTR)
En plus de faire des conversions de texte, il y a aussi des macros et des fonctions d'assistance pour la conversion TEXTMETRIC, DEVMODE, BSTRet OLE alloué des chaînes. Ces macros sont au-delà de la portée de cette discussion, se référer à AFXPRIV.H pour plus d'informations sur ces macros.
OLE Macros de Conversion
Les macros de conversion OLE sont spécialement conçus pour la manipulation des fonctions qui attendent OLESTR caractères. Si vous examinez les en-têtes OLE, vous pourrez voir de nombreuses références à LPCOLESTR et OLECHAR. Ces types sont utilisés pour désigner le type de caractères utilisés dans les interfaces OLE d'une manière qui n'est pas spécifique à la plate-forme. Cartes OLECHAR de char dans les plateformes Macintosh et de Win16 et WCHAR dans Win32.
Afin de réduire le nombre de directives # ifdef dans le code MFC au minimum, nous avons une macro similaire pour chaque conversion qu'où sont impliqués des chaînes OLE. Les macros suivantes sont les plus couramment utilisés:
T2COLE (LPCTSTR) - gt ; (LPCOLESTR)
T2OLE (LPCTSTR) - > (LPOLESTR)
OLE2CT (LPCOLESTR) - > (LPCTSTR)
OLE2T (LPCOLESTR) - > (LPCSTR)
Encore une fois, il y a des macros similaires pour faire TEXTMETRIC, DEVMODEet OLE BSTRalloué des chaînes. Reportez-vous à AFXPRIV.H pour plus d'informations.
Autres considérations
N'utilisez pas les macros dans une boucle serrée. Par exemple, vous ne souhaitez pas écrire le type suivant de code:
vOID BadIterateCode(LPCTSTR lpsz)
{
USES_CONVERSION ;
for (int ii = 0; lt ii 10000 ; ii ++)
pI - > SomeMethod (ii, T2COLE(lpsz)) ;
}
Le code ci-dessus pourrait se traduire par l'attributio&n de mégaoctets de mémoire sur la pile selon ce que le contenu de la chaîne lpsz est! nbsp ; Il faut aussi du temps pour convertir la chaîne pour chaque itération de la boucle. Au lieu de cela déplacer telles conversions constantes hors de la boucle:
vOID MuchBetterIterateCode(LPCTSTR lpsz)
{
USES_CONVERSION ;
LPCOLESTR lpszT = T2COLE(lpsz) ;
for (int ii = 0; lt ii 10000 ; ii ++)
pI - > SomeMethod (ii, lpszT) ;
}
Si la chaîne n'est pas constante, puis encapsuler l'appel de méthode dans une fonction. Cela permettra à la mémoire tampon de conversion être libérée chaque fois. Par exemple:
vOID CallSomeMethod (int ii, LPCTSTR lpsz)
{
USES_CONVERSION ;
pI-gt ;SomeMethod (ii, T2COLE(lpsz)) ;
}
VOID MuchBetterIterateCode2 (LPCTSTR * lpszArray)
{
for (int ii = 0; ii < 10000 ; ii ++)
CallSomeMethod (ii, lpszArray[ii]) ;
}
Jamais retourner le résultat de l'une des macros, sauf si la valeur de retour implique de faire une copie des données avant le retour. Par exemple, ce code est mauvais:
LPTSTR BadConvert(ISomeInterface* pI)
{
USES_CONVERSION ;
LPOLESTR lpsz = NULL ;
pI-gt ;GetFileName(&lpsz) ;
LPTSTR lpszT = OLE2T(lpsz) ;
CoMemFree(lpsz) ;
Return lpszT ; / / mauvaise ! mémoire consacré de retour
}
Le code ci-dessus pourrait être résolu en changeant la valeur de retour à quelque chose qui copie la valeur:
BetterConvert(ISomeInterface* pI) de CString
{
USES_CONVERSION ;
LPOLESTR lpsz = NULL ;
pI-gt ;GetFileName(&lpsz) ;
LPTSTR lpszT = OLE2T(lpsz) ;
CoMemFree(lpsz) ;
Return lpszT ; / / CString fait copie
}
Les macros sont faciles à utiliser et facile à insérer dans votre code, mais que vous pouvez dire par les mises en garde ci-dessus, vous devez être prudent lorsque vous utilisez les.
&Notes techniques par le numéro |nbsp ; Notes techniques par catégorie