Search code examples
windowsinstallationinno-setupenvironment

Constant for AppData\LocalLow in Inno Setup?


Currently to access LocalLow I use this:

{%USERPROFILE}\AppData\LocalLow

But I would like to know if there's a constant for that in Inno Setup, since both Roaming and Local have one.


Solution

  • There's no constant for AppData\LocalLow.

    You may use Pascal Scripting to resolve it.

    To resolve the "LocalLow", one has to use SHGetKnownFolderPath.
    See also Detect the location of AppData\LocalLow.

    The implementation involves few hacks, due to a lack of (wide) PChar type in Unicode Inno Setup.

    const
      MAX_PATH = 260;
      AppDataLocalLowGUID = '{A520A1A4-1780-4FF6-BD18-167343C5AF16}';
    
    // There's no PChar in Unicode Inno Setup,
    // pretend the function returns a pointer to an Integer
    function SHGetKnownFolderPath(rfid: TGUID; dwFlags: DWORD; hToken: THandle;
      var ppszPath: Integer): Integer;
      external '[email protected] stdcall';
    
    // And allow the Integer to be copied to string
    function StrCpy(Dest: string; Source: Integer): Integer;
      external '[email protected] stdcall';
      
    // And allow the Integer pointer to be released
    procedure CoTaskMemFreeAsInteger(pv: Integer);
      external '[email protected] stdcall';
    
    function GetAppDataLocalLow: string;
    var
      Path: Integer;
      I: Integer;
    begin
      if SHGetKnownFolderPath(StringToGUID(AppDataLocalLowGUID), 0, 0, Path) = 0 then
      begin
        // The path should not be longer than MAX_PATH
        SetLength(Result, MAX_PATH);
    
        StrCpy(Result, Path);
    
        CoTaskMemFreeAsInteger(Path);
    
        // Look for NUL character and adjust the length accordingly
        SetLength(Result, Pos(#0, Result) - 1);
      end;
    end;
    

    If you need to use the path in non-Code section (outside of the Pascal Script), you can use a scripted constant:

    [Files]
    Source: myfile.txt; DestDir: {code:GetAppDataLocalLow}
    

    And you need to change the function signature to take a dummy parameter:

    function GetAppDataLocalLow(Param: string): string;