FAQ VC++ et MFCConsultez toutes les FAQ
Nombre d'auteurs : 20, nombre de questions : 545, dernière mise à jour : 5 avril 2013 Ajouter une question
Cette faq a été réalisée pour répondre aux questions les plus fréquement posées sur le forum Développement Visual C++
Je tiens à souligner que cette faq ne garantit en aucun cas que les informations qu'elle contient sont correctes ; Les auteurs font le maximum, mais l'erreur est humaine. Si vous trouvez une erreur, ou si vous souhaitez devenir redacteur, lisez ceci.
Sur ce, je vous souhaite une bonne lecture. Farscape
- Comment convertir un BSTR en chaîne ordinaire et vice-versa ?
- Comment convertir une CString en int, double, long ?
- Comment convertir une CString vers une std::string et vice et versa ?
- Comment convertir des chaînes hexa en integer, inversement et plus largement comment changer la base d'une valeur dans une string ?
- Quel est le nombre de caractères maximum que peut contenir une CString ?
- Comment faire une extraction dans une CString avec des séparateurs ?
- Comment créer une chaîne de type BSTR ?
- Comment concaténer 2 BSTR ?
- Comment libérer une chaîne de type BSTR ?
- Comment convertir un entier, un double, un float, etc, en chaîne de caractères ?
- Comment convertir des chaînes de caractères en ANSI et en UNICODE avec les MFC ?
- Comment convertir une CString ?
- Comment récupérer directement le contenu d'un contrôle dans un entier,double,long, etc.?
- Comment affecter directement le contenu d'une variable de type int,long,double ... à un contrôle ?
- Comment encoder une chaîne au format UTF8 ?
- Comment décoder une chaîne au format UTF8 ?
- Comment convertir une chaîne UNICODE en Char * ?
Si vous développez des ActiveX ou objets COM avec Visual C++, vous allez devoir utiliser les BSTR lors de manipulation de chaînes de caractères.
Le type BSTR (Basic STRing) est un pointeur de 32 bits (comme tous les pointeurs) qui pointe vers un tableau de caractères UNICODE.
En représentation UNICODE, 1 caractère est codé sur 2 octets, alors qu'en ASCII, 1 caractère est codé sur 1 octet.
Ce type est utilisé par Automation pour la manipulation de chaînes de caractères. Il est défini dans les spécifications d'OLE 2.0 comme
Code C++ : | Sélectionner tout |
typedef OLECHAR FAR* BSTR;
Voici deux fonctions utilisant l'api Windows pour le transtypage en char* :
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | void BSTRtoASC (BSTR str, char * &strRet) { if ( str != NULL ) { unsigned long length = WideCharToMultiByte (CP_ACP, 0, str, SysStringLen(str), NULL, 0, NULL, NULL); strRet = new char[length]; length = WideCharToMultiByte (CP_ACP, 0, str, SysStringLen(str), reinterpret_cast <char *>(strRet), length, NULL, NULL); strRet[length] = '\0'; } } void ASCtoBSTR (char * str, BSTR * strRet) { if ( str != NULL ) { unsigned long length = strlen(str); int ResultLength = MultiByteToWideChar (CP_ACP,MB_PRECOMPOSED, reinterpret_cast <char *>(str),length,NULL,0); *strRet = SysAllocStringLen( NULL, ResultLength); MultiByteToWideChar (CP_ACP,MB_PRECOMPOSED, reinterpret_cast <char *>(str),length,*strRet,ResultLength); } } |
Code C++ : | Sélectionner tout |
1 2 | CString strResult("un test de chaîne"); return strResult.AllocSysString(); |
La classe CString dispose de l'opérateur (const char *), de ce fait toutes les fonctions C disposant d'une signature const char * peuvent être utilisées.
Exemple de conversions d'une CString en différents types de données :
Cet exemple est adapté d'un code trouvé sur MSDN pour la fonction strtoul.
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | char *stopstring; double x; long l; int base; unsigned long ul; CString string="3.1415926This stopped it"; x = strtod( string, &stopstring ); TRACE( "string = %s\n",(const char *)string ); TRACE(" strtod = %f\n", x ); TRACE(" Stopped scan at: %s\n\n", stopstring ); string = "-10110134932This stopped it"; l = strtol( string, &stopstring, 10 ); TRACE( "string = %s",(const char *)string ); TRACE(" strtol = %ld", l ); TRACE(" Stopped scan at: %s", stopstring ); string = "10110134932"; TRACE( "string = %s\n",(const char *)string ); /* Convert string using base 2, 4, and 8: */ for( base = 2; base <= 8; base *= 2 ) { /* Convert the string: */ ul = strtoul( string, &stopstring, base ); TRACE( " strtol = %ld (base %d)\n", ul, base ); TRACE( " Stopped scan at: %s\n", stopstring ); } |
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 | string = 3.1415926This stopped it strtod = 3.141593 Stopped scan at: This stopped it string = -10110134932This stopped it strtol = -2147483647 Stopped scan at: This stopped itstring = 10110134932 strtol = 45 (base 2) Stopped scan at: 34932 strtol = 4423 (base 4) Stopped scan at: 4932 strtol = 2134108 (base 8) Stopped scan at: 932 |
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include <sstream> template<typename T> bool ConvertCString( const CString & Str, T & Dest ) { // créer un flux à partir de la chaîne donnée std::istringstream iss( static_cast<const char *>( Str) ); // tenter la conversion vers Dest return iss >> Dest != 0; } CString str="25"; int nInt; ConvertCString( str, nInt ); //ou ConvertCString( "25", nInt );// fonctionne aussi ... |
Conversion d'une CString vers une std::string :
Code C++ : | Sélectionner tout |
1 2 | CString str("Bonjour"); std::string s((LPCTSTR)str); |
Conversion d'une std::string vers une CString :
Code C++ : | Sélectionner tout |
1 2 | std::string s("Bonjour"); CString str(s.c_str()); |
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | //*************************************************************************** // Change la base d'une valeur sous forme de chaîne. //*************************************************************************** CString COutils::ChangeBase(CString Value, int BaseFrom, int BaseTo) { CString ValBaseChanged; if (!( BaseFrom <2 || BaseFrom >36 || BaseTo <2 || BaseTo >36) ) { char *StopScan= NULL; char StrBaseOut[250]; intValIn= 0; //Merci nico-pyright(c) ValIn = strtol(Value.GetBuffer(0), &StopScan, BaseFrom); _itoa(ValIn, StrBaseOut, BaseTo); ValBaseChanged = CString(StrBaseOut, strlen(StrBaseOut)); } else { ValBaseChanged = "Invalid Base Number"; } return ValBaseChanged; } |
Code C++ : | Sélectionner tout |
1 2 3 4 5 | char *StopScan= NULL; intValIn= 0; //Merci nico-pyright(c) ValIn = strtol(Value.GetBuffer(0), &StopScan, BaseFrom); |
Remarque : transformer un int en string hexa peut être fait grâce à la fonction format de CString :
Code C++ : | Sélectionner tout |
1 2 3 4 | CString StrHexa; int Val = 125; StrHexa.Format("%X",Val); |
On trouve la réponse dans le code de la classe CString avec la fonction AllocBuffer qui est utilisée pour allouer la mémoire nécessaire :
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | void CString::AllocBuffer(int nLen) // always allocate one extra character for '\0' termination // assumes [optimistically] that data length will equal allocation length { ASSERT(nLen >= 0); ASSERT(nLen <= INT_MAX-1); // max size (enough room for 1 extra) if (nLen == 0) Init(); else { CStringData* pData; #ifndef _DEBUG if (nLen <= 64) { pData = (CStringData*)_afxAlloc64.Alloc(); pData->nAllocLength = 64; } else if (nLen <= 128) { pData = (CStringData*)_afxAlloc128.Alloc(); pData->nAllocLength = 128; } else if (nLen <= 256) { pData = (CStringData*)_afxAlloc256.Alloc(); pData->nAllocLength = 256; } else if (nLen <= 512) { pData = (CStringData*)_afxAlloc512.Alloc(); pData->nAllocLength = 512; } else #endif { pData = (CStringData*) new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)]; pData->nAllocLength = nLen; } pData->nRefs = 1; pData->data()[nLen] = '\0'; pData->nDataLength = nLen; m_pchData = pData->data(); } } |
Notez aussi le traitement différent dans le cas du mode release et debug qui peut expliquer que certains bogues de mémoire n'apparaissent pas en release.
Classiquement cette opération pourrait être réalisée avec la fonction C strtok.
Mais celle-ci à l'inconvénient de perturber la chaîne d'origine et de ne pas fonctionner dans certains cas :
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 | CString str = "aaa,bbb,ccc,,123"; CString strTemp = str; char *pWord = strtok(strTemp.GetBuffer(0), ","); while (pWord != NULL) { // Work // .................. afxDump << "\nWord:" << "\"" << pWord << "\""; // Get Next Token pWord = strtok( NULL, "," ); } strTemp.ReleaseBuffer(); |
donnera successivement :
Word:"bbb"
Word:"ccc"
Word:"123"
Code proposé pour fonctionner avec des CString :
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | CString CStringTok(const char *szToken, const char *szDelimit, bool &rbEndParse) { CString strOrg, str; static const char *pszOrg = NULL; ASSERT(szDelimit != NULL); if(szToken) { pszOrg = szToken; rbEndParse = false; } if(!pszOrg) { rbEndParse = true; return ""; } strOrg = pszOrg; int nPos = strOrg.Find(szDelimit); if(nPos != -1) { str = strOrg.Left(nPos); pszOrg += (nPos + strlen(szDelimit)); } else { str = strOrg; pszOrg = NULL; } return str; } |
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | CString strOrg = "aaa,bbb,,ccc"; bool bEndParse; CString strWord = CStringTok(strOrg, ",", bEndParse); while (!bEndParse) { // Work // .................. afxDump << "\nWord:" << "\"" << strWord << "\""; // Get Next Token strWord = CStringTok(NULL, ",", bEndParse); } |
donnera successivement :
Word:"bbb"
Word:""
Word:"ccc"
Code C++ : | Sélectionner tout |
BSTR chaine = SysAllocString(L"Exemple de chaine");
On pourra utiliser SysStringLen pour faire une copie par exemple
Code C++ : | Sélectionner tout |
BSTR chaine2 = SysAllocStringLen(chaine, SysStringLen(chaine));
Pour créer une chaîne depuis un char *, on pourra se reporter à l'utilisation de la fonction décrite ici Comment convertir un BSTR en chaîne ordinaire et vice-versa ?
Code C++ : | Sélectionner tout |
1 2 3 | char t1[] = "Exemple"; BSTR test1; ASCtoBSTR(t1, &test1); |
Code C++ : | Sélectionner tout |
1 2 3 4 | BSTR chaine1 = SysAllocString(L"Exemple "); BSTR chaine2 = SysAllocString(L"de chaine"); BSTR chaine3; VarBstrCat(chaine1, chaine2, &chaine3); |
Il ne faudra pas oublier de libérer la mémoire avec SysFreeString
Code C++ : | Sélectionner tout |
SysFreeString(chaineBstr);
La classe CString dispose d'une méthode Format qui prend en charge les conversions des types entier, double, float ,long etc. de la même manière que la fonction printf ou sprintf du C,
Elle utilise donc les mêmes options.
Quelques exemples de conversions :
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | CString str; str.Format(_T("Float arrondi 2 décimales: %.2f\n"), 12345.12345); str.Format(_T("Float longueur 10 dont 2 décimales: %10.2f\n"), 12345.12345); str.Format(_T("entier cadré a gauche : %.6d\n"), 35); str.Format(_T("entier cadré avec zéro : %06d\n"), 35); CString str2=_T("essai") ; str.Format(_T("chaine :%s: \n"), static_cast<const char *>(str2)); char c='1'; str.Format(_T("char %c", c) ; |
Pour plus de détails, consultez la liste des spécifications de format
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | { CStringW wstr = L"Chaine UNICODE"; CStringA str(wstr); // convertit en ANSI LPCSTR lpcstr = str; AfxMessageBox(lpcstr); } { CComBSTR bstr = L"Chaine UNICODE"; CStringA str(bstr); // convertit en ANSI LPCSTR lpcstr = str; AfxMessageBox(lpcstr); } { CStringA str = "Chiane ANSI"; CStringW wstr(str); // convertit en UNICODE LPCWSTR lpcwstr = wstr; } { CStringA str = "Chaine ANSI"; CComBSTR bstr(str); // convertit en UNICODE BSTR b = bstr; } { GUID guid; ::CoCreateGuid(&guid); // j'obtient un GUID CComBSTR bstrGuid(guid); // je convertit en UNICODE CStringA strGuid(bstrGuid); // Je convertit en ANSI AfxMessageBox(strGuid); // et j'affiche AfxMessageBox(CStringA(CComBSTR(guid))); // ou bien... } |
Les constructeurs des classes CString et CComBSTR réalisent aisément des conversions pour nous.
Encore mieux CComBSTR convertit un GUID (Global Unique Identifier ou UUID= Universal Unique ID) en Unicode BSTR.
En dehors des méthodes déjà présentées pour la conversion Comment convertir une CString en int, double, long ?
Voici une autre méthode plus C++ de procéder :
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #include <string> #include <iostream> #include <sstream> template<typename T,typename S> bool FromString( const S & Str, T & Dest ) { #ifdef _UNICODE std::wistringstream iss( Str ); #else std::istringstream iss( Str ); #endif // tenter la conversion vers Dest return iss >> Dest != 0; } |
Utilisation :
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | int nInt ; FromString(_T("10"), nInt ); // conversion en int. double dDouble; FromString( _T("3.14107"), dDouble ); // conversion en double CString str=_T("1200"); #ifdef _UNICODE std::wstring strstl; #else std::string strstl; #endif strstl=_T("1200"); int n=0; FromString(str.GetString(),n); n=0; FromString(strstl,n); |
les MFC comme l'api 32 permettent avec GetDlgItemInt la récupération du contenu d'un contrôle sous forme d'entier.
Mais quid des autres types long, float, double ?
Pour ces autres types il faudra attacher au contrôle une variable correspondante au type de donnée souhaité et appeler la méthode UpdateData(TRUE) pour disposer de la valeur.
Le code qui suit permet de se passer de l'association d'une variable à un contrôle et donc de récupérer directement la valeur pour le type souhaité.
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #include <sstream> #include <string> #include <iostream> template<typename T> bool FromCtrl( const CWnd & Ctrl, T & Dest ) { CString Str; Ctrl.GetWindowText(Str); #ifdef _UNICODE std::wistringstream iss( static_cast<LPCTSTR>( Str) ); #else std::istringstream iss( static_cast<LPCTSTR>( Str) ); #endif // tenter la conversion vers Dest return iss >> Dest != 0; } |
Utilisation :
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 | double d; FromCtrl(*GetDlgItem(IDC_EDITNOM),d); if(d==10.0) { // traitement } // etc. |
Les MFC comme l'api 32 permettent avec SetDlgItemInt l'affection d'un entier au contrôle.
Mais quid des autres types long, float, double ?
Pour ces autres types il faudra attacher au contrôle une variable correspondante au type de donnée traité et appeler la méthode UpdateData(FALSE) pour mettre à jour le contrôle.
Le code qui suit permet de se passer de l'association d'une variable à un contrôle et donc d'affecter directement une valeur d'un type donné au contrôle.
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | #include <sstream> #include <string> #include <iomanip> #include <iostream> class FormatNum { public : FormatNum(){} template <typename T> FormatNum(const T&t) { operator <<(t); } template <typename T> FormatNum & operator << (const T& t) { m_ss << t; return *this; } public : #ifdef _UNICODE std::wstringstream m_ss; #else std::stringstream m_ss; #endif }; template<typename T> void ToCtrl(CWnd & Ctrl,const T & Src,FormatNum &rFormat=FormatNum()) { rFormat << Src; #ifdef _UNICODE std::wstring s=rFormat.m_ss.str(); #else std::string s=rFormat.m_ss.str(); #endif Ctrl.SetWindowText(s.c_str()); } |
Utilisation :
Code C++ : | Sélectionner tout |
1 2 3 4 5 | // met 10.345 dans le contrôle. ToCtrl(*GetDlgItem(IDC_EDITNUM),10.345); // met 10.35 dans le contrôle. ToCtrl(*GetDlgItem(IDC_EDITNUM),10.345, FormatNum()<<std::setprecision(4)); |
Le traitement se décompose en deux parties :
La fonction modèle ToCtrl permettant la transformation du type utilisateur et l'affectation de la chaîne au contrôle passée en argument.
Un objet fonction FormatNum optionnel qui permet le formatage du flux pour contrôler la conversion, l'enchainement des arguments, et qui fournit l'objet flux de conversion de la classe stringstream à la fonction modèle ToCtrl.
Voyons son utilisation dans les exemples qui suivent :
Dans le cas d'un double ou float si on veut maitriser la précision du nombre envoyé on pourra utiliser la fonction setprecision définie dans l'entête standard <iomanip> pour fixer le nombre de digits souhaités.
Vous pouvez bien-sûr utiliser les autres fonctions et compléter le flux
Exemples :
Contrôler la longueur de la chaîne créée, et spécifier un caractère de remplissage.
Code C++ : | Sélectionner tout |
1 2 3 | // donne 0000010.35 ToCtrl(*GetDlgItem(IDC_EDITNUM),10.345, FormatNum()<<std::setprecision(4)<<std::setfill(_TCHAR('0'))<<std::setw(10)); |
Cet exemple impose une précision de 4 digits, une chaîne de 10 caractères remplie avec des '0'.
Dans le même ordre d'idée on pourra fixer la base de conversion...
Code C++ : | Sélectionner tout |
1 2 3 | // donne 0000000020 ToCtrl(*GetDlgItem(IDC_EDITNUM),32, FormatNum()<<std::setprecision(4)<<std::setfill(_TCHAR('0'))<<std::setw(10)<<setbase(16)); |
Enfin rajouter du texte devant la conversion :
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 | // donne: Conversion Hexa: 0x0000000020 ToCtrl(*GetDlgItem(IDC_EDITNUM), 32, FormatNum()<<_T("Conversion Hexa: 0x") <<std::setprecision(4)<<std::setfill(_TCHAR('0'))<<std::setw(10)<<setbase(16)); //ou ToCtrl(*GetDlgItem(IDC_EDITNUM), 32, FormatNum(_T("Conversion Hexa: 0x"))<<std::setprecision(4)<<std::setfill(_TCHAR('0'))<<std::setw(10)<<setbase(16)); |
Ou encore une syntaxe plus aérée :
Code C++ : | Sélectionner tout |
1 2 3 4 | FormatNum format; format <<_T("Conversion Hexa: 0x") <<std::setprecision(4)<<std::setfill(_TCHAR('0'))<<std::setw(10)<<setbase(16); ToCtrl(*GetDlgItem(IDC_EDITNUM),32,format); // donne: Conversion Hexa: 0x0000000020[FONT=monospace] |
Vous noterez aussi l'utilisation optionnelle de la spécification du format de conversion (FormatNum).
On pourra compléter notre traitement par une fonction de conversion vers une CString ou string de la STL.
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | template<typename T,typename S> void ToString(S & rstr,const T & Src,FormatNum &rFormat=FormatNum()) { rFormat << Src; #ifdef _UNICODE std::wstring s=rFormat.m_ss.str(); #else std::string s=rFormat.m_ss.str(); #endif rstr=s.c_str(); } |
Utilisation :
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 | CString str; ToString(str,1200); #ifdef _UNICODE std::wstring strstl; #else std::string strstl; #endif ToString(strstl,1200); |
UTF-8 (UCS transformation format 8 bits) permet de coder de l'Unicode sous une suite de 4 octets maximum.
Cette codification est par exemple utilisée dans le fichier document.xml au format OpenXml de Word 2007.
Les caractères dont le code ASCII est supérieur à 127 sont codés sur plusieurs octets.
Le code ci-dessus s'appuie sur la description donnée dans Wikipédia
Notes :
- Une chaîne au format UTF8 peut être contenue dans une CString multi bytes.
- J'ai implémenté la codification sur 4 octets mais l'exemple de Wikipédia avec le "?" ne semble pas correct dans ce cas puisque son code ASCII est égal à 63.
- Ce code ne fonctionne pas directement avec Visual 6.0 à cause des CString: On ne dispose pas de CStringA et de CStringW...
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | //------------------------------------------------------------------------- CStringA UTF8EncodeString(const CStringA str) { CStringW input(str); CStringA output; for(int i=0; i < input.GetLength(); i++) { // 0xxxxxxx if(input[i] < 0x80) { output+=input[i]; } // C0 80 // 110xxxxx 10xxxxxx else if((input[i] > 0x7F) && (input[i] < 0x800)) { output+=static_cast<unsigned char>(0xC0 | (input[i] >> 6)); output+=static_cast<unsigned char>(0x80 | (input[i] & 0x3F)); } // E0 80 80 // 1110xxxx 10xxxxxx 10xxxxxx else if(input[i] < 0x8000) { output+=static_cast<unsigned char>(0xE0 | (input[i] >> 12)); output+=static_cast<unsigned char>(0x80 | (input[i] >> 6 & 0x3F)); output+=static_cast<unsigned char>(0x80 | (input[i] & 0x3F)); } else { // F0 80 80 80 //11110xxx 10xxxxxx 10xxxxxx 10xxxxxx output+=static_cast<unsigned char>(0xF0 | (input[i] >> 12)>>6); output+=static_cast<unsigned char>(0x80 | (input[i] >> 12 & 0x3F)); output+=static_cast<unsigned char>(0x80 | (input[i] >> 6 & 0x1F)); output+=static_cast<unsigned char>(0x80 | (input[i] & 0x3F)); } } return output; } |
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 | CStringA input,output; input = "é"; output = UTF8EncodeString(input); TRACE("\n output é:%s", static_cast<const char *>(output)); input = "€"; output = UTF8EncodeString(input); TRACE("\n output €:%s",static_cast<const char *>(output)); |
Pour plus d'informations voir la question Comment encoder une chaîne au format UTF8 ?
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | CStringA UTF8DecodeString(const CStringA input) { CStringW output; for(int i=0; i < input.GetLength();i++) { // F0 80 80 80 //11110xxx 10xxxxxx 10xxxxxx 10xxxxxx if((input[i] & 0xFE) == 0xFE) { output+= static_cast<wchar_t>(((input[i] & 7 )<< 18) | ((input[i+1] & 0x3F) << 12) | ((input[i+2] & 0x3F) << 6) | (input[i+3] & 0x3F)); i += 3; } else // E0 80 80 // 1110xxxx 10xxxxxx 10xxxxxx if((input[i] & 0xE0) == 0xE0) { output+= static_cast<wchar_t>(((input[i] & 0x0F) << 12) | ((input[i+1] & 0x3F) << 6) | (input[i+2] & 0x3F)); i += 2; } // C0 80 // 110xxxxx 10xxxxxx else if((input[i] & 0xC0) == 0xC0) { output+= static_cast<wchar_t>(((input[i] & 0x1F) << 6) | (input[i+1] & 0x3F)); i ++; } // 0xxxxxxx else if(input[i] < 0x80) output+=input[i]; } return CStringA(output); } |
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 | CStringA input,output; input = "é"; output = UTF8EncodeString(input); TRACE("\n output é:%s",static_cast<const char *>(output)); output = UTF8DecodeString(output); TRACE("\n output é:%s",static_cast<const char *>(output)); input = "€"; output = UTF8EncodeString(input); TRACE("\n output €:%s",static_cast<const char *>(output)); output = UTF8DecodeString(output); TRACE("\n output é:%s",static_cast<const char *>(output)); |
La conversion d'une chaîne UNICODE en chaîne de caractères est relativement aisée avec les MFC récentes (après visual 6.0).
En effet la classe CString permet de travailler sur les deux conventions UNICODE et Multi-Byte dans un même projet.
On aura alors :
La classe CString qui suivra le paramétrage du projet : UNICODE ou Multi-Byte
La classe CStringA pour travailler avec des chaînes de caractères Multi-Byte (char *) .
La classe CStringW pour travailler avec des chaînes Unicode.
Une conversion d'une chaîne UNICODE en Multi-Byte devient une chose aisée :
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 | // réglage du projet en UNICODE CString strWide = _T("chaine de caractères"); CStringA strA(strWide); CString strWideDup(strA); // l'inverse VERIFY(strWideDup == strWide); char *sz = strA.GetBuffer(0); |
L'exemple ci-dessus part d'une CString UNICODE et fournit une CString Multi-Byte et un pointeur sur char *.
Et enfin fabrique une CString UNICODE à partir d'une CString Multi-Byte
Avec Visual 6.0 :
CString travaille dans le mode réglé dans le projet.
Pour transformer une CString Unicode en chaîne de caractères il faudra utiliser l'api WideCharToMultiByte :
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 | // réglage du projet en UNICODE CString strWide = _T("chaine de caractères"); char *sz = new char [strWide.GetLength()+1] ; WideCharToMultiByte(CP_ACP, 0, strWide, -1, sz, strWide.GetLength()+1, NULL, NULL ); //...... delete[] sz; |
Pour transformer une chaîne de caractères en chaîne Unicode on utilisera MultiByteToWideChar
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // réglage du projet en UNICODE CString strWide = _T("chaine de caractères"); char *sz = new char [strWide.GetLength()+1] ; WideCharToMultiByte( CP_ACP, 0, strWide, -1, sz, strWide.GetLength()+1, NULL, NULL ); int nSize = strlen(sz) + 1; TCHAR *wsz = new TCHAR[nSize]; MultiByteToWideChar(CP_ACP, 0, sz,nSize, wsz,nSize); CString strWideDup = wsz; VERIFY(strWideDup == strWide); //...... delete[] wsz; delete[] sz; |
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.