Execute a command after uninstall - inno-setup

I need my uninstall to run a command after it's removed the files it has installed.
[UninstallRun] is no use as I understand it runs BEFORE files are removed.
I kind of need a "postuninstall" flag.
Any suggestions as to how I can accomplish the above?

See "Uninstall Event Functions" in the documentation. You can use for instance CurUninstallStepChanged when 'CurUninstallStep' is 'usPostUninstall'.

In the same way there is a [Run] section, Inno allows to you to define an [UninstallRun] section to specify which files of your Installer package should be executed on unistall.
For example:
[UninstallRun]
Filename: {app}\Scripts\DeleteWindowsService.bat; Flags: runhidden;
Alternatively, solution proposed by #Sertac Akyuz, which makes use of event functions can be used for tunning a bit more unistalling actions. Here is an example of the usage of CurUninstallStepChanged function among other related functions.
https://github.com/HeliumProject/InnoSetup/blob/master/Examples/UninstallCodeExample1.iss
; -- UninstallCodeExample1.iss --
;
; This script shows various things you can achieve using a [Code] section for Uninstall
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
DefaultGroupName=My Program
UninstallDisplayIcon={app}\MyProg.exe
OutputDir=userdocs:Inno Setup Examples Output
[Files]
Source: "MyProg.exe"; DestDir: "{app}"
Source: "MyProg.chm"; DestDir: "{app}"
Source: "Readme.txt"; DestDir: "{app}"; Flags: isreadme
[Code]
function InitializeUninstall(): Boolean;
begin
Result := MsgBox('InitializeUninstall:' #13#13 'Uninstall is initializing. Do you really want to start Uninstall?', mbConfirmation, MB_YESNO) = idYes;
if Result = False then
MsgBox('InitializeUninstall:' #13#13 'Ok, bye bye.', mbInformation, MB_OK);
end;
procedure DeinitializeUninstall();
begin
MsgBox('DeinitializeUninstall:' #13#13 'Bye bye!', mbInformation, MB_OK);
end;
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
case CurUninstallStep of
usUninstall:
begin
MsgBox('CurUninstallStepChanged:' #13#13 'Uninstall is about to start.', mbInformation, MB_OK)
// ...insert code to perform pre-uninstall tasks here...
end;
usPostUninstall:
begin
MsgBox('CurUninstallStepChanged:' #13#13 'Uninstall just finished.', mbInformation, MB_OK);
// ...insert code to perform post-uninstall tasks here...
end;
end;
end;

Related

Inno Setup - Avoid displaying filenames of sub-installers

I am trying to use the idea from Inno Setup - How to hide certain filenames while installing? (FilenameLabel)
The only sure solution is to avoid installing the files, you do not want to show, using the [Files] section. Install them using a code instead. Use the ExtractTemporaryFile and FileCopy functions
But the files that I want to hide are using in the [Run] Section:
[Files]
Source: "_Redist\DXWebSetup.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall
[Run]
Filename: "{tmp}\DXWebSetup.exe"; Components: DirectX; StatusMsg: "Installing DirectX..."; \
BeforeInstall: StartWaitingForDirectXWindow; AfterInstall: StopWaitingForDirectXWindow
How to hide (while installing, in filenamelabel) using [Files] section, ExtractTemporaryFile and FileCopy functions?
The easiest is to give up on the standard [Files] and [Run] sections and code everything on your own in the CurStepChanged event fuction:
[Files]
Source: "dxwebsetup.exe"; Flags: dontcopy
[Code]
procedure CurStepChanged(CurStep: TSetupStep);
var
ProgressPage: TOutputProgressWizardPage;
ResultCode: Integer;
begin
if CurStep = ssInstall then { or maybe ssPostInstall }
begin
if IsComponentSelected('DirectX') then
begin
ProgressPage := CreateOutputProgressPage('Installing prerequsities', '');
ProgressPage.SetText('Installing DirectX...', '');
ProgressPage.Show;
try
ExtractTemporaryFile('dxwebsetup.exe');
StartWaitingForDirectXWindow;
Exec(ExpandConstant('{tmp}\dxwebsetup.exe'), '', '', SW_SHOW,
ewWaitUntilTerminated, ResultCode);
finally
StopWaitingForDirectXWindow;
ProgressPage.Hide;
end;
end;
end;
end;
This even gives you a chance to check for results of the sub-installer. And you can e.g. prevent the installation from continuing, when the sub-installer fails or is cancelled.
Then it's easier to use the PrepareToInstall instead of the CurStepChanged.
Another option is to display a custom label, while extracting the sub-installer.
See Inno Setup - How to create a personalized FilenameLabel with the names I want?

How to process Registry section prior the Run section?

I have noticed that the [Registry] section is processed after the [Run] section. How can I make the [Registry] section to be processed before the [Run] section ?
You can use CurStepChanged procedure to add Registry Entries at the very beginning of installing files.
As an example:
[Code]
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssInstall then begin
RegWriteStringValue(HKEY_CURRENT_USER, 'Software\My Company\My Program',
'UserName', ExpandConstant('{sysuserinfoname}'));
end;
end;
You are mistaken. The [Registry] section is installed prior to the [Run] section. See the Installation Order help topic.

Call exe in Inno Setup uninstall

I have an issue with the Inno Setup uninstaller. I have a exe file I want to executable to keep track of the installation and uninstallations. The exe is really simple and sends a message to a server.
[Files]
Source: "Tracker\LocalSandboxInstallTracker.exe"; DestDir: "{app}/Tracker";
Source: "Tracker\LocalSandboxInstallTracker.exe.config"; DestDir: "{app}/Tracker";
Source: "Tracker\Tracker.Client.dll"; DestDir: "{app}/Tracker";
[Run]
Filename: "{app}\Tracker\LocalSandboxInstallTracker.exe"; Parameters: " {#MyAppVersion} install"; Flags: runhidden; StatusMsg: "Sending tracking data..."
[Code]
procedure InitializeUninstallProgressForm();
var
ResultCode: Integer;
begin
Exec ('{app}\Tracker\LocalSandboxInstallTracker.exe',' {#MyAppVersion} uninstall','',SW_SHOW, ewWaitUntilTerminated, ResultCode);
end;
The call at the installation works well, but not at the uninstall. I placed a breakpoint to my Exec command and it really goes through there, but the exe does not seem to be called.
You must expand the {app} constant before passing it to the Exec script function. Use the ExpandConstant whenever you need to get the value of the constant. Modify your script this way:
Exec(ExpandConstant('{app}\Tracker\LocalSandboxInstallTracker.exe'),
'{#MyAppVersion} uninstall', '', SW_SHOW,
ewWaitUntilTerminated, ResultCode);
Also, you should check the function result and the output result code to react when the Exec function fails. The error code you'll get in the ResultCode you can check against the System Error Codes reference or use SysErrorMessage(ResultCode) to get the error description from script.
You have to call the ExpandConstant function if you want to use constants like {app} in your Exec call:
[Code]
procedure InitializeUninstallProgressForm();
var
ResultCode: Integer;
begin
Exec (ExpandConstant('{app}\Tracker\LocalSandboxInstallTracker.exe')
,' {#MyAppVersion} uninstall','',SW_SHOW, ewWaitUntilTerminated, ResultCode);
end;
Other way, you're failing to locate the exe.

How to rename a file using inno setup

I want to first rename an existing file 'My program old' to 'My program v2' but only if 'My program v2' doesn't already exist.
Then I want to rename 'My program' to 'My program old' but only if 'My program old' doesn't already exist.
And then I want to install 'My program' from the installer but only if 'My program' doesn't already exist.
I would be very grateful for any guidance !
I would give a try to something like this. In the ssInstall stage of the CurStepChanged event, which occurs just before the installation process starts, just check if the file doesn't exist with the FileExists function, and if not, then just call the RenameFile function, which will silently fail if the source file doesn't exist, so you don't need to care if the source file exists. In the [Files] section you can then use the onlyifdoesntexist flag for your last requirement. You can follow the commented version of this script if you want:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
[Files]
Source: "My program"; DestDir: "{app}"; Flags: onlyifdoesntexist
[Code]
function GetFileName(const AFileName: string): string;
begin
Result := ExpandConstant('{app}\' + AFileName);
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if (CurStep = ssInstall) then
begin
if not FileExists(GetFileName('My program v2')) then
RenameFile(GetFileName('My program old'), GetFileName('My program v2'));
if not FileExists(GetFileName('My program old')) then
RenameFile(GetFileName('My program'), GetFileName('My program old'));
end;
end;

Inno Setup: Install file from Internet

I am using Inno Setup to distribute my application.
Is it possible to check in Inno Script for a particular condition and download and install some file from internet if required.
Inno Setup 6.1 and newer has a built-in support for downloads. No 3rd party solution are needed anymore.
Check the Examples\CodeDownloadFiles.iss in Inno Setup installation folder.
The important parts of the example are:
[Files]
; These files will be downloaded
Source: "{tmp}\innosetup-latest.exe"; DestDir: "{app}"; Flags: external
Source: "{tmp}\ISCrypt.dll"; DestDir: "{app}"; Flags: external
[Code]
var
DownloadPage: TDownloadWizardPage;
function OnDownloadProgress(const Url, FileName: String; const Progress, ProgressMax: Int64): Boolean;
begin
if Progress = ProgressMax then
Log(Format('Successfully downloaded file to {tmp}: %s', [FileName]));
Result := True;
end;
procedure InitializeWizard;
begin
DownloadPage := CreateDownloadPage(SetupMessage(msgWizardPreparing), SetupMessage(msgPreparingDesc), #OnDownloadProgress);
end;
function NextButtonClick(CurPageID: Integer): Boolean;
begin
if CurPageID = wpReady then begin
DownloadPage.Clear;
DownloadPage.Add('https://jrsoftware.org/download.php/is.exe', 'innosetup-latest.exe', '');
DownloadPage.Add('https://jrsoftware.org/download.php/iscrypt.dll', 'ISCrypt.dll', '2f6294f9aa09f59a574b5dcd33be54e16b39377984f3d5658cda44950fa0f8fc');
DownloadPage.Show;
try
try
DownloadPage.Download;
Result := True;
except
SuppressibleMsgBox(AddPeriod(GetExceptionMessage), mbCriticalError, MB_OK, IDOK);
Result := False;
end;
finally
DownloadPage.Hide;
end;
end else
Result := True;
end;
For alternatives, see Running a program after it is downloaded in Code section in Inno Setup
Inno Download Plugin by Mitrich Software.
It's an InnoSetup script and DLL, which allows you to download files as part of your installation.
It supports FTP, HTTP and HTTPS.
It's kind of a drop-in replacement for InnoTools Downloader. Only few changes required.
It brings a decent download display and HTTPS and Mirror(s) support.
Example:
#include <idp.iss>
[Files]
Source: "{tmp}\file.zip"; DestDir: "{app}"; Flags: external; ExternalSize: 1048576
[Code]
procedure InitializeWizard();
begin
idpAddFileSize('http://127.0.0.1/file.zip', ExpandConstant('{tmp}\file.zip'), 1048576);
idpDownloadAfter(wpReady);
end.
Yes, there is a library called InnoTools Downloader which has samples that do pretty much this. They can be conditioned on anything you want using normal Inno code.
Found on Inno 3rd Party is one very similar in scope and style to the Inno Download Plugin, DWinsHs.
Included with an easy and intuitive chm file which requires unblocking to view.

Resources