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