Boy, I was wrong. Somewhere in the back of my head I knew it.
ParamStr goes from zero (the name of the EXE) through ParamCount (the last parameter). Duh :)
I’ll keep this so you can have a good laugh:
When you add double quoted arguments to the commandline of your Delphi app, strange things can happen: the first parameter seems to be gone, while it is there.
It appears that the ParamCount/ParamStr logic fails here, and cannot be repaired because of backward compatibility.
Lets look at this commandline:
“..\bin\DumpCommandLine.exe” “C:\Program Files\test.xml” “C:\Program Files\meMySelfAndI.xml”
The demo code below will output something like this:
ParamCount: 2 ParamStr(): 0 C:\develop\DumpCommandLine\bin\DumpCommandLine.exe 1 C:\Program Files\test.xml CommandLine: "..\bin\DumpCommandLine.exe" "C:\Program Files\test.xml" "C:\Program Files\meMySelfAndI.xml" CommandLineStrings.Count: 3 CommandLineStrings[]: 0 ..\bin\DumpCommandLine.exe 1 C:\Program Files\test.xml 2 C:\Program Files\meMySelfAndI.xml
You see that regular ParamCount/ParamStr calls will mis the “C:\Program Files\test.xml” parameter.
But getting it through CommandLineStrings will correctly get it.
This is the dump code:
unit CommandlineDemoUnit;
interface
procedure DumpCommandLineToConsole;
implementation
uses
Classes, CommandlineUnit;
procedure DumpCommandLineToConsole;
var
CommandLineStrings: TStrings;
I: Integer;
begin
Writeln('ParamCount:', #9, ParamCount);
Writeln('ParamStr():');
for I := 0 to ParamCount - 1 do
Writeln(I, #9, ParamStr(I));
Writeln('CommandLine:');
Writeln(CommandLine);
CommandLineStrings := CreateCommandLineStrings();
Writeln('CommandLineStrings.Count:', #9, CommandLineStrings.Count);
Writeln('CommandLineStrings[]:');
try
for I := 0 to CommandLineStrings.Count - 1 do
Writeln(I, #9, CommandLineStrings[I]);
finally
CommandLineStrings.Free;
end;
end;
end.
And this the code to get the CommandLine and CommandLineStrings, which will fill a TStrings result using the CommaText property (it uses a default QuoteChar of of double quote #34 and Delimiter of space #32, this will work nicely):
unit CommandlineUnit; interface uses Classes; function CommandLine: string; function CreateCommandLineStrings: TStrings; implementation uses Windows; function CommandLine: string; begin Result := GetCommandLine(); end; function CreateCommandLineStrings: TStrings; begin Result := TStringList.Create(); Result.CommaText := CommandLine; end; end.
Note that you need to manually free the TStrings object to avoid memory leaks.
–jeroen





