Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
783 views
in Technique[技术] by (71.8m points)

inno setup - Specify the registry uninstall key location/hive via [Code]

Inno Setup by default looks at the PrivilegesRequired setup variable, if this is set to admin or poweruser, the installer installs the uninstall registry key to HKLM. If this is set to lowest, then it will install the registry entries to HKCU.

I have a requirement to provide the user an option to install for "just me" or "everybody", and have done so by replacing the dir selection page with a radio selection of these two options. what I need to do now is also modify the registry install location based on this setting. If I install the app into the local user app data, it won't make sense to register the uninstall data at the HKLM level, because then other users will see it in the programs list and still be unable to uninstall or use it.

Edit: After looking through the documentation and the source of Install.pas, I found the CreateUninstallRegKey setup directive, which will disable Inno from installing registry keys at all, after which I can add my own registry entries, but is this really the only way?

Edit #2 (marked as duplicate): I've already taken a look at this Conditional Elevation question (and actually implemented it), and it's not the same as mine. The current elevation state does not alter where Inno Setup actually saves the uninstall registry info (in HKCU or HKLM). If you look at the Inno source code (Install.pas #507) you'll see that the PrivilegesRequired directive is the primary factor in where the registry is stored. If this is set to lowest, it doesnt matter if the installer is elevated or not - it will install the registry keys to HKCU, when the desired behavior is to select one or the other based on the users install preference, NOT the current elevation state. So all this being said, I'm looking for a solution to alter the registry root based on a code variable, regardless of current PrivilegesRequired or Elevation setting.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Inno Setup 6 has a built-in support for selecting between "Install for all users" and "Install for me only".

Basically, you can simply set PrivilegesRequiredOverridesAllowed:

[Setup]
PrivilegesRequiredOverridesAllowed=commandline dialog

enter image description here


For Inno Setup 5: As you found yourself, the logic is hard-coded. You cannot really control that.

The closest you can get is by using the undocumented (deprecated) PrivilegesRequired=none.

With this value (and with a help of installer-autodetection in Windows):

  • When you start the installer with an un-privileged account, it starts without prompting you for elevation. If you decide you need to elevate during the installation, you can restart the installer elevated.
  • When you start the installer with a privileged account, it always prompts you for elevation and won't start, if you reject that. So the installer always runs elevated. Again, you would have to restart the installer, if you decide you to proceed un-elevated. See How to Start a Process Unelevated or maybe Run un-elevated command from an elevated prompt?.

It's not exactly, what you want, but I do not think you can get any closer.


You can of course copy (move) the registry key between the HKCU and HKLM yourself by a code:

function MoveHKCUUninstallKeyToHKLM: Boolean;
var
  UninstallKey: string;
  AppId: string;
  I: Integer;
  ValueNames: TArrayOfString;
  ValueName: string;
  ValueStr: string;
  ValueDWord: Cardinal;
begin
  if '{#emit SetupSetting("AppId")}' <> '' then
  begin
    AppId := '{#emit SetupSetting("AppId")}';
  end
    else
  begin
    AppId := '{#emit SetupSetting("AppName")}';
  end;

  Result := False;
  if AppId = '' then
  begin
    Log('Cannot identify AppId');
  end
    else
  begin
    UninstallKey :=
      'SoftwareMicrosoftWindowsCurrentVersionUninstall' + AppId + '_is1';
    Log(Format(
      'AppId identified as "%s", using uninstall key "%s"', [AppId, UninstallKey]));
    if not RegKeyExists(HKCU, UninstallKey) then
    begin
      Log('HKCU uninstall key not found');
    end
      else
    if RegKeyExists(HKLM, UninstallKey) then
    begin
      Log('HKLM uninstall key exists already');
    end
      else
    begin
      Log('HKCU uninstall key found and HKLM key not exists yet');

      if not RegGetValueNames(HKCU, UninstallKey, ValueNames) then
      begin
        Log('Cannot list uninstall key values');
      end
        else
      begin
        I := 0;
        Result := True;
        while (I < GetArrayLength(ValueNames)) and Result do
        begin
          ValueName := ValueNames[I];
          if RegQueryStringValue(HKCU, UninstallKey, ValueName, ValueStr) then
          begin
            if not RegWriteStringValue(HKLM, UninstallKey, ValueName, ValueStr) then
            begin
              Log(Format('Error moving "%s" string value', [ValueName]));
              Result := False;
            end
              else
            begin
              Log(Format('Moved "%s" string value', [ValueName]));
            end;
          end
            else
          if RegQueryDWordValue(HKCU, UninstallKey, ValueName, ValueDWord) then
          begin
            if not RegWriteDWordValue(HKLM, UninstallKey, ValueName, ValueDWord) then
            begin
              Log(Format('Error moving "%s" dword value', [ValueName]));
              Result := False;
            end
              else
            begin
              Log(Format('Moved "%s" dword value', [ValueName]));
            end;
          end
            else
          begin
            { All uninstall values written by Inno Setup are either string or dword }
            Log(Format('Value "%s" is neither string nor dword', [ValueName]));
            Result := False;
          end;
          Inc(I);
        end;

        if Result then
        begin
          if not RegDeleteKeyIncludingSubkeys(HKCU, UninstallKey) then
          begin
            Log('Error removing HKCU uninstall key');
            Result := False;
          end
            else
          begin
            Log('Removed HKCU uninstall key');
          end;
        end;

        if not Result then
        begin
          if not RegDeleteKeyIncludingSubkeys(HKCU, UninstallKey) then
          begin
            Log('Failed to move uninstall key to HKLM, ' +
                'and also failed to rollback the changes');
          end
            else
          begin
            Log('Failed to move uninstall key to HKLM, rolled back the changes');
          end;
        end;
      end;
    end;
  end;
end;

procedure CurStepChanged(CurStep: TSetupStep);
begin
  if CurStep = ssPostInstall then
  begin
    Log('Post install');
    MoveHKCUUninstallKeyToHKLM;
  end;
end;

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...