IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Visual C++ Discussion :

Conversion unicode (utf-8)


Sujet :

Visual C++

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2003
    Messages : 82
    Points : 50
    Points
    50
    Par défaut Conversion unicode (utf-8)
    Bonjour,
    Je m'attaque au portage d'un application existante vers Unicode.
    Je suis sous Visual C++ Embedded 4 et j'ai bien la propriété unicode dans les settings du projet.
    Actuellement, j'ai un CEdit, je récupère son contenu que je met dans un char* puis je l'envoi à une autre appli via une socket. Ensuite, dans l'autre sens, je reçois un char* via une socket puis je l'affiche dans un CEdit. Le but désormais est d'échanger de l'unicode (format utf-8) avec cette seconde appli.
    Comment (avec quel type et méthode) puis-je passer du contenu du CEdit à un char* en passant par un encodage utf-8 et vice versa ?
    Merci d'avance pour votre aide.

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 382
    Points : 41 593
    Points
    41 593
    Par défaut
    Je ne connais pas trop Embedded, mais traditionnellement sous Windows on utilise les fonctions libres MultiByteToWideChar() et WideCharToMultiByte() avec le paramètre CP_UTF8.

    J'ignore s'il y a plus évolué sous MFC, ni ce que permet ta version de MFC. Dans cette version, CString est-elle une classe ou y a-t-il le template CStringT?

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2003
    Messages : 82
    Points : 50
    Points
    50
    Par défaut
    Bonjour,

    Merci Médinoc pour la réponse.

    Je ne pense pas que CStringT, CStringA ou CStringW soient disponibles car ça a été implémenté après VC++ 6 d'après ce que dit la faq et là moi je suis sur une base de 4....
    Je me suis en effet tourné vers les méthodes MultiByteToWideChar() et WideCharToMultiByte() mais elles sont délicates à utiliser et je ne m'en sors pas pour le moment avec ce code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    LPWSTR orgUnicode = L"Coucou";
    LPSTR destUTF8 = NULL;
    //Unicode vers UTF-8
    WideCharToMultiByte(CP_UTF8, 0, orgUnicode, 6, destUTF8, 7, NULL, NULL); 
     
    orgUnicode = L"";
     
    //UTF-8 vers Unicode
    MultiByteToWideChar(CP_ACP, 0, destUTF8, 7, orgUnicode, 7); //wcslen(orgUnicode));
    Une idée de ce qui pourrait clocher ?

    Merci d'avance pour votre aide.

  4. #4
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 382
    Points : 41 593
    Points
    41 593
    Par défaut
    Pour faire une conversion, il faut deux appels à la même fonction:
    • Un avec un buffer nul, pour connaître la taille de buffer à allouer,
    • Et un avec un buffer fraichement alloué avec la bonne taille.

  5. #5
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 382
    Points : 41 593
    Points
    41 593
    Par défaut
    Pour la conversion vers Unicode, je m'étais fait cette fonction. Elle est plus compliquée que le strict nécessaire, mais elle est en C, retourne un HRESULT cas d'erreur et donne la taille de la chaîne en cas de succès:
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    /* Get a HRESULT from a Win32 error code, or E_UNEXPECTED */
    static HRESULT GetHResultFromWin32(DWORD error)
    {
    	HRESULT hr = HRESULT_FROM_WIN32(error);
    	if(SUCCEEDED(hr))
    		hr = E_UNEXPECTED;
    	return hr;
    }
     
    /* Convert a char string into an unicode string. */
    HRESULT GetUnicodeString(
     LPCSTR sczInA,    /*[in] char string.*/
     UINT codePage,    /*[in] Code page identifier, or CP_ACP etc.*/
     LPWSTR * pSzOutW, /*[out] Receives a pointer to the new wide character string.*/
     int * pCchWritten /*[out/opt] If set, receives the length of the wide character string, in characters. */
     )
    {
    	HRESULT hrRet = E_UNEXPECTED;
    	int cchSizeW = 0;
     
    	/*Initialize optional output parameters to their default values*/
    	if(pCchWritten != NULL)
    		*pCchWritten = 0;
    	/*Test other output parameters, and initialize to their default values as long as possible*/
    	if(pSzOutW==NULL)
    		return E_POINTER;
    	*pSzOutW = NULL;
     
    	/*Test input parameters*/
    	if(sczInA==NULL)
    		return E_INVALIDARG;
     
    	/*Calculate size*/
    	cchSizeW = MultiByteToWideChar(codePage, MB_ERR_INVALID_CHARS, sczInA, -1, NULL, 0);
    	if(cchSizeW <= 0)
    		hrRet = GetHResultFromWin32(GetLastError());
    	else
    	{
    		/*Alloc buffer*/
    		LPWSTR szOutW = malloc(cchSizeW * sizeof *szOutW);
    		if(szOutW==NULL)
    			hrRet = E_OUTOFMEMORY;
    		else
    		{
    			/*Use buffer*/
    			BOOL bKeepMem = FALSE;
    			int cchWritten = MultiByteToWideChar(codePage, MB_ERR_INVALID_CHARS, sczInA, -1, szOutW, cchSizeW);
    			if(cchWritten <= 0)
    				hrRet = GetHResultFromWin32(GetLastError()); /*This error is very unlikely to happen, since it was tested before*/
    			else
    			{
    				/*OK!*/
    				hrRet = S_OK;
    				bKeepMem = TRUE;
    				*pSzOutW = szOutW;
    				if(pCchWritten!=NULL)
    					*pCchWritten = cchWritten;
    			}
     
    			if(!bKeepMem)
    				free(szOutW);
    		}
    	}
    	return hrRet;
    }
     
    /* Delete a wide character string allocated by GetUnicodeString() */
    HRESULT FreeUnicodeString(LPWSTR szDelW)
    {
    	if(szDelW==NULL)
    		return S_FALSE;
    	free(szDelW);
    	return S_OK;
    }
    J'ai aussi en stock une version de cette fonction qui donne une BSTR à la place.

  6. #6
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Points : 50 369
    Points
    50 369
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Pour faire une conversion, il faut deux appels à la même fonction:
    • Un avec un buffer nul, pour connaître la taille de buffer à allouer,
    • Et un avec un buffer fraichement alloué avec la bonne taille.
    J'avais optimisé un peu la chose.

    Le premier appel, je donnais un buffer dont la taille était arbitraire (32 caractères), et je traitais les cas d'erreur. En cas d'erreur "buffer pas assez grand", je réallouais à la taille demandée et je faisais le deuxième appel.

    J'ai remarqué que dans la majorité des cas, j'économisais ainsi 1 appel.

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2003
    Messages : 82
    Points : 50
    Points
    50
    Par défaut
    Bonjour,

    Merci Médinoc et ram-0000 pour vos réponses.
    Je vais donc tester la méthode du double appels successifs et vous tiendrai informé du résultat.

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2003
    Messages : 82
    Points : 50
    Points
    50
    Par défaut
    Bonjour,

    Comme convenu, voici ce que j'ai implémenté pour effectuer les conversions.
    Il doit me reste encore quelques trucs à tester.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    //Unicode vers UTF-8
    int UTF8Chars = WideCharToMultiByte(CP_UTF8, 0, orgUnicode, wcslen(orgUnicode), 0, 0, 0, 0);
    LPSTR UTF8Buffer = (LPSTR)alloca(UTF8Chars);
    WideCharToMultiByte(CP_UTF8, 0, orgUnicode, wcslen(orgUnicode), UTF8Buffer, UTF8Chars, 0, 0); 
     
    //UTF-8 vers Unicode
    int InputChars = strlen(UTF8Buffer);
    int UnicodeChars = MultiByteToWideChar(CP_ACP, 0, UTF8Buffer, InputChars, 0, 0);
    LPWSTR UnicodeBuffer = (LPWSTR)alloca(UnicodeChars*sizeof(WCHAR));
    MultiByteToWideChar(CP_ACP, 0, UTF8Buffer, InputChars, UnicodeBuffer, UnicodeChars);
    En tout cas, j'aimerai avoir votre avis pour savoir si cela correspond bien à ce que vous proposiez ?

    Merci d'avance.

  9. #9
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 382
    Points : 41 593
    Points
    41 593
    Par défaut
    Ça y ressemble, en tout cas.
    Par contre, plutôt qu'appeler wcslen() à chaque fois, tu peux utiliser -1. Ou au moins, ne l'appeler qu'une seule fois et mémoriser le résultat...

    PS: Pourquoi utilises-tu CP_ACP au lieu de CP_UTF8 dans le second cas?

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2003
    Messages : 82
    Points : 50
    Points
    50
    Par défaut
    Bonjour,

    Oui pour la mémorisation, effectivement dans un soucis de performance, ça peut y contribuer. Là pour le moment je m'intéresse plus à la fonctionnalité qu'aux performances

    Par contre, pourquoi -1 au lieu de cette valeur retournée par wcslen() ? Qu'est-ce que ça change ou apporte ?

    Alors en fait, c'est peut-être une erreur de ma part car j'ai peut-être mal compris le passage de ce paramètre à la fonction. Je croyais qu'il fallait utiliser CP_ACP pour une conversion de Unicode vers UTF-8 et CP_UTF8 pour une conversion d'UTF-8 vers Unicode. N'ayant pas encore testé la deuxième conversion, je n'ai pas pu observer un quelconque problème.....
    Que faut-il donc passer dans mon cas ? systématiquement la valeur CP_UTF8 ?

    Merci d'avance pour votre aide.

  11. #11
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 382
    Points : 41 593
    Points
    41 593
    Par défaut
    Citation Envoyé par spender Voir le message
    Par contre, pourquoi -1 au lieu de cette valeur retournée par wcslen() ? Qu'est-ce que ça change ou apporte ?
    Ça t'évite d'appeler wcslen() toi-même, et... rien d'autre, je crois.

    Alors en fait, c'est peut-être une erreur de ma part car j'ai peut-être mal compris le passage de ce paramètre à la fonction. Je croyais qu'il fallait utiliser CP_ACP pour une conversion de Unicode vers UTF-8 et CP_UTF8 pour une conversion d'UTF-8 vers Unicode. N'ayant pas encore testé la deuxième conversion, je n'ai pas pu observer un quelconque problème.....
    Que faut-il donc passer dans mon cas ? systématiquement la valeur CP_UTF8 ?
    Tant que tu fais de l'UTF-8, oui.
    CP_ACP fait typiquement une conversion entre Unicode (UTF-16 en fait) et Windows-1252. Du moins, ici, car ça dépend du pays.

  12. #12
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2003
    Messages : 82
    Points : 50
    Points
    50
    Par défaut
    Rebonjour,

    Ça t'évite d'appeler wcslen() toi-même, et... rien d'autre, je crois.
    Lol, bien que l'intérêt soit limité, c'est toujours ça de pris pour éviter d'écrire une connerie

    Tant que tu fais de l'UTF-8, oui.
    Ok, donc j'avais mal compris, je vais donc mettre uniquement CP_UTF8. Merci pour l'explication

    Je vous tiens au courant de la suite.
    On ne sait jamais si ça peut servir à d'autres

  13. #13
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2003
    Messages : 82
    Points : 50
    Points
    50
    Par défaut
    Bonjour,

    Etant dans mes tests de conversions, il s'avère que ça semble pas mal marcher. En revanche, il y a un point que j'aimerai éclaircir, en effet, avec des caractères grecques par exemple, l'affichage sur l'appareil mobile se fait bien par contre, si je passe des caractères un peu plus exotique d'un langue dont je ne connaissais même pas le nom..... ça m'affiche des carrés à la place des caractères
    Alors à première vue, je pencherai vers une plages unicode non supportée par la machine (mobile), qu'en pensez-vous ?
    Pensez-vous qu'il soit possible de détecter soit par programmation ou bien physiquement sur le matériel ce genre de chose ?

    Merci d'avance si vous pouvez m'éclairer.

  14. #14
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Points : 50 369
    Points
    50 369
    Par défaut
    Il y a d'une part le code Unicode à afficher et d'autre part la fonte de caractère utilisée qui possède ou non le (ou la ?) glyphe (la forme quoi!) du caractère à afficher.

    Si tu n'as pas la fonte adéquate, tu affiches effectivement des petits carrés.

  15. #15
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 382
    Points : 41 593
    Points
    41 593
    Par défaut
    La police Microsoft qui contient le plus de glyphes est Arial Unicode MS, mais elle fait 22Mo et je ne suis pas sûr qu'elle soit présente sur ton système...

  16. #16
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2003
    Messages : 82
    Points : 50
    Points
    50
    Par défaut
    Bonjour,

    Merci encore ram-0000 et Médinoc pour vos éclaircissements
    Je vois mieux, la problématique se précise puisqu'en plus je dois être en police à chasse fixe.....
    D'après ce que j'ai pû voir la Arial Unicode MS est très vaste mais ne semble pas fixe.....

    Vous connaissez une police unicode assez étendue (assez universelle) à chasse fixe ?

    Merci d'avance pour vos réponses.

  17. #17
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 382
    Points : 41 593
    Points
    41 593
    Par défaut
    La plus complète police à chasse fixe que je connaisse est Lucida Sans Unicode, mais elle est beaucoup moins complète que Arial Unicode MS...

  18. #18
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2003
    Messages : 82
    Points : 50
    Points
    50
    Par défaut
    Bonjour,

    Oui je pense que la police sera dépendante du pays..... mais bon c'est un autre sujet Merci pour les renseignements sur les polices unicode

    Suite à mes différents tests, je mets donc le code des 2 conversions car la première version posait problème :

    //UTF-8 vers Unicode
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    int length = MultiByteToWideChar(CP_UTF8, 0, m_buf_recept, size_recept, NULL, NULL );
    WCHAR *UnicodeBuffer = NULL;
    UnicodeBuffer = new WCHAR[length+1];
    MultiByteToWideChar(CP_UTF8, 0, m_buf_recept, -1, UnicodeBuffer, length );
    //Unicode vers UTF-8
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    LPWSTR orgUnicode = new WCHAR[strlen(m_send_mess)+1];
    mbstowcs(orgUnicode, m_send_mess, strlen(m_send_mess));
    int UTF8Chars = WideCharToMultiByte(CP_UTF8, 0, orgUnicode, -1, 0, 0, 0, 0);
    LPSTR UTF8Buffer = (LPSTR)alloca(UTF8Chars);
    WideCharToMultiByte(CP_UTF8, 0, orgUnicode, -1, UTF8Buffer, UTF8Chars, 0, 0);
    Bon, pour les puristes, il y a des optimisations possibles mais le principe est là.
    Voilà si ça peut servir à d'autres

    Et merci encore pour votre aide

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Conversions Unicode Ascii
    Par Klaim dans le forum C++
    Réponses: 25
    Dernier message: 01/08/2007, 23h15
  2. conversion iso -> utf
    Par troumad dans le forum C
    Réponses: 6
    Dernier message: 20/04/2007, 17h52
  3. Conversion vers UTF-8
    Par magnus2005 dans le forum Langage
    Réponses: 1
    Dernier message: 26/10/2005, 11h12
  4. Problème de conversion unicode
    Par djmalo dans le forum C
    Réponses: 5
    Dernier message: 09/03/2004, 12h48
  5. conversion Unicode -> ASCII
    Par juzam dans le forum C
    Réponses: 8
    Dernier message: 24/07/2003, 11h07

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo