Funktion mit LPTSTR als Parameter. Audruf mit TCHAR Array: ist Leer.
-
Hier meine Funktion:
void CWin32App::AppDirectory(LPTSTR szFileName) { GetModuleFileName(NULL, this->m_szFileName, sizeof(this->m_szFileName) / sizeof(TCHAR)); szFileName = TEXT("Ein Test!"); }
Aufruf mit :
Win32App->AppDirectory( szAppDir );
wobei:
TCHAR szAppDir[MAX_PATH] = TEXT("\0");
Mein Problem:
Wenn ich debugge und mir den Wert von "szAppDir ansehe ist der leer. Eben gleich "".IDE: Visual Studio 2008.
Ich sehe das Problem nicht. LPTSTR ist doch TCHAR*. Wenn ich dann die Funktion mit dem Array aufrufe, dann sollte der doch den String besitzen.
denn szFileName enthält ja den Text???
-
Du bringst da etwas mit den Pointern durcheinander.
TCHAR szAppDir[MAX_PATH] = TEXT("\0");
Hierbei wird ein Array von TCHAR's erstellt, szAppDir gibst du ganz richtig in deine Funktion rein, allerdings musst du dir dabei immer vor Augen halten dass szAppDir innerhalb deiner Funktion nur ein Pointer auf die erste Variable deines Arrays ist.
Deine Funktion weist also einfach nur dem "eingehenden" Pointer szFileName einen neuen Wert zu. Davon bekommt aber deine Hauptroutine nichts mit weil die Parameter bei Funktionsaufrufen kopiert werden, und du somit innerhalb der Funktion nur auf der Kopie arbeitest.
Korrekt müsste deine Funktion lauten:
void CWin32App::AppDirectory(LPTSTR szFileName) { GetModuleFileName(NULL, this->m_szFileName, sizeof(this->m_szFileName) / sizeof(TCHAR)); strcpy( szFileName, TEXT("Ein Test!") ); //bzw wcscpy bei Unicode }
Hierbei verwendet die Funktion strcpy ("String Copy") nur die Adresse welche in szFileName drin steht, und die ist identisch mit derer die in szAppName drin steht.
Bei den guten alten C-Strings brauchts immer ein wenig bis man das verstanden hat, war bei mir auch so. Einfach immer vor Augen halten dass ein C-String nur ein Array ist, und die vermeindliche "String-Variable" nur ein Zeiger auf das erste Element ist.
-
Zum einen: Strings in C sind null-terminiert. Das heißt, effektiv sind "" und "\0" das selbe (effektiv im Sinne von "alle String-Funktionen behandeln sie gleich"). Im Konkreten Fall der Array-Initialisierung machen
TCHAR szAppDir[MAX_PATH] = TEXT("\0");
und
TCHAR szAppDir[MAX_PATH] = TEXT("");
sogar genau das gleiche, weil der verbleibende Teil des Buffers mit Nullen gefüllt wird.
Zweitens (und das wird wahrscheinlich dein eigentliches Problem sein) hängt
szFileName = TEXT("Ein Test!");
nur einen Zeiger um. Da dieser im konkreten Fall eine Kopie des Zeigers ist, in den das Array szAppDir degeneriert, ändert das am Status des Arrays selbst rein gar nichts. Vermutlich willst du
_tstrcpy(szFileName, TEXT("Ein Test!");
...allerdings befinden wir uns damit tief im WinAPI und eigentlich im falschen Forum (Standard-C++ kennt weder TCHAr noch LPTSTR noch _tstrcpy).
-
seldon schrieb:
...allerdings befinden wir uns damit tief im WinAPI und eigentlich im falschen Forum (Standard-C++ kennt weder TCHAr noch LPTSTR noch _tstrcpy).
Deshalb wollte ich auch zuerst mit strcpy bzw. wcscpy kommen, gibt nichts schlimmeres als wenn die Leute die MS-Typen von Anfang an lernen und nachher verwundert sind dass ihr Code auf Linux nicht Compiliert
-
Ich verstehe, worauf du hinaus willst, aber TCHAR/LPTSTR mit strcpy zu mischen, macht eigentlich wenig Sinn - man läuft damit in Gefahr, dass das ganze nachher auch unter Windows nicht kompiliert.
Zumal schon GetModuleFileName die Portabilität schreiend aus dem Fenster springen lässt.
-
RedPuma schrieb:
Du bringst da etwas mit den Pointern durcheinander.
...
Korrekt müsste deine Funktion lauten:
void CWin32App::AppDirectory(LPTSTR szFileName) { GetModuleFileName(NULL, this->m_szFileName, sizeof(this->m_szFileName) / sizeof(TCHAR)); strcpy( szFileName, TEXT("Ein Test!") ); //bzw wcscpy bei Unicode }
...
Bei den guten alten C-Strings brauchts immer ein wenig bis man das verstanden hat, war bei mir auch so.
Die andere Stelle ist wohl auch etwas daneben, denn erstens
nSize: The size of the lpFilename buffer, in TCHARs
- Also darf NICHT durch sizeof(TCHAR) dividiert werden.
und zweitens gibt sizeof() vermutlich nur die groesse eines Zeigers zurueck, sollte aber die arraygroesse MAX_PATH sein.
Bemerkung:
Was an ANSI-C Strings unter Windows gut sein soll kann ich nicht erkennen. Im Gegensatz zu UNIX funktionieren selbst einfachste Dinge wie printf() nicht zuverlässig.
-
Hi,
danke, ich habe jetzt den Code geändert. Ok, szFileName (TCHAR*) wird jetzt "gefüllt" und nicht nur "umgehängt".
void CWin32App::AppDirectory(LPTSTR szFileName) { GetModuleFileName(NULL, this->m_szFileName, MAX_PATH); #ifndef UNICODE strcpy_s(szFileName, MAX_PATH, this->m_szFileName); #else wcscpy(szFileName, MAX_PATH, this->m_szFileName); #endif }
wo steht denn die _tstrcpy . Die findet VS 2008 nicht. _tstrcpy entscheidet ob UNICODE oder nicht...
GetModuleFileName sollte jetzt funktioneren,...
seldon schrieb:
Ich verstehe, worauf du hinaus willst, aber TCHAR/LPTSTR mit strcpy zu mischen, macht eigentlich wenig Sinn - man läuft damit in Gefahr, dass das ganze nachher auch unter Windows nicht kompiliert.
Zumal schon GetModuleFileName die Portabilität schreiend aus dem Fenster springen lässt.
Ähm, das mit der Kopie...
wenn ich
void foo(std::string bar)
kopie vom String bar...
wenn ich
void foo(std::string& bar)
dann kann ich bar ändern und das Original wird auch geändert.
Ich habe also in meinem Beispiel nur die Adresse umgehängt, ohne Daten an diese Adresse zu packen. Demzufolge war der Array leer, weil ich nur einen leeren auf einen anderen leeren gehängt hatte.
Gruß
Franky
-
Tut mir Leid, mein Fehler. Das Ding heißt _tcscpy und wird in der tchar.h definiert. Siehe auch hier.
Ich arbeite selten mit TCHAR etc. - es macht das Arbeiten mit plattformübergreifenden Bibliotheken unnötig schwierig. Jedenfalls, wenn dir diese Strings andrehen.
-
Hi,
Danke. Da ja schon mehrfach erwähnt worden ist, das "TCHAR" "char*" oder "LPTSTR" usw. eher C ist, sollte dann in "C++" eher mit String oder CString (MFC/ATL).
Kann denn String oder CString plattformübergreifend eingesetzt werden?
Da Windows-Programme ja regen Gebrauch vom Windows-API machen (das ja in C geschrieben ist, also auch nach wie vor) kann das ja auch schlecht auf z.B. Linux portiert werden.Gruß
Franky
-
Hallo
Zunächst läuft der Code ja nun. Allerdings wäre zu überlegen, ob man den Funktionsaufruf nicht wirklich mal auf C++ Niveau hebt. Der Prototyp
FrankTheFox schrieb:
void CWin32App::AppDirectory(LPTSTR szFileName)
Nutzt zum einen den Rückgabewert nicht und beim Parameter geht die Information verloren wieviel Platz man reserviert hat.
Ich würde raten objektbasierte Strings zu verwenden und den Parameter wegzulassen.
CString CWin32App::AppDirectory(void)
Den Speicher für GetModuleFileName() kann man zunächst lokal allokieren und dann in einem CString zurückgeben.
Auch der Rückgabewert von GetModuleFileName() sollte ausgewertet werden.
Wenn der zurückgegebene String zu gross für den Puffer war, wird dieser abgeschnitten und die abschliessende Null weggelassen - das führt später
in der Regel zu einer Katastrophe.Notfalls wäre das so zu lösen:
LPTSTR pName = new TCHAR[MAX_PATH]; DWORD len = GetModuleFileName( ... ,MAX_PATH) if(len >= MAX_PATH) pName[MAX_PATH-1] = (TCHAR)0; CString cName(pName); delete [] pName; return(cName);
--
PS: Über Portabilität muss man sich eigentlich keine grossen Gedanken mehr machen sobald man Systemaufrufe - egal ob UNIX oder Windows tätigen muss