Partager via


TN059 : Utilisation des macros de conversion MFC MBCS/Unicode

[!REMARQUE]

La note technique suivante n'a pas été modifiée depuis si c'était première inclus dans la documentation en ligne.Par conséquent, certaines procédures et rubriques peuvent être obsolètes ou incorrects.Pour obtenir les informations les plus récentes, il est recommandé que vous trouviez la rubrique d'intérêt dans l'index de la documentation en ligne.

Cette remarque décrit comment utiliser les macros pour la conversion mbcs/unicode, définies dans AFXPRIV.H.Il est très utile si votre application traite directement OLE API ou pour une raison quelconque, souvent les besoins convertir ces macros entre Unicode et MBCS.

Vue d'ensemble

Dans MFC 3.x, une DLL spéciale a été utilisé (MFCANS32.DLL) pour convertir automatiquement entre Unicode et MBCS lorsque de interfaces OLE est appelée.Cette DLL est une couche presque transparente qui a permis aux applications OLE d'être écrit comme si les OLE API et interfaces étaient MBCS, bien qu'elles soient toujours Unicode (sauf sur Macintosh.)Bien que cette couche a des applications pratiques et autorisées d'être rapidement déplacées de Win16 en Win32 (MFC, Microsoft Word, Microsoft Excel, et VBA, sont uniquement certaines applications Microsoft qui utilisaient cette technologie), elle avait une correspondance parfois significative des performances.Pour cette raison, MFC 4.x n'utilise pas cette DLL et ne décrit pas à la place directement aux interfaces Unicode OLE.Pour cela, les MFC doivent convertir au format Unicode en unicode ou en faisant appel à une NOTION interface, et souvent les besoins de convertir en UNICODE Unicode en implémentant une NOTION interface.Pour gérer cela rapidement et facilement, plusieurs macros ont été créées pour faciliter cette conversion.

L'un des principaux obstacles de créer un tel ensemble de macros est allocation de mémoire.Étant donné que les chaînes ne peuvent pas être converti en place, la nouvelle mémoire pour stocker les résultats convertis doit être allouée.Cela a pu être fait avec un code semblable au suivant :

// 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;

Cette approche comme un certain nombre de problèmes.Le principal problème est qu'il est beaucoup de code à écrire, tester, puis débogage.Quelque chose qui était un appel de fonction simple, est désormais beaucoup plus complexe.De plus, il existe une charge d'exécution significative ce faisant.La mémoire doit être allouée sur le tas et être libérée chaque fois qu'une conversion est effectuée.Enfin, le code ci-dessus doit avoir #ifdefs approprié ajouté pour les builds Unicode et Macintosh (qui ne requièrent pas que cette conversion s'effectue).

La solution que nous avons extensibilité avec consiste à créer des macros à 1) le masque la différence entre les différentes plateformes, et 2) utilisez un modèle d'allocation de mémoire efficace, et 3) sont faciles d'insérer dans le code source existant.Voici un exemple de l'une des définitions :

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

À l'aide de cette macro à la place de code ci-dessus et opérations sont beaucoup plus simple :

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

Il existe des appels supplémentaires pour lesquels la conversion est nécessaire, mais l'aide de macros est simple et efficace.

L'implémentation de chaque macro utilise la fonction d'alloca() _pour allouer de la mémoire de la pile au lieu du tas.Allouer de la mémoire de la pile est beaucoup plus rapide que l'allocation de mémoire sur le tas, et que la mémoire est automatiquement libérée lorsque la fonction est quittée.En outre, les macros évitent d'appeler plusieurs temps de MultiByteToWideChar (ou WideCharToMultiByte).Cela est fait en allouant un peu plus de mémoire que est nécessaire.Nous savons qu'un MBC convertira dans qu'un WCHAR et que chaque WCHAR nous prendrons un maximum de deux octets du MBC.En allouant un peu plus que nécessaire, mais suffisant toujours pour gérer la conversion l'appel du deuxième deuxième appel à la fonction de conversion est évité.L'appel à la fonction d'assistance AfxA2Whelper réduit le nombre de runtime pousse d'argument qui doivent être effectuées pour exécuter la conversion (cela provoque plus petit code, que s'il MultiByteToWideChar appelé directement).

Pour que les macros ait l'espace pour stocker une longueur temporaire, il est nécessaire de déclarer une variable locale appelée le _convert à cet effet dans chaque fonction qui utilise les macros de conversion.Cela est fait en appelant la macro d' USES_CONVERSION comme indiqué ci-dessus dans l'exemple.

Il existe des macros génériques de conversion et de OLE macros spécifiques.Ces deux macro ensembles différents sont présentés ci-dessous.Toutes les macros résident dans AFXPRIV.H.

Macros génériques de conversion

Les macros génériques de conversion constituent le mécanisme sous-jacent.L'exemple de macro et l'implémentation présentés dans la section précédente, A2W, est une telle macro « générique ».Il n'est pas lié à OLE spécifiquement.l'ensemble de macros génériques est répertorié ci-dessous :

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

Non seulement vous pouvez effectuer des conversions de texte, il existe également des macros et des fonctions d'assistance pour convertir TEXTMETRIC, DEVMODE, BSTR, et les chaînes allouées par OLE.Ces macros dépassent le cadre de cette rubrique – reportez -vous à AFXPRIV.H pour plus d'informations sur ces macros.

OLE macros de conversion

Les OLE macros de conversion sont conçues spécifiquement pour gérer les fonctions qui attendent des caractères d' OLESTR .Si vous examinez les OLE en-têtes, vous verrez de nombreuses références à LPCOLESTR et à OLECHAR.Ces types sont utilisés pour faire référence au type de caractères utilisés dans des interfaces OLE d'une façon qui n'est pas spécifique à la plateforme.Cartes d'OLECHAR à char dans Win16 et les plateformes Macintosh et à WCHAR dans Win32.

Pour conserver le nombre de directives de #ifdef dans le code MFC au minimum nous avons une macro similaire pour chaque conversion auquel OLE les chaînes sont impliquées.Les macros suivantes sont les plus courantes :

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

Là encore, il existe des macros similaires pour faire TEXTMETRIC, DEVMODE, BSTR, et les chaînes allouées par OLE.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 de code suivant :

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

Le code ci-dessus peut avoir en allouant de mégaoctets de mémoire sur la pile en fonction de ce qu'est le contenu de la chaîne lpsz !Il faut également le temps de convertir la chaîne pour chaque itération de la boucle.À la place, déplacez de ces conversions constantes hors de la boucle :

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

Si la chaîne ne correspond pas à une constante, ensuite encapsuler l'appel de méthode dans une fonction.Cela permettra à la mémoire tampon de conversion à libérer chaque fois.Par exemple :

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]);
}

Ne retourne jamais le résultat de l'une des macros, à moins que la valeur de retour implique copie des données avant le retour.Par exemple, ce code est incorrect :

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

Le code ci-dessus peut être résolu en modifiant la valeur de retour à ce qui copie la valeur :

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

Les macros sont faciles à utiliser et faciles à insérer dans votre code, mais comme vous pouvez demander des avertissements ci-dessus, vous devez être prudent lorsque les utilise.

Voir aussi

Autres ressources

Notes techniques de nombres

Notes techniques de catégorie