Konvertierung einer LPWSTR ins ansi char -w2a macro



  • Hallo Zusammen,

    Wenn ich w2a(wide to ansi) macro benutze, um von LPWSTR ins ansi char zu konvertieren, kriege ich einen Access-Violation Fehler(Buffer Overflow?).

    Jedenfalls dieses funktionert nicht

    ...
    USES_CONVERSION ;
    
      // sps_variables[9] ist TYP von OPCITEMDEF 
      // szItemID ist TYP von LPWSTR
       printf("%s\n",W2A(mydc->sps_variables[9].szItemID) ;
    
    ...
    

    Sowie ich von MS strings verstanden habe, ist ein LPWSTR nichts anders als wchar * . Somit soll der Einsatz der W2A macro IMHO erfolgreich durchgefuehrt werden. Im netz gab's passend zu der W2A problematik folgende Beitraege:

    [1] http://www.tech-archive.net/Archive/PocketPC/microsoft.public.pocketpc.developer/2004-11/1403.html
    [2] http://www.codeguru.com/forum/showthread.php?p=1135929

    was mich aber net schlauer gemacht hat. Wie waere der beste Weg aus einem LPWSTR einen ansi c string zu schaffen? Wieso funktioniert denn W2A net?

    Danke im voraus,
    jsbach

    ps: Die A2W macro funktionert problemlos an anderer Stelle meines Programs.



  • Dieses Problem tritt bei allen Fällen auf, in denen eine Funktion eine dynamische Parameterliste verwendet.

    Das einfachste wäre ein wprintf, damit kannst Du Dir die Umwandlung ersparen. Ab ATL 7.0 geht auch

    CW2A pszItemID(mydc->sps_variables[9].szItemID); 
    printf("%s\n", pszItemID);
    

    Funktionieren sollte auch

    printf("%s\n", CString(mydc->sps_variables[9].szItemID));
    

  • Mod

    1. funktioniert nicht und birgt Fehlerquellen.
    http://blog.m-ri.de/index.php/2007/09/12/die-cx2y-falle/
    2. Ist auch unsicher. da ein CString Objekt nicht explizit enem Zeiger gleich kommt. Besser man verwendet hier CString(anything).GetString();

    @jsbach: Wo kommt der Fehler? In printf oder in der Konvertierung? Was sagt der Stack?
    Ist es auch wirklich ein MBCS Programm. IMHO ist W2T sicherer und kompatibler.



  • Martin Richter schrieb:

    1. funktioniert nicht und birgt Fehlerquellen.
    http://blog.m-ri.de/index.php/2007/09/12/die-cx2y-falle/

    Aber nur, wenn man das CW2A direkt in den Funktionsaufruf einbaut und die Argumente der Funktion später in eine va_list konvertiert werden. Beispiel 1. erstellt aber vor dem Funktionsaufruf eine CW2A-Instanz, die bis nach dem Funktionsaufruf gültig bleibt. Mehr dazu hier:

    http://msdn2.microsoft.com/en-us/library/87zae4a3(VS.71).aspx


  • Mod

    Nein! Es geht nicht! Denn pszItemID ist eben ein Objekt und kann vom ... Operator nicht zu einem LPCTSTR dereferiert werden. Es ist und bleibt ein Objekt.

    Und warum sollte es einen Unterschied machen. Innerhalb der printf Funktion ist ein temporäres Objekt erlaubt...
    Der Link, den Du angegeben hast zeigt nur Funktionen die einen char* oder wchar_t* annehmen. Hier greift die implizite Umwandlung (Umwandlungsoperator)! Nicht jedoch bei ...!



  • sri schrieb:

    Das einfachste wäre ein wprintf, damit kannst Du Dir die Umwandlung ersparen.

    es klappt mit wprintf. Ich muss mich allerdings an der "L" und anderen Makros gewoehnen..

    wprintf(L"%s\n", mydc->sps_variables[9].szItemID) ;
    

    sri schrieb:

    Ab ATL 7.0 geht auch
    uer unicode (wide) pointers

    CW2A pszItemID(mydc->sps_variables[9].szItemID); 
    printf("%s\n", pszItemID);
    

    funktioniert auch.

    sri schrieb:

    Funktionieren sollte auch

    printf("%s\n", CString(mydc->sps_variables[9].szItemID));
    

    dies funktioniert leider net. Denn s-flag wird ja fuer ansi chars angewendet. Laut http://msdn2.microsoft.com/en-us/library/wc7014hz(VS.71).aspx soll fuer unicode [wide] ptrs entweder "%ls" oder "%S" verwendet werden. nun eine

    printf("%S\n",CString(mydc->sps_variables[9].szItemID).GetString()) ;
    

    hat keinen sinnvolen Zeichenfolge in meine Console ausgegeben.. merkwuerdig..

    Greetz,
    jsbach


  • Mod

    Was ist das bitte denn für ein Programm? MBCS oder Unicode?

    Das sollte Dir klar sein bevor Du mit Konvertierungen herum bastelst.



  • Hallo Martin,
    sorry fuer die verspaetete Antwort.

    Martin Richter schrieb:

    Was ist das bitte denn für ein Programm? MBCS oder Unicode?

    Die Project Properties besagt, dass Multibyte Character Set dabei angewendet wird.

    Eine andere Loesung, die ich gerade erfolgreich ausprobiert habe, ist:

    USES_CONVERSION ;
    	LPSTR ptr_casted = W2A(mydc->sps_variables[7].szItemID) ;
    
    	printf("%s\n", (char *) ptr_casted) ;
    

    Wobei muss ich sagen, dass es insgesamt keine gute Idee ist, eine Unicode String ins ansi character array umzuwandeln.

    Gruss,
    jsbach


  • Mod

    Du brauchst bei der letzten Lösung keinen cast!

    printf("%s\n", W2A(mydc->sps_variables[7].szItemID)) ;
    

    langt.



  • Martin Richter schrieb:

    Nein! Es geht nicht! Denn pszItemID ist eben ein Objekt und kann vom ... Operator nicht zu einem LPCTSTR dereferiert werden. Es ist und bleibt ein Objekt.

    Also bei mir funktioniert es hervorragend.

    Martin Richter schrieb:

    Und warum sollte es einen Unterschied machen. Innerhalb der printf Funktion ist ein temporäres Objekt erlaubt...

    Ich habe mit anderen Funktionen, die einen ... Operator anbieten, die Erfahrung gemacht, dass temporäre CW2A-Objekte hier Probleme bereiten. Eine vorherige explizite Instantiierung hat dabei immer geholfen.


  • Mod

    Ihr habt nicht gelesen, was ich geschrieben habe. Und ich habe mir nicht die Mühe gemacht es genau zu erklären. Sorry!

    OK! Die Konvertierung selbst funktioniert. Es spielt keine Rolle, ob man hier eine eigene Instanz baut oder ein temporäres Objekt nimmt.

    Aber! Das Objekt, dass gepusht wird, ist größer als ein PTR. Sollten nach dem printf weitere Argumente folgen, wie in meinem Blog erklärt, dann kann die Daten nicht korrekt ausgeben.

    Wenn überhaupt muss ein cast erfolgen!

    Das Problem ist eben, dass bei der Verwendung von ... exakt gesagt werden muss, was gepusht wird.

    Sollte sich z.B. die Implementierung ändern, weil z.B. die maximale Puffergröße zuerst im Objekt gespiechert wird und kein Zeiger, dann muss dieser Code fehlgehen.
    Dieser Code kann nur dann funktionieren, wenn:
    1. Der Zeiger auf den String als erstes im Objekt steht.
    2. (Für nachfolgende Elemente) Das Objekt exakt so groß ist wie ein Zeiger.


Anmelden zum Antworten