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

C++ Discussion :

Reconnaitre le type d'encodage d'une chaine de caractere


Sujet :

C++

  1. #1
    tsp
    tsp est déconnecté
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 82
    Points : 54
    Points
    54
    Par défaut Reconnaitre le type d'encodage d'une chaine de caractere
    Bonjour,
    j'aimerais savoir s'il y a un moyen simple de reconnaitre le type d'encodage d'une chaine de caractere. Je m'explique, j'ai fais une DLL C++ avec une fonction qui reçoit une chaine de caractere :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void __stdcall TestReception(LPWSTR Texte);
    seulement voila, certains programmes encodent leurs chaines de caracteres en UNICODE (PowerBuilder 10) et d'autre en ANSI (PowerBuilder 9), donc ma fonction ne marche pas partout. J'aimerais donc pouvoir reconnaitre le type d'encodage de ma chaine de caractere pour que le type de mon Texte corresponde.

    Sinon quelle demarche je devrais entreprendre ?

    Merci

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Généralement, pour les DLL, on utilise la même pratique que Windows:
    Fonction déclarée en extern "C", avec deux versions:
    TestReceptionA pour ansi
    TestReceptionW pour unicode

    Et le #define qui va avec, dans le header:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #ifdef __cplusplus
    extern "C" {
    #endif
    void __stdcall TestReception(LPTSTR Texte);
    void __stdcall TestReceptionA(LPSTR Texte);
    void __stdcall TestReceptionW(LPWSTR Texte);
    #ifdef __cplusplus
    }
    #endif
     
    #ifdef UNICODE
    #define TestReception TestReceptionW
    #else
    #define TestReception TestReceptionA
    #endif
    Ainsi, la fonction elle-même ne fait pas la différence, mais l'appelant peut appeler deux fonctions séparées.

    Ensuite, si ta fonction n'a besoin que d'un seul code source, tu peux faire comme ceci (ça peut paraitre sale, mais ça marche):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    // Fonction.cpp
    #include <windows.h>
     
    extern "C" void __stdcall TestReception(LPTSTR Texte)
    {
    //Faire quelque chose sur le texte avec les fonctions utilisant des TCHAR
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    // FonctionU.cpp
    #define UNICODE
    #define _UNICODE
     
    //Compile les fonctions en version unicode
    #include "Fonction.cpp"




    Par contre, si tu veux une fonction qui doit reconnaitre d'elle-même l'encodage à partir d'un pointeur indéterminé, essaie peut-être la fonction IsTextUnicode()...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    tsp
    tsp est déconnecté
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 82
    Points : 54
    Points
    54
    Par défaut
    Je n'arrive pas à mettre en place ta premiere méthode, j'aurai 2-3 questions. Dans mon header, quelle fonction faut-il exporter ? les 3 ? ou juste la générale ? Pour l'instant j'ai fait comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #ifdef __cplusplus
    extern "C" {
    #endif
    EXPORT void __stdcall TestReception(LPTSTR Texte);
    void __stdcall TestReceptionA(LPSTR Texte);
    void __stdcall TestReceptionW(LPWSTR Texte);
    #ifdef __cplusplus
    }
    #endif
     
    #ifdef UNICODE
    #define TestReception TestReceptionW
    #else
    #define TestReception TestReceptionA
    #endif
    Ensuite dans le .cpp, il ne faut bien implementer que les 2 fonctions TestReceptionA(LPSTR Texte) et TestReceptionW(LPWSTR Texte) ou alors les 3 ? Mon cpp ressemble à ça :

    Code : 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
    void TestReceptionW(LPWSTR Texte)
    {
    	USES_CONVERSION;
     
    	ecrit_fichier("Entrée dans TestReceptionW");
     
    	AfxMessageBox(W2CA(Texte));
     
    	ecrit_fichier(to_string(Texte));
    }
     
    void TestReceptionA(LPSTR Texte)
    {
    	ecrit_fichier("Entrée dans TestReceptionA");
     
    	ecrit_fichier(to_string(Texte));
    }
    et lorsque je compile le tout j'obtiens ces 2 erreurs :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    error C2373: 'TestReceptionW' : redefinition; different type modifiers
    error C2373: 'TestReceptionA' : redefinition; different type modifiers
    Et pour finir, si j'exporte la fonction generale TestReception, c'est elle que j'appelle depuis l'extérieur et c'est la DLL qui m'envoit vers la bonne fonction en fonction du type de l'encodage ?

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Alors, je vais répondre à tes questions dans l'ordre:
    1°) Il faut exporter les deux (A et W).
    La déclaration de la fonction générale ne sert à rien pour le compilateur, en fait (mais elle peut servir à ton EDI, c'est pour cela que je l'avais mise). La fonction générale n'a pas d'implémentation (en tout cas, elle n'en a pas une fois le code compilé).

    2°) Comme je te l'ai dis, deux possibilités:
    • Soit tu implémentes les deux (A et W) séparément (dans ce cas, tu n'as besoin que d'un seul fichier source),
    • Soit tu "implémentes" la fonction générale (en fait, c'est comme si tu faisais seulement semblant de l'implémenter) en utilisant des TCHAR, et grâce aux #define et au second fichier source (mon "FonctionU.cpp"), elle sera compilée deux fois: Une fois en A, l'autre en W
    Généralement, on choisit entre ces deux solutions selon le degré de différence entre les deux versions. Des fois il est plus simple de faire avec une seule, des fois il est mieux de faire les deux séparément.

    3°) Puisque tu dois exporter les deux, le programme extérieur doit appeler lui-même la bonne fonction.
    • S'il est écrit avec des TCHARs, il pourra utiliser la "fonction" générale: Grâce aux #define, l'appel sera transformé en un appel de la bonne fonction (si pas compilé avec UNICODE, il appellera explicitement TestReceptionA, si compilé avec UNICODE, il appellera explicitement TestReceptionW).
    • S'il est écrit avec des chars et des WCHARs, il faudra appeler explicitement l'une des deux fonctions dans le fichier source: Pour traiter une LPWSTR, appeler TestReceptionW, etc.

    PS: Pense à rajouter des gardes d'inclusion dans ton header: Il ne faut pas qu'il soit passé deux fois, car à ce moment-là, la fonction "générale" se retrouvera avec une double déclaration, ce qui peut (peut-être) être la cause de ton erreur.
    PS2: La cause de ton erreur, ce doit être que tu as oublié les __stdcall dans l'implémentation. Ces modifieurs (ainsi que ceux pour l'exportation) doivent figurer dans la déclaration et la définition.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    tsp
    tsp est déconnecté
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 82
    Points : 54
    Points
    54
    Par défaut
    très juste pour les erreurs. Erreurs stupides d'inattention. Pour le reste j'essaye ...

  6. #6
    tsp
    tsp est déconnecté
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 82
    Points : 54
    Points
    54
    Par défaut
    Bon alors j'ai réussi à faire ce que je cherchais a faire avec la fonction IsTextUnicode(), c'est à dire tester dans ma fonction si le texte entré en parametre est du texte unicode ou non et ensuite le traiter dans les 2 cas. Je met ma fonction pour ceux que ça interesse (du moins la méthode) :

    Code : 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
     
    Dans le .cpp :
     
    // entrée en parametre le texte et la taille du texte
    void __stdcall TestReception(LPTSTR Texte, int taille)
    {
    	USES_CONVERSION;
     
    	if (IsTextUnicode(Texte,taille,(LPINT) NULL))
    	{
    		// le texte est du texte UNICODE
    		LPWSTR CopieTexte = (LPWSTR) Texte;
    		...
                    // ensuite on peux traiter le texte CopieTexte comme une chaine de caractere UNICODE
    	}
    	else
    	{
    		// le texte n'est pas du texte UNICODE
    		LPSTR CopieTexte =  (LPSTR) Texte;
    		...
                    // ensuite on peux traiter le texte CopieTexte comme une chaine de caractere NON UNICODE
    	}
    }
     
    Dans le .h :
     
    void __stdcall TestReception(LPTSTR Texte, int Taille);
    Par contre pour la méthode avec les macros (que je n'ai finalement pas mise en place car elle ne semblait pas correspondre à mes attentes) j'aurai 1 question :

    tu as dis
    S'il est écrit avec des TCHARs, il pourra utiliser la "fonction" générale: Grâce aux #define, l'appel sera transformé en un appel de la bonne fonction (si pas compilé avec UNICODE, il appellera explicitement TestReceptionA, si compilé avec UNICODE, il appellera explicitement TestReceptionW).
    Dans ce cas ci, c'est par rapport à l'OS que la fonction sera compilé avec UNICODE ou pas ? Ou c'est la personne qui compile qui le décide ? Dans ce cas si c'est compilé avec UNICODE, si la fonction reçoit du texte non UNICODE elle ne marchera pas ? Si on me comprend et si j'ai bien compris, cette méthode ne sert pas à faire ce que je voulais...

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Salut,
    1°) Si tu utilises IsTextUnicode, n'utilise pas un LPTSTR/LPCTSTR comme paramètre, mais un LPVOID: Le LPTSTR n'est pas un pointeur magique qui sait si le texte est d'un type ou non.
    Le LPTSTR, c'est toujours un LPSTR si le programme n'est pas compilé avec UNICODE, ou toujours un LPWSTR si le programme est compilé en UNICODE.

    2°) Celui qui décide, c'est l'utilisateur qui compile: sur un vieux compilateur, ça peut se décider en rajoutant des #define UNICODE et #define _UNICODE (il faut les deux, suite à une couille dans les en-têtes) au début de chaque source, ou tout simplement en ligne de commande (-D UNICODE et -D _UNICODE pour gcc). Sur Visual 2005, il y a une option pour cela dans les propriétés du projet.

    Ainsi, si tu compiles avec UNICODE, tu auras ces définitions:
    Code : 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
    //Dans les headers Windows
    typedef WCHAR TCHAR, _TCHAR, *LPTSTR;
    typedef const WCHAR *LPCTSTR;
    #define TEXT(s) L##s
     
    #define CreateWindow CreateWindowW
    #define MessageBox MessageBoxW
    //etc.
     
    //-----------------------
    //Dans le header:
    void __stdcall TestReception(LPTSTR Texte);//Ici, LPTSTR équivaut à LPWSTR
    void __stdcall TestReceptionA(LPSTR Texte);
    void __stdcall TestReceptionW(LPWSTR Texte);
     
    #define TestReception TestReceptionW
    Ainsi, si dans le programme appelant, tu avais mis un:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    TCHAR texte[10] = TEXT("blabla");
    TestReception(texte)
    Une fois le programme appelant compilé en unicode, il correspondra à:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    WCHAR texte[10] = L"blabla";
    TestReceptionW(texte)
    Donc le programme appellera TestReceptionW.


    Ici, la fonction à appeler (A ou W) est choisie statiquement à la compilation. C'est ainsi que sont faits la plupart des programmes Windows, parce que les headers Windows sont fait exactment comme le header que j'ai montré.
    Tandis que ta fonction utilisant un LPVOID (oui, j'ai dit un LPVOID) et IsTextUnicode choisira son traitement dynamiquement à l'exécution.
    Ici, tu as donc vraiment implémenté (sans faire semblant) une fonction générique qui choisit dynamiquement le traitement à effectuer.
    Il faut savoir que ça prend du temps de calcul et que c'est rarement utile. Généralement, le choix statique suffit.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    tsp
    tsp est déconnecté
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 82
    Points : 54
    Points
    54
    Par défaut
    Effectivement LPVOID ça semble plus logique, et marche tout aussi bien (surement mieux meme lol). Je savais ce qu'etait le LPTSTR mais ça marchait alors jme suis di allons bon.

    Bon sinon pour la méthode statique, je pense avoir bien compris maintenant. Et ça confirme ce que je pensais à savoir qu'en faisant la méthode statique, c'est repousser le problème au programme appelant la fonction. Parce que si on fait 2 fonctions, une W pour l'unicode et une A pour l'ansi, je devrais savoir qu'elle est le type d'encodage de mon texte dans mon programme appelant pour appeler la bonne fonction. Et en fait la finalité de ma fonction C++ et qu'elle sera dans une DLL et susceptible d'etre appelée par différents programmes. Certains encodant leur texte en UNICODE (comme PowerBuilder 10 par exemple) et d'autre en ANSI (comme PowerBuilder 9 par exemple). Donc le faite de trouver dynamiquement le type d'encodage du texte me semble le plus judicieux, au détriment de la rapidité que je ne pense pas beaucoup amoindri.

    Merci pour ton aide précieuse.

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Ben, la logique généralement utilisée est la logique inverse: Comme le programme appelant, lui, sait comment il est codé (ansi ou unicode), c'est à lui de savoir quelle fonction appeler, sans que la DLL ait à s'emm***er à deviner (surtout qu'elle peut se tromper: la doc dit bien que IsTextUnicode() n'est pas fiable à 100%; C'est vraiment de deviner que je parle).
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  10. #10
    tsp
    tsp est déconnecté
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 82
    Points : 54
    Points
    54
    Par défaut
    c'est vrai, bon ben je vais voir par la suite. thanks

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

Discussions similaires

  1. tester le type de contenu d'une chaine
    Par thechris33 dans le forum VB.NET
    Réponses: 7
    Dernier message: 11/06/2008, 22h11
  2. reconnaitre une chaine de caracteres
    Par inh40 dans le forum C++
    Réponses: 4
    Dernier message: 10/04/2007, 11h21
  3. [VBA-Excel] reconnaitre une chaine de caractere
    Par DonKnacki dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 13/06/2006, 16h15
  4. Réponses: 3
    Dernier message: 01/08/2005, 12h15
  5. [Débutant]Encodage d'une chaine de caractères
    Par Crazyblinkgirl dans le forum Entrée/Sortie
    Réponses: 3
    Dernier message: 03/08/2004, 16h47

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