ab-tools
ab-tools

Reputation: 548

Inno Setup: Keep existing 32-bit installation path for upgrades, use 64-bit path for new installations

Our application now supports 64-bit natively and therefore should be installed below the C:\Program Files directory by default. For that reason we set these two directives:

ArchitecturesInstallIn64BitMode=x64
DefaultDirName={pf}\{#ProductName}

This works without any issues so far!

The problem is that we do have a lot existent installations of our product when it was still 32-bit only and therefore correctly installed below C:\Program Files (x86).

Normally Inno Setup detects an existent installation and uses the same installation path, if it finds one. But this seems not to work when changed from 32-bit to 64-bit mode - probably because now a different uninstall registry key is used.

Is there still a way to tell Inno Setup to use the existent 32-bit installation path, if the application was installed already (to perform an update) and only use the 64-bit one if it is a new installation?

Upvotes: 5

Views: 681

Answers (1)

Martin Prikryl
Martin Prikryl

Reputation: 202652

I do not think you can have Inno Setup do this for you automatically.

But you can copy the 32-bit registry key to 64-bit when initializing the installer, to allow Inno Setup find it. Of course, you have to rollback the copy, if the installation is cancelled.

#define AppId "My Program"

[Setup]
AppId={#AppId}
DefaultDirName={pf}\My Program
ArchitecturesInstallIn64BitMode=x64
[Code]

const
  UninstallKey =
    'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{#AppId}_is1';

var
  Rollback64Key: Boolean;
  RootKey32: Integer;
  RootKey64: Integer;

procedure Copy32BitUninstallKeyTo64bit;
var
  I: Integer;
  ValueNames: TArrayOfString;
  ValueName: string;
  ValueStr: string;
  ValueDWord: Cardinal;
  Success: Boolean;
begin
  if RegKeyExists(HKCU64, UninstallKey) or
     RegKeyExists(HKLM64, UninstallKey) then
  begin
    Log('64-bit uninstall key found, leaving as it is');
  end
    else
  begin
    if RegKeyExists(HKCU32, UninstallKey) then
    begin
      Log('32-bit HKCU uninstall key found, will copy it to the 64-bit key');
      RootKey32 := HKCU32;
      RootKey64 := HKCU64;
    end
      else
    if RegKeyExists(HKLM32, UninstallKey) then
    begin
      Log('32-bit HKLM uninstall key found, will copy it to the 64-bit key');
      RootKey32 := HKLM32;
      RootKey64 := HKLM64;
    end
      else
    begin
      Log('No 32-bit uninstall key found');
      RootKey32 := 0;
      RootKey64 := 0;
    end;
    
    if RootKey32 <> 0 then
    begin
      if not RegGetValueNames(RootKey32, UninstallKey, ValueNames) then
      begin
        Log('Cannot list 32-bit uninstall key values');
      end
        else
      begin
        I := 0;
        Success := True;
        while (I < GetArrayLength(ValueNames)) and Success do
        begin
          ValueName := ValueNames[I];
          if RegQueryStringValue(
               RootKey32, UninstallKey, ValueName, ValueStr) then
          begin
            if not RegWriteStringValue(
                     RootKey64, UninstallKey, ValueName, ValueStr) then
            begin
              Log(Format('Error copying "%s" string value', [ValueName]));
              Success := False;
            end
              else
            begin
              Log(Format('Copied "%s" string value', [ValueName]));
            end;
          end
            else
          if RegQueryDWordValue(
               RootKey32, UninstallKey, ValueName, ValueDWord) then
          begin
            if not RegWriteDWordValue(
                     RootKey64, UninstallKey, ValueName, ValueDWord) then
            begin
              Log(Format('Error copying "%s" dword value', [ValueName]));
              Success := False;
            end
              else
            begin
              Log(Format('Copied "%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]));
            Success := False;
          end;

          I := I + 1;
        end;

        if Success then
        begin
          Log('Copied 32-bit uninstall key to 64-bit');
          Rollback64Key := True;
        end
          else
        begin
          if not RegDeleteKeyIncludingSubkeys(RootKey64, UninstallKey) then
          begin
            Log('Failed to copy 32-bit uninstall key to 64-bit, ' +
                'and also failed to rollback the changes');
          end
            else
          begin
            Log('Failed to copy 32-bit uninstall key to 64-bit, ' +
                'rolled back the changes');
          end;
        end;
      end;
    end;
  end;
end;

function InitializeSetup(): Boolean;
begin
  if IsWin64 then
  begin
    Copy32BitUninstallKeyTo64bit;
  end;

  Result := True;
end;

procedure CurStepChanged(CurStep: TSetupStep);
begin
  if CurStep = ssPostInstall then
  begin
    if Rollback64Key then
    begin
      Log('Installation finished, removing obsolete 32-bit key');
      Rollback64Key := False;

      if not RegDeleteKeyIncludingSubkeys(RootKey32, UninstallKey) then
      begin
        Log('Failed to remove obsolete 32-bit uninstall key');
      end
        else
      begin
        Log('Removed obsolete 32-bit uninstall key');
      end;
    end;
  end;
end;

procedure DeinitializeSetup();
begin
  if Rollback64Key then
  begin
    Log('Installation cancelled, rolling back cloned 64-bit uninstall key');

    if not RegDeleteKeyIncludingSubkeys(RootKey64, UninstallKey) then
    begin
      Log('Failed to roll back cloned 64-bit uninstall key');
    end
      else
    begin
      Log('Rolled back cloned 64-bit uninstall key');
    end;
  end;
end;

(Needs Unicode version of Inno Setup – The only version as of Inno Setup 6)

Upvotes: 5

Related Questions