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



  • aber ich weiß immer noch nicht, wie es möglich ist, den erhaltenen String zurückzugeben, ohne daß da noch ein new rumschwirrt, das eigentlich ein delete bräuchte.

    Direkt ist das garnicht möglich.

    Das "NULL in" ist im übrigen kein Problem, das kannst du abfangen indem du einfach vor der Umwandlung die Parameter checkst.

    Das "NULL out" ist etwas tricky. Normalerweise kann man es ignorieren und "NULL in" einfach in einen leeren std::(w)string verwandeln. Wenn du unbedingt "NULL in, NULL out" brauchst ist das aber auch einfach nur etwas Arbeit. Eine kleine Helper-Klasse welche z.B. einen std::wstring enthält, sowie die Information ob ein NULL Pointer zurückgegeben werden soll, oder ein Zeiger auf den Inhalt des Strings. Dann definierst du noch passende Konstruktoren, und ggf. einen operator wchar_t const*, fertig.



  • hustbaer schrieb:

    aber ich weiß immer noch nicht, wie es möglich ist, den erhaltenen String zurückzugeben, ohne daß da noch ein new rumschwirrt, das eigentlich ein delete bräuchte.

    Direkt ist das garnicht möglich.

    Das "NULL in" ist im übrigen kein Problem, das kannst du abfangen indem du einfach vor der Umwandlung die Parameter checkst.

    Wie soll ich denn einen Parameter vom Typ std::string, dem ich einen LPCSTR übergebe, auf NULL prüfen?

    hustbaer schrieb:

    Das "NULL out" ist etwas tricky. Normalerweise kann man es ignorieren und "NULL in" einfach in einen leeren std::(w)string verwandeln. Wenn du unbedingt "NULL in, NULL out" brauchst ist das aber auch einfach nur etwas Arbeit. Eine kleine Helper-Klasse welche z.B. einen std::wstring enthält, sowie die Information ob ein NULL Pointer zurückgegeben werden soll, oder ein Zeiger auf den Inhalt des Strings. Dann definierst du noch passende Konstruktoren, und ggf. einen operator wchar_t const*, fertig.

    Wieso muß ich hier überhaupt mit den C++-Strings arbeiten? Meine Funktion ist, wie gesagt, direkt für die Umwandlung von Strings, die in der WinAPI vorkommen. Ich finde es da nicht besonders günstig (oder passend), die Umwandlungsfunktion mit std::string zu schreiben, zumal die Umwandlung selbst durch MultiByteToWideChar wieder mit LPCSTR getätigt wird. Ich hätte also einen LPCSTR, den ich als Parameter an einen std::string übergebe. Aus dem mache ich in der Funktion einen LPCSTR, um den LPCWSTR zu bekommen. Der wird dann wieder an einen std::wstring übergeben, den ich zurückliefere und der außerhalb der Funktion in einen LPCWSTR umgewandelt wird. Da finde ich, sollte ich gleich von vornherein nur mit LPCSTR/LPCWSTR arbeiten (und dann vielleicht als Zusatz die Funktion mit std::string um die LPCSTR-Funktion wrappen).

    Wie wird das eigentlich in den originalen WinAPI-Funktionen gemacht? Soweit ich weiß, ruft ja zum Beispiel die MessageBoxA-Funktion einfach nur die MessageBoxW-Funktion auf. Dort müssen die das doch auch irgendwie umwandeln. Und da die WinAPI in C geschrieben ist, gibt es dort keinen std::string. Wie würden diese A-Funktionen also aussehen? Ist davon auszugehen, daß dort überall erst dynamischer Speicher für die Strings reserviert wird? So wie hier

    int MessageBoxA(HWND hWnd, LPCSTR message, LPCSTR caption, UINT buttons)
    {
        LPCWSTR wMessage = malloc(irgendwas);
        MultiByteToWideChar(blablabla, wMessage, blablabla);
    
        LPCWSTR wCaption = malloc(irgendwas);
        MultiByteToWideChar(blablabla, wCaption, blablabla);
    
        int returnValue = MessageBoxW(hWnd, wMessage, wCaption, buttons);
    
        free(wMessage);
        free(wCaption);
    
        return returnValue;    
    }
    


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

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



  • 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*.


Anmelden zum Antworten