Verbesserung der Umwandlung eines ANSI- in einen Wide-String gesucht



  • sri schrieb:

    Ja, die einzelnen Ansi-Strings werden vorher in Unicode-Strings umgewandelt und nach dem Aufruf der Unicode-Version wird der Speicher wieder freigegeben.

    Gibt's irgendwo mal die Implementierung davon zu sehen? Bei Wine sollte das doch möglich sein, oder?

    sri schrieb:

    Hast Du Dir schon einmal die Konvertierungsklassen der ATL (CW2A, CA2W) angeschaut?

    Ja, hab ich gestern gesehen. Aber ich hab sie wieder verworfen, weil es sie nur für Visual C++ gibt und MinGW sie beispielsweise sie nicht kennt.


  • Mod

    Du hast den Source Code der ATL. Es dauert 5 Minuten aus den ATL Klassen und Templates eine eigene Konvertierung zu schreiben.
    Zumal die Implementierung sehr nett ist, effektiv, simpel und absolut verständlich für Jedermann.



  • NES-Spieler schrieb:

    Gibt's irgendwo mal die Implementierung davon zu sehen? Bei Wine sollte das doch möglich sein, oder?

    Ja. MessageBoxA ist in dlls\user32\msgbox.c implementiert.



  • Ich hab mir die ATL-Sachen mal angeguckt, aber soweit ich gesehen habe, brauchen die auch alle einen bereits initialisierten String. Ein Zeiger, der noch auf NULL zeigt, funktioniert da nicht.

    Dann nochmal zum Vorschlag, ich solle mit den C++-Strings arbeiten. Das funktioniert auch nicht, was folgende Funktion verdeutlicht:

    #include <iostream>
    #include <windows.h>
    
    using namespace std;
    
    string Funktion()
    {
    	string str = "Hallo";
    
    	return str;
    }
    
    int main()
    {
    	LPCSTR winAPIString = Funktion().c_str();
    
    	cout << "Dieser Text lautet auf keine Fall 'Hallo':\n"
    	     << winAPIString << '\n';
    }
    

    Denn die c_str()-Funktion liefert ja nur die Adresse des intern gespeicherten Character-Arrays, welche aber schon nicht mehr gültig ist, wenn die Funktion verlassen wird. Das heißt, wenn ich einen ANSI-String habe und will diesen auf WNDCLASSEXW::lpszClassName kopieren, dann könnte ich gar nicht mit einer Konvertierungsfunktion arbeiten, die std::string und std::wstring erwartet.

    Ich weiß also noch immer nicht, wie ich weiter vorgehen soll. Der Vollständigkeit halber werde ich mal zeigen, worum es eigentlich geht: Ich habe ein paar Funktionen, die mir das Erstellen von Fenstern vereinfachen sollen. Jede Funktion, die Strings entgegennimmt, existiert in zwei Ausführungen: Einmal für ANSI-, einmal für Unicode-Strings. Die ANSI-Funktion wandelt den String um und ruft die Unicode-Funktion auf, welche dann die eigentlichen Aufgaben erledigt. Soweit wäre das kein großes Problem, da ich in diesem Fall ja in der ANSI-Funktion einen String auf dem Heap erstellen könnte, den ich wieder lösche, bevor die Funktion verlassen wird. Das Problem liegt vielmehr innerhalb der eigentlichen Unicode-Funktion: Denn für den Fall, daß auf dem Betriebssystem Unicode nicht unterstützt wird, muß der String dort nochmal in einen ANSI-String zurückverwandelt werden:

    HWND Create(/* ... */ LPCWSTR className /* ... */)
    {
    	WNDCLASSEXW wndClassW;
    	WNDCLASSEXA wndClassA;
    
    	// ...
    	wndClassW.lpszClassName = className;
    	// ...
    
    	if (UnicodeIsSupported()) // Eigene Funktion
    		RegisterClassExW(&wndClassW);
    	else
    	{
    		// Wenn Unicode nicht unterstützt wird (Windows 95/98/Me),
    		// dann werden alle wndClassW-Werte nochmal auf wndClassA
    		// kopiert und die Klasse wird entsprechend anders
    		// initialisiert.
    
    		// ...
    		wndClassA.lpszClassName =
    			ConvertToANSIString(wndClassW.lpszClassName); //Eigene Funktion
    		// ...
    
    		RegisterClassExA(&wndClassA);
    	}
    
    	if (UnicodeIsSupported())
    		return CreateWindowExW(/* ... */ wndClassW.lpszClassName /* ... */);
    	else
    		return CreateWindowExA(/* ... */ wndClassA.lpszClassName /* ... */);
    }
    

    Wie kann ich hier die Strings aus der WNDCLASSEXW-Struktur umwandeln? Kann ich sie mit new initialisieren, dann meine ursprüngliche Umwandlungsfunktion (aus meinem ersten Post) nehmen und sie nach dem CreateWindowEx-Aufruf wieder löschen oder werden die Strings innerhalb des WinAPI-Frameworks weiter gebraucht? Wie muß man solche Probleme wie hier geschildert handhaben?


  • Mod

    NES-Spieler schrieb:

    Ich hab mir die ATL-Sachen mal angeguckt, aber soweit ich gesehen habe, brauchen die auch alle einen bereits initialisierten String. Ein Zeiger, der noch auf NULL zeigt, funktioniert da nicht.

    Was hast Du Dir bitte angesehen?
    Die CA2W Funktion und andere Funktionieren perfekt auch mit NULL Zeigern!
    Ebenso A2W!

    Dann nochmal zum Vorschlag, ich solle mit den C++-Strings arbeiten. Das funktioniert auch nicht, was folgende Funktion verdeutlicht:

    #include <iostream>
    #include <windows.h>
    
    using namespace std;
    
    string Funktion()
    {
    	string str = "Hallo";
    
    	return str;
    }
    
    int main()
    {
    	LPCSTR winAPIString = Funktion().c_str();
    
    	cout << "Dieser Text lautet auf keine Fall 'Hallo':\n"
    	     << winAPIString << '\n';
    }
    

    Denn die c_str()-Funktion liefert ja nur die Adresse des intern gespeicherten Character-Arrays, welche aber schon nicht mehr gültig ist, wenn die Funktion verlassen wird.

    Logisch! Das temporäere Objekt ist nur gültig solange eben das Statement gilt.
    Man kann so nicht mit Zeigern arbeiten. Die könntest Du einfach nicht automatisch entsorgen.
    Du musst also das Objekt (std::string) zwischenspeichern. Und schon geht es.

    Das heißt, wenn ich einen ANSI-String habe und will diesen auf WNDCLASSEXW::lpszClassName kopieren, dann könnte ich gar nicht mit einer Konvertierungsfunktion arbeiten, die std::string und std::wstring erwartet.

    Korrekt! Ohne das Du das Objekt auch zwischenspeicherst geht hier gar nichts!
    Dafür gibt es aber auck eine andree Lösung. Denn wie willst Du das Objekt auch dterminsitisch wieder entsorgen.

    Du könntest eine Kontextklasse einrichten wie es mit den alten ATL Klassen und USES-CONVERSION geschieht und diese Klasse auf dem Stack einrichten. In dessen Kontext werden die temnporären Strings gespeichert und entsorgt wenn der Kontext aus dem Skope geht.

    Schau Dr mal die alten ATL Konvertierungen an, die verwenden alloca!
    Die erzeugen eine Persitenz auf dem Stack!

    Ich weiß also noch immer nicht, wie ich weiter vorgehen soll. Der Vollständigkeit halber werde ich mal zeigen, worum es eigentlich geht: Ich habe ein paar Funktionen, die mir das Erstellen von Fenstern vereinfachen sollen. Jede Funktion, die Strings entgegennimmt, existiert in zwei Ausführungen: Einmal für ANSI-, einmal für Unicode-Strings. Die ANSI-Funktion wandelt den String um und ruft die Unicode-Funktion auf, welche dann die eigentlichen Aufgaben erledigt. Soweit wäre das kein großes Problem, da ich in diesem Fall ja in der ANSI-Funktion einen String auf dem Heap erstellen könnte, den ich wieder lösche, bevor die Funktion verlassen wird. Das Problem liegt vielmehr innerhalb der eigentlichen Unicode-Funktion: Denn für den Fall, daß auf dem Betriebssystem Unicode nicht unterstützt wird, muß der String dort nochmal in einen ANSI-String zurückverwandelt werden:

    HWND Create(/* ... */ LPCWSTR className /* ... */)
    {
    	WNDCLASSEXW wndClassW;
    	WNDCLASSEXA wndClassA;
    
    	// ...
    	wndClassW.lpszClassName = className;
    	// ...
    
    	if (UnicodeIsSupported()) // Eigene Funktion
    		RegisterClassExW(&wndClassW);
    	else
    	{
    		// Wenn Unicode nicht unterstützt wird (Windows 95/98/Me),
    		// dann werden alle wndClassW-Werte nochmal auf wndClassA
    		// kopiert und die Klasse wird entsprechend anders
    		// initialisiert.
    
    		// ...
    		wndClassA.lpszClassName =
    			ConvertToANSIString(wndClassW.lpszClassName); //Eigene Funktion
    		// ...
    
    		RegisterClassExA(&wndClassA);
    	}
    
    	if (UnicodeIsSupported())
    		return CreateWindowExW(/* ... */ wndClassW.lpszClassName /* ... */);
    	else
    		return CreateWindowExA(/* ... */ wndClassA.lpszClassName /* ... */);
    }
    

    Wie kann ich hier die Strings aus der WNDCLASSEXW-Struktur umwandeln? Kann ich sie mit new initialisieren, dann meine ursprüngliche Umwandlungsfunktion (aus meinem ersten Post) nehmen und sie nach dem CreateWindowEx-Aufruf wieder löschen oder werden die Strings innerhalb des WinAPI-Frameworks weiter gebraucht? Wie muß man solche Probleme wie hier geschildert handhaben?

    Die alten ATL Makros machen genau das!

    #include <iostream>
    #include <windows.h>
    #include <atlbase.h>
    
    using namespace std;
    
    string Funktion()
    {
    	string str = "Hallo";
    
    	return str;
    }
    
    int main()
    {
             USES_CONVERSION;
    	LPCWSTR winAPIString = A2W(Funktion().c_str());
    
    	cout << "Dieser Text lautet auf keine Fall 'Hallo':\n"
    	     << winAPIString << '\n';
    }
    

    Das geht! 🕶



  • Martin Richter schrieb:

    Was hast Du Dir bitte angesehen?
    Die CA2W Funktion und andere Funktionieren perfekt auch mit NULL Zeigern!
    Ebenso A2W!

    Dieses ATLASSERT(lpw != NULL) in AtlW2AHelper hat mich zu dem Gedanken gebracht. Außerdem hab ich USES_CONVERSION nicht beachtet. Aber egal. Es funktioniert jetzt erstmal.

    Ich hab nur noch eine Frage: Da das ATL-Zeug nur bei Visual C++ existiert und ich die Makros und Funktionen somit direkt in meinen Quellcode kopieren muß, müßte ich noch wissen: Ist sichergestellt, daß alloca bei jedem Compiler dabei ist? Denn soweit ich das sehe, ist "malloc.h" kein Standardheader.


  • Mod

    NES-Spieler schrieb:

    Martin Richter schrieb:

    Was hast Du Dir bitte angesehen?
    Die CA2W Funktion und andere Funktionieren perfekt auch mit NULL Zeigern!
    Ebenso A2W!

    Dieses ATLASSERT(lpw != NULL) in AtlW2AHelper hat mich zu dem Gedanken gebracht. Außerdem hab ich USES_CONVERSION nicht beachtet. Aber egal. Es funktioniert jetzt erstmal.

    Wenn Du es Dir so wichtig, ist einegute Funktion zu finden würde ich Dir raten, die Code-Empfehlungen besser anzusehen. Die ältere ATL-Makros haben drekt einen Test, der den Umgang mit dem NULL Pointer regelt.
    Das hätte sofort auffallen müssen:

    #define A2W(lpa) (\
    	((_lpa = lpa) == NULL) ? NULL : (\
    		_convert = (lstrlenA(_lpa)+1),\
    		(INT_MAX/2<_convert)? NULL :  \
    		ATLA2WHELPER((LPWSTR) alloca(_convert*sizeof(WCHAR)), _lpa, _convert, _acp)))
    

    Ich hab nur noch eine Frage: Da das ATL-Zeug nur bei Visual C++ existiert und ich die Makros und Funktionen somit direkt in meinen Quellcode kopieren muß, müßte ich noch wissen: Ist sichergestellt, daß alloca bei jedem Compiler dabei ist? Denn soweit ich das sehe, ist "malloc.h" kein Standardheader.

    Kann ich Dir so nicht sagen. Frage bitte nach einem spezifischen Compiler.
    Allerdings hat jeder C Compiler mit der entsprchenden CRT, die ich kenne und auch schon verwendet habe eine entsprechende Funktion wie alloca (GNU, Intel)



  • Da wär ich mal wieder. 😃

    Ich habe die Makros jetzt mal in eine Funktion gepackt. (Immerhin sollen sie später in mein Programm kommen und da will ich auch mit Funktionen und nicht mit ätzenden Makros arbeiten. Und so kann man schonmal gucken, ob es überhaupt geht.) Das Problem ist jetzt aber: Solange sich der String in der Konvertierungsfunktion befindet, funktioniert er. Aber außerhalb ist er dann wieder ungültig. Und das, obwohl ich die LPCSTR-Variable per Referenz übergeben habe:

    #include <windows.h>
    #include <atlbase.h>
    
    void Convert(LPCSTR &a, // Übergabe des umzuwandelnden
                            // Strings per Referenz!
                 LPCWSTR w)
    {
    	USES_CONVERSION;
    
    	a = W2A(w);
    	// Hier ist noch alles in Ordnung:
    	// Adresse von a: 0x0065fcbc
    	// Wert    von a: "Ich bin ein String"
    
    	MessageBoxA(NULL, a, "Convert", MB_OK);
    	// Korrekte Ausgabe
    }
    
    int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
    {
    	LPCSTR str = NULL;
    
    	Convert(str, L"Ich bin ein String.");
    	// Korrekte Adresse, aber der String ist leer:
    	// Adresse von str: 0x0065fcbc
    	// Wert    von str: ""
    
    	MessageBoxA(NULL, str, "Main", MB_OK);
    	//Leere Message-Box
    }
    

    Sollte der mit alloca generierte Speicherplatz nicht solange gültig sein wie auch die Variable gültig ist? Warum also ist zwar die Adresse von str aus WinMain noch immer die gleiche wie die von a aus Convert, während aber alle Zeichen auf 0 gesetzt sind?


  • Mod

    <kopfschüttel>
    Das ist doch kein Auto-Pointer System!
    Die konvertierten Strings werden auf dem Stack abgelegt! Deine Funktion kann so nicht funktionieren. Sie funktionieren so lange wie der aktuelle Stack-Frame nicht verlassen wird.

    Das was Du hier willst bedeutet den konsequenten Einsatz von std::string oder CString und bei Bedarf eben die Konvertierungen an dieser Stelle. Die konvertierten Strings dürfen nur in dem Funktionsblock verwendet werden in dem sie definiert wurden. RÜckgabeist so unmöglich, genauso wie das persistente Speichern in anderen Strukturen.



  • Martin Richter schrieb:

    <kopfschüttel>
    Das ist doch kein Auto-Pointer System!
    Die konvertierten Strings werden auf dem Stack abgelegt! Deine Funktion kann so nicht funktionieren. Sie funktionieren so lange wie der aktuelle Stack-Frame nicht verlassen wird.

    Aber ich habe die Variable doch per Referenz übergeben. Das heißt, der Stack-Rahmen dafür endet erst am Ende der Main-Funktion.

    Martin Richter schrieb:

    Das was Du hier willst bedeutet den konsequenten Einsatz von std::string oder CString und bei Bedarf eben die Konvertierungen an dieser Stelle. Die konvertierten Strings dürfen nur in dem Funktionsblock verwendet werden in dem sie definiert wurden. RÜckgabeist so unmöglich, genauso wie das persistente Speichern in anderen Strukturen.

    Deshalb hab ich den String ja auch nicht zurückgegeben, sondern per Referenz übergeben.


  • Mod

    NES-Spieler schrieb:

    Martin Richter schrieb:

    <kopfschüttel>
    Das ist doch kein Auto-Pointer System!
    Die konvertierten Strings werden auf dem Stack abgelegt! Deine Funktion kann so nicht funktionieren. Sie funktionieren so lange wie der aktuelle Stack-Frame nicht verlassen wird.

    Aber ich habe die Variable doch per Referenz übergeben. Das heißt, der Stack-Rahmen dafür endet erst am Ende der Main-Funktion.

    Aber der Strin Array selbst liegt doch im Stackrahmen der Funktion!
    Es gibt keine eferenz-Zählung für einfache Pointer! Punkt!

    Genauso falsch ist das hier und kommt Deinem Code sehr nahe:

    char *MyString()
    {
    char szTest[20];
    strcpy(szTest,"TEST");
    return szTest;
    }
    

    Martin Richter schrieb:

    Das was Du hier willst bedeutet den konsequenten Einsatz von std::string oder CString und bei Bedarf eben die Konvertierungen an dieser Stelle. Die konvertierten Strings dürfen nur in dem Funktionsblock verwendet werden in dem sie definiert wurden. RÜckgabeist so unmöglich, genauso wie das persistente Speichern in anderen Strukturen.

    Deshalb hab ich den String ja auch nicht zurückgegeben, sondern per Referenz übergeben.

    Kennst Du den Unterschied zwischen einer Referenz und einem Zeiger und vor allem einer Referenz auf einen Zeiger?
    Wenn nicht beschäftige dich mal damit und versuche vor allem mal raus zu bekommen welchen Einfluss eine Referenz auf den Storage hat auf den sie verweist... 🕶

    Antwort (hier vorab): Keinen!



  • Martin Richter schrieb:

    NES-Spieler schrieb:

    Aber ich habe die Variable doch per Referenz übergeben. Das heißt, der Stack-Rahmen dafür endet erst am Ende der Main-Funktion.

    Aber der Strin Array selbst liegt doch im Stackrahmen der Funktion!
    Es gibt keine eferenz-Zählung für einfache Pointer! Punkt!

    Ich weiß, daß es keine Referenzzählung gibt. (Hätte ich das geglaubt, dann hätte ich die Funktion ja einfach so geschrieben, daß der umgewandelte String per return zurückgegeben wird und nicht, daß ich den umzuwandelnden String per Referenz übergebe.) Ich hatte gedacht, daß der Speicherplatz auf dem Stack dann der ursprünglich deklarierten Variable, die per referenz übergeben wurde, zugewiesen wird, aber ich sehe jetzt, was Du meinst.

    Gibt es nun überhaupt eine Möglichkeit, einen String in einen Unicode-String umzuwandeln, ohne
    a) ohne den String dynamisch auf dem Heap zu erstellen (was ja eine manuelle Löschung mit delete erfordern würde)
    b) ohne die Benutzung von Makros
    c) ohne den Konvertierungscode an der entsprechenden Stelle immer wieder neu zu schreiben
    d) ohne die Verwendung von C++-Strings (denn wenn ich einen String aus einer WNDCLASSEXA-Struktur in einen String aus einer WNDCLASSEXW-Struktur umwandeln will, nützt mir das nichts)?



  • Ich glaube NES-Spieler kennt den Unterschied zwischen einem Zeiger und einem String bzw. Array nicht.



  • Ironischerweise gibt es da in C nichtmal wirklich einen durch die Quellcodesyntax gesicherten Unterschied:

    int main()
    {
    	char c = 'A';
    
    	char *p = &c; // p ist ein char-Pointer.
    	p = "Hallo";  // Nein, Moment! p ist ein String.
    	p[3] = 'X';   // Oder doch ein char-Array?
    }
    

    😉


  • Mod

    Mein angebotenes Verfahren funktioniert solange Du eben nicht so einen Quatsch machst und Zeiger und Referenzen bedienst.



  • Martin Richter schrieb:

    Mein angebotenes Verfahren funktioniert solange Du eben nicht so einen Quatsch machst und Zeiger und Referenzen bedienst.

    O.k., gut. Dann sag mir doch bitte noch, wie die Konvertierungsfunktion letztendlich genau aussehen muß. Wenn ich es so mache, wie Du vorgeschlagen hast:

    #include <iostream>
    #include <windows.h>
    #include <atlbase.h>
    
    using namespace std;
    
    string Funktion()
    {
        string str = "Hallo";
    
        return str;
    }
    
    int main()
    {
        USES_CONVERSION;
        LPCWSTR winAPIString = A2W(Funktion().c_str());
    
        cout << winAPIString << '\n';
    }
    

    dann muß ich ja entweder Makros bemühen oder das, was sich hinter den Makros befindet, direkt hinschreiben. Zweitere Möglichkeit bedeutet allerdings, daß ich all die Sachen, die sich hinter den Makros befinden, jedesmal, bei jedem einzelnen String, manuell neu deklarieren muß (zum Beispiel die Variablen aus USES_CONVERSION).
    Wie würde das ganze also schlußendlich aussehen, wenn ich eine einzelne, für sich allein stehende Funktion haben will, die mir einen String in einen anderen konvertiert?
    Ich habe nun schon diverse Tips hier gelesen, aber ich habe noch nicht eine in sich geschlossene Funktion gesehen, die man von überall aufrufen kann. Wie müßte diese aussehen? Wie sieht eine ConvertString-Funktion aus, die intern vielleicht noch die Makros USES_CONVERSION und A2W/W2A benutzt (die Makros auflösen kann ich ja dann später selbst), mit der es aber nicht mehr nötig ist, diese Makros außerhalb (in der main oder einer anderen Funktion) noch irgendwo zu verwenden? Wie sieht eine ConvertString-Funktion aus, bei der ich in der main nur noch schreiben muß:

    LPCSTR str = NULL;
    
    /* ... */ ConvertString(/* ... */ L"Tadaaa! Es klappt!" /* ... */);
    
    MessageBoxA(str);
    // Ausgabe:
    // Tadaaa! Es klappt!
    

    Wenn Du mir sagen könntest, wie das geht, dann wäre ich Dir wirklich dankbar.



  • Wie würde das ganze also schlußendlich aussehen, wenn ich eine einzelne, für sich allein stehende Funktion haben will, die mir einen String in einen anderen konvertiert?

    Die Antwort wurde bereits mehrfach gegeben, nur du akzeptierst sie nicht.

    Es gibt in C++ keine Strings, also kannst du auch keine zurückgeben. Du kannst nur entweder einen Zeiger auf ein char Array zurückgeben, oder ein Objekt. Wenn du einen Zeiger auf ein char Array zurückgibst hast du ein Problem mit der Speicherverwaltung, und Objekte willst du nicht.
    Ergo: was du wünscht ist *unmöglich*.



  • O.k., ich hab es jetzt so geregelt, daß mir die Funktion einen String auf dem Heap erzeugt und zurückgibt. Dazu noch eine Delete-Funktion. Das ganze sieht so aus:

    LPSTR CreateANSIString(LPCWSTR str)
    {
    	if (str)
    	{
    		const UINT LENGTH = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
    		LPSTR newString = new CHAR[LENGTH];
    
    		WideCharToMultiByte(CP_ACP, 0, str, -1, newString, LENGTH, NULL, NULL);
    
    		return newString;
    	}
    	else
    		return NULL;
    }
    
    void DeleteANSIString(LPSTR str)
    {
    	if (str)
    		delete[] str;
    }
    

    Nur ist jetzt das Problem: Die Strings, die in Windows immer verwendet werden (z.B. WNDCLASSEXA::lpszClassName) sind vom Typ LPCSTR und die ließen sich nicht mit delete[] löschen. Was kann man da tun?


  • Mod

    Dann deklariere die zweite Funktion doch mit einem const Zeiger?

    PS: Ich Frage mich warum wir diese ganze Diskussion geführt haben.
    Nachträglich diese Funktion einzubauen ist mit Sicherheit genauso schwer, wie eine vernünftige Klasse zu verwenden!



  • Martin Richter schrieb:

    Dann deklariere die zweite Funktion doch mit einem const Zeiger?

    Hab ich. Dann hat er sich geweigert, das delete durchzuführen.

    Martin Richter schrieb:

    PS: Ich Frage mich warum wir diese ganze Diskussion geführt haben.
    Nachträglich diese Funktion einzubauen ist mit Sicherheit genauso schwer, wie eine vernünftige Klasse zu verwenden!

    Aber ich kann keine Klasse verwenden, weil die Strings, die ich benutze, nicht von mir selbst deklariert wurden. Es ging mir darum, sowas hier zu realisieren:

    WNDCLASSEXW wndClass;
    // ...
    wndClass.lpszClassName = L"Irgendein String";
    // ...
    
    if (/* OS unterstützt Unicode nicht*/)
    {
        WNDCLASSEXA wndClassA;
        // ...
        wndClassA.lpszClassName = Convert(wndClass.lpszClassName);
        // ...
        RegisterClassExA(&wndClassA);
    }
    else
        RegisterClassExW(&wndClass);
    

    In diesem Fall nützt es mir überhaupt nichts, irgendeine Wrapperklasse zu benutzen, da der umzuwandelnde String von Windows vorgegeben ist. Und ich kann ja nicht die WNDCLASSEX-Struktur umdefinieren.


Anmelden zum Antworten