Why does ParamStr show the wrong file name?

1.4k views Asked by At

I have associated the ".file_5" extension with my application and I used the ParamStr(1) function in Delphi to show a messagebox that contains the path & file name of the file when I double click on it in explorer using the code below.

procedure TForm1.FormCreate(Sender: TObject);
 var
  TheFile : string;
begin
  TheFile := ParamStr(1);  //filename for the file that was loaded
  ShowMessage(TheFile);
end;

This works, but if I move the file to another location then the location it was originally in, then the message that is shown is not correct.

Example: (using test.file_5)

The original location of the file is in the C:\ drive and when I double click it my application starts and displays a Messagebox that says:

C:\test.file_5

This is correct. If I move that same file to a directory that contains spaces like the program file folder for example then the Messagbox that is displayed is not

C:\Program Files\test.file_5

like I would expect but rather

C:\PROGRA~1.FILE_

which is obviously not the information I am after so my question is how can I use the ParamStr() function to take into account directories that have spaces in them or is there a better function that I should use that works with directories that contains spaces in them.

3

There are 3 answers

1
Ken White On BEST ANSWER

Your association is set up wrong. Instead of having double_clicking the .file_5 doing

C:\YourPath\YourApp.exe %1

The association should be set up as

"C:\YourPathYourApp.exe" "%1"

Notice the double quotes around the %1 - this keeps any spaces contained instead of their causing Windows to pass the short path and filename.

5
Andrew Flemming On

Solved it on my own using this function.


Function GetLongPathAndFilename(Const S : String) : String;

Var srSRec : TSearchRec; iP,iRes : Integer; sTemp,sRest : String; Bo : Boolean;

Begin Result := S + ' [directory not found]'; // Check if file exists Bo := FileExists(S); // Check if directory exists iRes := FindFirst(S + '*.*',faAnyFile,srSRec); // If both not found then exit If ((not Bo) and (iRes <> 0)) then Exit; sRest := S; iP := Pos('\',sRest); If iP > 0 then Begin sTemp := Copy(sRest,1,iP - 1); // Drive sRest := Copy(sRest,iP + 1,255); // Path and filename End else Exit; // Get long path name While Pos('\',sRest) > 0 do begin iP := Pos('\',sRest); If iP > 0 then Begin iRes := FindFirst(sTemp + '\' + Copy(sRest,1,iP - 1),faAnyFile,srSRec); sRest := Copy(sRest,iP + 1,255); If iRes = 0 then sTemp := sTemp + '\' + srSRec.FindData.cFileName; End; End; // Get long filename If FindFirst(sTemp + '\' + sRest,faAnyFile,srSRec) = 0 then Result := sTemp + '\' + srSRec.FindData.cFilename; SysUtils.FindClose(srSRec); End;

1
jachguate On

This is not neccesarily wrong... is just explorer is passing a short file name to your program -instead of the long file name-. See short vs. long names.

You can open the file using both names or you can convert from short to long file name before the ShowMessage (or actually manipulating the file) if you're concerned about working with long file names only. Use the GetLongPathName API call, defined in Windows.pas.

function ShortToLongFileName(const ShortName: string): string;
var
  outs: array[0..MAX_PATH] of char;
begin
  GetLongPathName(PChar(ShortName), OutS, MAX_PATH);
  Result := OutS;
end;

procedure TForm2.Button1Click(Sender: TObject);
var
  TheFile : string;
begin
  TheFile := ParamStr(1);  //filename for the file that was loaded
  TheFile := ShortToLongFileName(TheFile);
  ShowMessage(TheFile);
end;

I tested it under Windows Vista and GetLongPathName works whether you supply a short or a already long file name (if the file exists, obviusly)