I wanted to use Inno Setup to remove old possible instances of a program. The program does not have to be installed in specific part of the system to run, but I wanted to make up a standard and remove old instances that were just there by copying the files. Since there have been a few changes and I wanted to remove entries from previous installations from the registry (32 and 64 bit installs were possible, so two entries may exist for the same program if you want both installers), I wrote this in the assumption that the installation would start after the PrepareToInstall portion was done running the uninstaller and removing the files.
{ This is the part that is executed after you started the install }
function PrepareToInstall(var NeedsRestart: Boolean): String;
var
ResultCode: integer;
UninstallString: String;
AppId: String;
begin
AppId := '{#SetupSetting("AppId")}';
AppId := Copy(AppId, 2, Length(AppId) - 1);
if (IsWin64 And RegQueryStringValue(HKEY_LOCAL_MACHINE_64, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\'+AppId+'_is1', 'UninstallString', UninstallString)) then begin
Exec(Copy(UninstallString, 2, Length(UninstallString) - 2), '/VERYSILENT', '', SW_HIDE, ewWaitUntilTerminated, ResultCode)
if RegKeyExists(HKEY_LOCAL_MACHINE_64, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\'+AppId+'_is1') then begin
RegDeleteKeyIncludingSubkeys(HKEY_LOCAL_MACHINE_64, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\'+AppId+'_is1')
end;
end;
if (RegQueryStringValue(HKEY_LOCAL_MACHINE_32, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\'+AppId+'_is1', 'UninstallString', UninstallString)) then begin
Exec(Copy(UninstallString, 2, Length(UninstallString) - 2), '/VERYSILENT', '', SW_HIDE, ewWaitUntilTerminated, ResultCode)
if RegKeyExists(HKEY_LOCAL_MACHINE_32, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\'+AppId+'_is1') then begin
RegDeleteKeyIncludingSubkeys(HKEY_LOCAL_MACHINE_32, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\'+AppId+'_is1')
end;
end;
If (DirIsSysLink(ExpandConstant('{app}')) = True) Then begin
RenameFile(ExpandConstant('{app}'), ExpandConstant('{app}_link'));
CreateDir(ExpandConstant('{app}'));
DirectoryCopy(ExpandConstant('{app}_link'), ExpandConstant('{app}'));
DelTree(ExpandConstant('{app}_link'), True, True, True);
End;
If (IsWin64) Then Begin
If (DirExists('C:\Program Files (x86)\TargetProgram')) then begin
CleanupFolder('C:\Program Files (x86)\TargetProgram', 'X86')
If (DirIsSysLink('C:\Program Files (x86)\TargetProgram') = False) Then begin
DelTree('C:\Program Files (x86)\TargetProgram', True, True, True)
end
end;
End;
If (DirExists('C:\Program Files\TargetProgram')) then begin
CleanupFolder('C:\Program Files\TargetProgram', 'X64')
end;
end;
{ Tries to remove existing installations and additional files in the folders that don't belong here before install starts }
function CleanupFolder(Folder: String; Num: String): Boolean;
var
BolTmpVal: Boolean;
FindRec: TFindRec;
FileList: String;
begin
BolCopyFailed := False;
If (DirExists(Folder)) then begin
FileList := '|a.file|b.dll|...|'
if (FindFirst(Folder+'\*', FindRec)) then begin
try
repeat
if (Pos('|'+LowerCase(FindRec.Name)+'|', FileList) <> 0) then begin//this is a file known to be installed later
DeleteFile(Folder+'\'+FindRec.Name);
end Else if ((Pos('unins0', FindRec.Name) = 1) And ((Pos('.exe', FindRec.Name) = 9) OR (Pos('.dat', FindRec.Name) = 9))) Then begin
{Deleting the uninstall files seems to remove the actual installer itself...}
//DeleteFile(Folder+'\'+FindRec.Name);
End Else If ((FindRec.Name = '.') OR (FindRec.Name = '..') OR (LowerCase(FindRec.Name) = 'backup')) Then Begin
// do nothing with main directories or backup folder
end Else begin
//... some copy and paste backup of possible user-files not involved in the problem
end;
until not FindNext(FindRec);
finally
FindClose(FindRec);
end;
end;
end;
end;
If I use this to clear up the old installs, the installation sometimes consists only of 8 of 15 files that should be installed (are defined in the [Files]
and I can see them being added in the compilers output and usually are installed). So my only guess why I get less than 15 files is that the files that should be removed during pre-installation are removed during the install. So the desired cleanup must remove the install files if I am not mistaken. But I cannot find a reason why this is the case.
I thought that the installation itself puts the content in the target-folder after the preparation part. So was I wrong / how do I modify the code so the install is valid? I know I could test this by checking before the installer ends, but I guess it would not be a god practice...
The previous installation that I'm uninstalling was like:
[Files]
Source: "Input\*"; DestDir: "{app}"; \
Flags: ignoreversion recursesubdirs createallsubdirs
[UninstallDelete]
Type: dirifempty; Name: "{app}" Type: dirifempty; Name: "C:\Program Files\A"
[UninstallRun]
Filename: "{sys}\taskkill.exe"; Parameters: "/F /IM a.exe"; Flags:runhidden ; \
StatusMsg: "Closing process"