Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inno Setup always installs into admin's AppData directory

I want to store my app in the current user's AppData directory to avoid problems with permissions we had when auto-updating our app (when it's stored in Program Files). We don't give the user the option of where to install the app. We've had complaints from non-admin users that the installer stores the app in the admin's AppData directory (after UAC of course), instead of the current user's AppData directory, which then prevents the app from running in the future.

Firstly, I had DefaultDirName={userappdata}\{#MyAppName}. Then I tried DefaultDirName={commonappdata}\{#MyAppName}. Then I tried that along with PrivilegesRequired=lowest and even as PrivilegesRequired=none as the Make InnoSetup installer request privileges elevation only when needed question suggested.

This is my script as of right now in case I'm missing something obvious:

; Script generated by the Inno Setup Script Wizard.
;SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

#define MyAppName "Teamwork Chat"
#define MyAppVersion "0.10.0"
#define MyAppPublisher "Digital Crew, Ltd."
#define MyAppURL "http://www.teamwork.com/"
#define MyAppExeName "TeamworkChat.exe"

[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{0F063485-F5AF-4ADE-A9F9-661AB3BAA661}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={userappdata}\{#MyAppName}
DisableDirPage=yes
DefaultGroupName={#MyAppName}
OutputDir=E:\chat-client\dist
OutputBaseFilename={#MyAppName}_for_Windows32_Installer-{#MyAppVersion}
SetupIconFile=E:\chat-client\icons\teamwork_chat.ico
WizardImageFile=E:\chat-client\icons\chatWizardImageFile.bmp
Compression=lzma
SolidCompression=yes
PrivilegesRequired=none

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked

[Files]
Source: "E:\chat-client\dist\TeamworkChat\win32\TeamworkChat.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "E:\chat-client\dist\TeamworkChat\win32\ffmpegsumo.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "E:\chat-client\dist\TeamworkChat\win32\icudtl.dat"; DestDir: "{app}"; Flags: ignoreversion
Source: "E:\chat-client\dist\TeamworkChat\win32\libEGL.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "E:\chat-client\dist\TeamworkChat\win32\libGLESv2.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "E:\chat-client\dist\TeamworkChat\win32\nw.pak"; DestDir: "{app}"; Flags: ignoreversion
; NOTE: Don't use "Flags: ignoreversion" on any shared system files

[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon

[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent

Edit

I've changed two options but still no luck;

PrivilegesRequired=lowest
...
[Icons]
...
Name: "{userdesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon

Edit 2:

I've added the runasoriginaluser flag and generated a new AppId (GUID) but still no luck;

[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent runasoriginaluser

Edit 3:

I've created a simple GitHub repository with the source files and Inno script.

Edit 4:

I had been testing on Windows 8.1. It seems to work when compiled on Windows 7, and ran on Windows 8, but not when compiled on 8 and ran on 8.

Edit 5:

It's solved now but to clear things up regarding Edit 4, it wasn't working only on my machine. It worked on other Windows 8 machines. Must've been some weird caching or something (even though I changed the AppId).

like image 870
Adam Lynch Avatar asked Mar 31 '15 19:03

Adam Lynch


2 Answers

From the wording of your question and if I am understanding you correctly, it sounds like this is because you are "validating with an admin account for the install to run." If this is the case and you are entering a different account (from that which you are logged in with) at the UAC prompt, the current user then actually becomes the Administrator account you just entered at the UAC prompt and not the account you are logged in with. Therefore, as long as you are being asked to elevate the installation using UAC, it will not end up in the logged in user's AppData directory.

What you may need to do is use the runasoriginaluser function, which will use the logged in user credentials instead of the account you entered at the UAC prompt, or find what is causing the UAC elevation prompt.

See also Inno Setup Creating registry key for logged in user (not admin user).

The MSDN documentation on Installation Context may also be useful.

like image 82
Robert Wigley Avatar answered Oct 14 '22 05:10

Robert Wigley


It should work with PrivilegesRequired=lowest. And it's the correct approach. If it does not, we want to see a log file.

The lowest will make the installer run within context of the current unprivileged user. Hence all constants, like {userappdata}, {userdesktop}, etc, will refer to the current user.


Anyway, to answer your question, you can use the code below.

But that's just for special situations, when the installer really needs administrator privileges (e.g. to register some system DLL), but still needs to deploy files for the original user. Like here: Inno Setup - Register components as an administrator.

[Files]
Source: "MyProg.exe"; DestDir: "{code:GetAppData}"

[Code]

var
  AppDataPath: string;

function GetAppData(Param: string): string;
begin
  Result := AppDataPath;
end;  

function InitializeSetup(): Boolean;
var
  Uniq: string;
  TempFileName: string;
  Cmd: string;
  Params: string;
  ResultCode: Integer;
  Buf: AnsiString;
begin
  AppDataPath := ExpandConstant('{userappdata}');
  Log(Format('Default/Fallback application data path is %s', [AppDataPath]));
  Uniq := ExtractFileName(ExpandConstant('{tmp}'));
  TempFileName :=
    ExpandConstant(Format('{commondocs}\appdata-%s.txt', [Uniq]));
  Params := Format('/C echo %%APPDATA%% > %s', [TempFileName]);
  Log(Format('Resolving APPDATA using %s', [Params]));
  Cmd := ExpandConstant('{cmd}');
  if ExecAsOriginalUser(Cmd, Params, '', SW_HIDE, ewWaitUntilTerminated, ResultCode) and
     (ResultCode = 0) then
  begin
    if LoadStringFromFile(TempFileName, Buf) then
    begin
      AppDataPath := Trim(Buf);
      Log(Format('APPDATA resolved to %s', [AppDataPath]));
    end
      else
    begin
      Log(Format('Error reading %s', [TempFileName]));
    end;
    DeleteFile(TempFileName);
  end
    else
  begin
    Log(Format('Error %d resolving APPDATA', [ResultCode]));
  end;

  Result := True;
end;

More similar questions:

  • Inno Setup Using {localappdata} for logged in user
  • Inno Setup - puts user files in admin documents
like image 26
Martin Prikryl Avatar answered Oct 14 '22 05:10

Martin Prikryl