I use a side-by-side installation of my software where each new version is installed into a separate folder, for example MySoftware2
, MySoftware3
etc. This was not a good idea and I would like to move to a single folder installation where all installations and updates would be into MySoftware
folder (without version numbers).
For all fresh installs the folder would be
DefaultDirName={pf}\MySoftware
But what about the auto updates from the previous versions of the software (for example from v3 to v4)? I guess those should be installed into existing folder (MySoftware3
) and then renamed? How can Inno know the existing folder and could Inno rename the installation directory after the installation?
Any idea how to do this properly? Thanks.
To rename a installation folder, you can use RenameFile
function from CurStepChanged(ssPostInstall)
. That's the easy part.
But you also need to update the uninstall registry information. That's much more work.
Something like this will do.
#define AppId "My Program"
[Setup]
AppId={#AppId}
[Code]
const
OldDirName = 'MySoftware3';
NewDirName = 'MySoftware';
InnoSetupReg =
'Software\Microsoft\Windows\CurrentVersion\Uninstall\{#AppId}_is1';
var
Path, NewPath: string;
RootKey: Integer;
function CheckRegistry(
ValueName: string; var P: Integer; var Value: string): Boolean;
begin
if not RegQueryStringValue(RootKey, InnoSetupReg, ValueName, Value) then
begin
Log(Format('Cannot find uninstall registry value "%s" in key %s', [
ValueName, InnoSetupReg]));
Result := False;
end
else
begin
P := Pos(Lowercase(Path), Lowercase(Value));
Result := (P > 0);
if not Result then
begin
Log(Format(
'Uninstall registry value "%s" in key %s "%s" ' +
'does not contain the installation path "%s"', [
ValueName, InnoSetupReg, Value, Path]));
end;
end
end;
procedure UpdateRegistry(ValueName: string);
var
Value, NewValue: string;
P: Integer;
begin
if CheckRegistry(ValueName, P, Value) then
begin
NewValue :=
Copy(Value, 1, P - 1) +
NewPath +
Copy(Value, P + Length(Path), Length(Value) - P - Length(Path) + 1);
if not RegWriteStringValue(RootKey, InnoSetupReg, ValueName, NewValue) then
begin
Log(Format('Cannot write uninstall registry value "%s" in key %s', [
ValueName, InnoSetupReg]));
end
else
begin
Log(Format('Updated uninstall registry value "%s" from "%s" to "%s"', [
ValueName, Value, NewValue]));
end;
end;
end;
procedure CurStepChanged(CurStep: TSetupStep);
var
Value: string;
P: Integer;
begin
Log(Format('CurStepChanged %d', [CurStep]));
if CurStep = ssPostInstall then
begin
Path := ExpandConstant('{app}');
if CompareText(ExtractFileName(Path), OldDirName) = 0 then
begin
Log(Format(
'Program was installed to old folder name "%s", trying to rename...', [
Path]));
NewPath := ExtractFilePath(Path) + NewDirName;
if IsAdminInstallMode then RootKey := HKLM
else RootKey := HKCU;
if CheckRegistry('UninstallString', P, Value) then
begin
if not RenameFile(Path, NewPath) then
begin
Log('Failed to rename');
end
else
begin
Log('Renamed, updating uninstall registry information...');
UpdateRegistry('UninstallString');
UpdateRegistry('QuietUninstallString');
UpdateRegistry('DisplayIcon');
UpdateRegistry('Inno Setup: App Path');
UpdateRegistry('InstallLocation');
Log('Installation path rename done');
end;
end;
end;
end;
end;
Though note that it relies old name not to be part of the new name, like you have it now (MySoftware3
=> MySoftware
). Otherwise it would keep renaming with every update.