2
votes

Inno Setup Version 5.5.9
Windows 7

We created an install package which installs the program in the current user's appdata\local\programs folder ({userpf}).

When trying to uninstall the program from command-line using Administrator account, it does the delete from the file structure, but the entry on the "Programs and Features" still exists. You have to go into the registry and delete the key.

We did various tests.

When you uninstall a 32-bit application from a user, who is a a administrator, it works, but not when you try to uninstall, where the user is not an administrator.

When you uninstall a 64-bit application, it does not work for an administrator or user.

When you look at the registry the 32-bit administrator's entry is under HKEY_LOCAL_MACHINE and the 32-bit user and 64-bit user and administrator's entry is under HKEY_USERS.

It seem that when entry is under HKEY_USERS, it does not delete it when uninstalling by administrator.

We use PDQ to log onto a PC to uninstall files. If the user go into programs and features and uninstall it works 100%. When uninstalling Silverlight using PDQ it works.

Thank you

Hendriette

1

1 Answers

0
votes

If an application is installed using Inno Setup without Administrator privileges, its Uninstall registry entry is stored to HKCU hive of the local account running the installation.

To uninstall such installation, you have to use the same local account.


If you run the uninstaller using any other account, it won't have an access to HKCU of the original account (which did run the installer) and won't be able to remove it.

It does not matter that you run the uninstaller by a user with Administrator privileges. Inno Setup does not remember, what account did run the installation. So even Administrator won't be able to identify, what registry hive to look to for the HKCU Uninstall registry entry.


If you need to support a remote administration, you have to both install and uninstall with Administrator privileges.


If you need to keep your approach, you would have to modify the uninstaller to programmatically identify the original account and remove the Uninstall registry entry:

const
  { Can use #SetupSetting('AppId') [in curly brackets], }
  { if AppId directive is specified in [Setup] section }
  AppId = 'My Program'; 

procedure RemoveNonAdminUninstallKeys;
var
  Subkeys: TArrayOfString;
  Subkey: string;
  UninstallerLocation: string;
  UninstallKey: string;
  InstallLocation: string;
  I: Integer;
begin
  UninstallerLocation := 
    AddBackslash(ExtractFilePath(ExpandFileName(ExpandConstant('{uninstallexe}'))));
  Log(Format('Uninstalling from "%s"', [UninstallerLocation]));

  RegGetSubkeyNames(HKU, '', Subkeys);

  for I := 0 to GetArrayLength(Subkeys) - 1 do
  begin
    Subkey := Subkeys[I];
    Log(Format('Testing account "%s"', [Subkey]));

    UninstallKey :=
      Subkey + '\Software\Microsoft\Windows\CurrentVersion\Uninstall\' +
      AppId + '_is1';

    { Would be more appropriate to compare "uninstallexe" against a path }
    { in UninstallString, but that would require more complicated parsing. }
    { Using InstallLocation is easier, and safe, }
    { as long as UninstallFilesDir has its default value of "app" }
    if RegQueryStringValue(HKU, UninstallKey, 'InstallLocation', InstallLocation) then
    begin
      InstallLocation := AddBackslash(ExpandFileName(InstallLocation));
      Log(Format('Checking installation location "%s"', [InstallLocation]));
      if CompareText(InstallLocation, UninstallerLocation) = 0 then
      begin
        Log(Format('Installation location matches, deleting Uninstall key "%s"', [
          UninstallKey]));
        if RegDeleteKeyIncludingSubkeys(HKU, UninstallKey) then
        begin
          Log(Format('Uninstall key "%s" deleted', [UninstallKey]));
        end
          else
        begin
          MsgBox(Format('Failed to delete Uninstall key "%s"', [UninstallKey]),
            mbError, MB_OK);
        end;
        Break; { Do not try other acccounts }
      end;
    end;
  end;
end;

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
  if CurUninstallStep = usPostUninstall then
  begin
    if IsAdminLoggedOn then
    begin
      Log('Administrator uninstallation, ' +
          'will try to detect if uninstalling non-administrator installation');
      RemoveNonAdminUninstallKeys;
    end;
  end;
end;