![]() |
Rückgabe von CommandLineToArgvW
Folgender Code:
Delphi-Quellcode:
Wenn ich PPWideChar und die Funktion nicht selber deklariere, siehe auskommentierten Code, bekomme ich nicht die Argumente, sondern nur die ersten drei Zeichen des Pfades.
//type
//TPWideCharArray = array[0..0] of PWideChar; //PPWideCharArray = ^TPWideCharArray; //function CommandLineToArgvW( lpCmdLine: PWideChar; var NumArgs: Integer): PPWideChar; //stdcall; external 'shell32.dll'; procedure GetCommandLineArgs(Args: TStrings); var NumArgs: Integer; //TempArgs: PPWideCharArray; TempArgs: PPWideChar; i: Integer; begin if CommandLineToArgvW(GetCommandLineW, NumArgs) <> nil then begin try try TempArgs := CommandLineToArgvW(GetCommandLineW, NumArgs); for i := 0 to NumArgs - 1 do Args.Add(TempArgs^[i]); except raise Exception.Create(SysErrorMessage(GetLastError)); end; finally GlobalFree(THandle(TempArgs)); end; end; end; procedure TForm1.FormCreate(Sender: TObject); begin GetCommandLineArgs(ListBox1.Items); end; Was muss ich ändern, damit ich die Datentypen und die Funktion nicht selber deklarieren muss, damit es funktioniert? Entwicklungsumgebung ist Delphi 7, also nix Unicode. |
AW: Rückgabe von CommandLineToArgvW
Delphi-Quellcode:
for i := 0 to NumArgs - 1 do begin Args.Add(TempArgs^); Inc(TempArgs); end; |
AW: Rückgabe von CommandLineToArgvW
Danke funktioniert. Aber warum? Kannst du mir das auch noch erklären?
|
AW: Rückgabe von CommandLineToArgvW
Der Rückgabewert ist ein Zeiger auf den ersten WideChar Zeiger. Also bei mir funkz das mit PPWideCharArray.
|
AW: Rückgabe von CommandLineToArgvW
Hm, OK. Dann habe ich nur den Zugriff versemmelt. ;)
Ja mit PPWideCharArray funktioniert es bei mir auch, nur ich wollte ohne die zusätzliche Deklaration auskommen. |
AW: Rückgabe von CommandLineToArgvW
Ich habe nochmal darüber nachgedacht und mir ist aufgefallen, das der Code, so wie er von mir vorgeschlagen wurde, gleich zwei Memoryleaks produziert. Hier nun eine korregierte Fassung. (Ich gehe davon aus, das die Windows-Funktionen keine Exception erzeugen werden).
Delphi-Quellcode:
procedure GetCommandLineArgs(Args: TStrings);
type TPWideCharArray = array[0..0] of PWideChar; var NumArgs: Integer; TempArgs: PPWideChar; i: Integer; begin TempArgs := CommandLineToArgvW(GetCommandLineW, NumArgs); try if TempArgs <> nil then begin for i := 0 to NumArgs - 1 do Args.Add(TPWideCharArray(TempArgs^)[i]); end else RaiseLastOSError; finally GlobalFree(THandle(TempArgs)); end; end; |
AW: Rückgabe von CommandLineToArgvW
Das heißt, dieser Code
![]() verursacht Speicherlücken? Wo entstehen diese denn? |
AW: Rückgabe von CommandLineToArgvW
Ich habe auch was :)
1. CommandLineToArgvW verwendet LocalAlloc und daher sollte LocalFree verwendet werden (das macht aber in 32bit nichts mehr aus, da es dasselbe ist. Aber MSDN sagt es halt so 2. try/except ist hier garnicht notwendig, ja sogar total falsch, da GetLastError verwendet wird, was falsche Werte liefert, weil keine Winapi so eine Exception wirft (könnte auch eine AV sein) 3. Das Prüfen des Rückgabewertes von CommandLineToArgvW auf nil ist ein Fehler, denn hier wird Speicher alloziert, jedoch nicht freigegeben. Weiterhin gibt es nur zwei Fälle, die ein nil produzieren
|
AW: Rückgabe von CommandLineToArgvW
Der Code
Delphi-Quellcode:
erzeugt zwei Speicherlöcher:
procedure GetCommandLineArgs(Args: TStrings);
var NumArgs: Integer; TempArgs: PPWideChar; i: Integer; begin if CommandLineToArgvW(GetCommandLineW, NumArgs) <> nil then begin try try TempArgs := CommandLineToArgvW(GetCommandLineW, NumArgs); for i := 0 to NumArgs - 1 do begin Args.Add(TempArgs^); Inc(TempArgs); end; except raise Exception.Create(SysErrorMessage(GetLastError)); end; finally GlobalFree(THandle(TempArgs)); end; end; end; Erstes Speicherloch:
Delphi-Quellcode:
denn das Ergebnis wird nicht freigegeben (wie Dezipaitor schon richtig schreibt)
if CommandLineToArgvW(GetCommandLineW, NumArgs) <> nil then
Zweites Speicherloch:
Delphi-Quellcode:
denn TempArgs ist nicht mehr gültig (wegen Inc()).
GlobalFree(THandle(TempArgs));
|
AW: Rückgabe von CommandLineToArgvW
Ok, danke für die Erklärung.
|
AW: Rückgabe von CommandLineToArgvW
Zitat:
Delphi-Quellcode:
der Wert von TempArgs zugewiesen wird.
TempArgs := CommandLineToArgvW(GetCommandLineW, NumArgs);
|
AW: Rückgabe von CommandLineToArgvW
Ja, das ist wohl war. Es gibt viele Wege zum Ziel. Es geht auch so:
Delphi-Quellcode:
Gegenüber der Lösung in Antwort #6 sieht das hier zwar nicht so schön aus, dafür übersteht es aber eine Bereichsprüfung.
procedure GetCommandLineArgs(Args: TStrings);
var NumArgs: Integer; TempArgs, p: PPWideChar; i: Integer; begin TempArgs := CommandLineToArgvW(GetCommandLineW, NumArgs); try if TempArgs <> nil then begin p := TempArgs; for i := 0 to NumArgs - 1 do begin Args.Add(p^); Inc(p); end; end else RaiseLastOSError; finally LocalFree(THandle(TempArgs)); end; end; |
AW: Rückgabe von CommandLineToArgvW
Man muss Prioritäten setzen. Schönheit oder Korrektheit. :wink:
|
AW: Rückgabe von CommandLineToArgvW
Naja, das try finally ist hier garnicht notwendig und macht es imo unübersichtlich. Besser sollte es weg und das LocalFree in die if-Bed mit rein.
|
AW: Rückgabe von CommandLineToArgvW
Also so:
Delphi-Quellcode:
procedure GetCommandLineArgs(Args: TStrings);
type TPWideCharArray = array[0..0] of PWideChar; var NumArgs: Integer; TempArgs: PPWideChar; i: Integer; begin TempArgs := CommandLineToArgvW(GetCommandLineW, NumArgs); if TempArgs <> nil then begin for i := 0 to NumArgs - 1 do Args.Add(TPWideCharArray(TempArgs^)[i]); LocalFree(THandle(TempArgs)); end else RaiseLastOSError; end; |
AW: Rückgabe von CommandLineToArgvW
Nunja, ich hatte auch darüber nachgedacht, ob das try finally notwendig ist. Ich hatte es drinn gelassen, weil die Add-funktion bei einer leeren Liste (args=nil oder args nicht gültig) eine Exception erzeugen würde. Falls man den Fall LocalFree(0) abfangen möchte (was ich nicht für notwendig halte), dann könnte man das ja auch noch auf anderen Wegen erreichen.
|
AW: Rückgabe von CommandLineToArgvW
Zitat:
Zitat:
Delphi-Quellcode:
Es müste auch funktionieren, wenn du das ^ weglassen würdest.
for i := 0 to NumArgs - 1 do
Args.Add(TempArgs[i]); Über ^ dereferenzierst du den PPWideChar und der Index [i] wird dann als Zeichenindex im 1. PWideChar gezählt. Ohne ^ wäre es aber der Index im PPWideChar, also im Array. bzw. so müßte es auch gehn.
Delphi-Quellcode:
type TTempArgs: array[0..0] of PWideChar;
var TempArgs: ^TempArgs; TempArgs := Ponter(CommandLineToArgvW(GetCommandLineW, NumArgs)); ... for i := 0 to NumArgs - 1 do Args.Add(TempArgs[i]); |
AW: Rückgabe von CommandLineToArgvW
Danke für die Erklärung.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:24 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz