Search code examples
windowswinapiinno-setuppascalscript

How do I use PathCombine() from WinAPI in Pascal Script/Inno Setup?


I'm trying to figure out how to use WinAPI functions from Pascal Script/Inno Setup. I didn't find much code examples how to do it and I'm not a Pascal programmer. Here's what I did so far:

Importing the function

function PathCombine (
    pszPathOut : PChar;
    pszPathIn  : PChar;
    pszMore    : PChar
) : PChar;
  external 'PathCombineA@Shlwapi.dll stdcall';

and using it like this:

function InitializeSetup(): Boolean;
var 
  a, b,c : PChar;
  s : string;
begin
   SetLength(s, 256); { soon it gets working I'll switch to use MAX_PATH instead of }
   a := 'C:';
   b := 'one\two';
   c := PathCombine(s, a, b);
   MsgBox(s, mbInformation, MB_OK);
end;

The output is this:

enter image description here

The expected output is:

C:\one\two

I'm pretty sure I'm accessing garbage values in memory but I don't know why, how do I fix this?


Solution

  • You didn't specify if you are using Ansi or Unicode version of Inno Setup.

    But this should work in either version:

    function PathCombine(
       pszPathOut : PAnsiChar;
       pszPathIn  : PAnsiChar;
       pszMore    : PAnsiChar
    ) : PAnsiChar; external 'PathCombineA@Shlwapi.dll stdcall';
    
    function InitializeSetup(): Boolean;
    var 
      a, b, c: AnsiString;
    begin
       SetLength(c, 256); { soon it gets working I'll switch to use MAX_PATH instead of }
       a := 'C:';
       b := 'one\two';
       PathCombine(c, a, b);
       MsgBox(c, mbInformation, MB_OK);
       Result := True;
    end;
    

    Though I strongly encourage you to use Unicode version of Inno Setup and PathCombineW instead.

    function PathCombine(
       pszPathOut : string;
       pszPathIn  : string;
       pszMore    : string
    ) : Cardinal; external 'PathCombineW@Shlwapi.dll stdcall';
    
    function InitializeSetup(): Boolean;
    var 
      a, b, c: string;
    begin
       SetLength(c, 256); { soon it gets working I'll switch to use MAX_PATH instead of }
       a := 'C:';
       b := 'one\two';
       PathCombine(c, a, b);
       MsgBox(c, mbInformation, MB_OK);
       Result := True;
    end;
    

    Note that Inno Setup lacks PWideChar type. While it can marshal string to LPTSTR (PWideChar) function arguments, it cannot marshal LPTSTR return value. So I've used Cardinal for return type. It has the same size as pointer (to char), so a stack will match. And we do not actually need the returned value.