Running code only after successful uninstallation in Inno Setup - inno-setup

Is it possible to handle event when user clicks NO in uninstallation confirmation prompt?
And if NO is clicked, don't execute DeinitializeUninstall() ?
Or is it possible to handle NO button from DeinitializeUninstall() function?
Basically, I wont to avoid DelTree here:
procedure DeinitializeUninstall();
begin
{ if we are running in /SILENT mode, then this is an overinstall - }
{ don't delete additional folder}
if not UninstallSilent() then
begin
DelTree(ExpandConstant('{#BSPLOC}'),True, True, True);
end;
end;

I believe your logic is wrong. It looks like XY problem.
I do not think, that you want to detect "No". I believe, you want to run the code during or after uninstallation.
So use an event function that matches your requirements. The function is CurUninstallStepChanged. And depending on when you exactly need the code to run, check for a corresponding value of CurUninstallStep argument (usUninstall, usPostUninstall or usDone).
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep = usDone then
begin
{ ... }
end;
end;
For similar questions, see:
Inno Setup: Conditionally delete non-empty directory in user's home folder
How to save a folder when user confirms uninstallation? (Inno Setup)
Ntb, it also seems that you abuse the /SILENT switch to detect if the uninstaller is run automatically as part of some process (upgrade?). What if the user runs the uninstaller silently him/herself? You should add another custom switch to signal the automatic run. But that's another question.

Related

Inno Setup close already open application without user interaction [duplicate]

Referring to the question Basic or Advanced installation mode choice to skip or use advanced options pages, I need to skip the Preparing to Install wizard page now.
In my case this page is displayed because one or more programs are using files that need to be replaced by the installer; so the installer asks to the user if they want the setup to automatically close the applications and restart at the end of the setup.
I need that this page is hide from the setup process in Basic mode, and if some files are used, that the setup automatically closes the applications using them without asking anything to the user.
I've tried editing ShouldSkipPage as:
function ShouldSkipPage(PageID: Integer): Boolean;
begin
{ If "Basic" mode is selected, skip Directory and Components pages }
Result :=
ModePage.Values[0] and
((PageID = wpSelectDir) or (PageID = wpSelectComponents) or (PageID = wpReady) or (PageID = wpPreparing));
end;
adding (PageID = wpPreparing) but the page still displayed in Basic mode.
Is there a way to implement this using Inno Setup?
ShouldSkipPage event is not even called for wpPreparing. That page is not to be skipped.
If you still want to skip it, you have to use hacks like these:
How to skip all the wizard pages and go directly to the installation process?
Inno Setup - How to close finished installer after a certain time?
With the first approach, your code would look like:
[Code]
const
BN_CLICKED = 0;
WM_COMMAND = $0111;
CN_BASE = $BC00;
CN_COMMAND = CN_BASE + WM_COMMAND;
procedure CurPageChanged(CurPageID: Integer);
var
Param: Longint;
begin
{ If Basic mode is selected, skip Preparing page }
if (CurPageID = wpPreparing) and ModePage.Values[0] then
begin
Param := 0 or BN_CLICKED shl 16;
PostMessage(WizardForm.NextButton.Handle, CN_COMMAND, Param, 0);
end;
end;
Just don't do that. Ever. It is absolutely unacceptable for you to close an arbitrary list of applications without prompting the user. It's equally impolite to barrel ahead and then require a reboot at the end of the install. (It's unforgivable to then trigger the reboot without asking.)
What you can do is to put some code in the PrepareToInstall [Code] function which will automatically close your application. This executes before the user is prompted to close apps, so if it was only your apps involved then they will not be prompted.

Allow only one instance of Inno Setup without prompting

I need to allow only one instance of Inno Setup. I used SetupMutex, but when I run the second setup it will prompt the user. I need the setup do nothing and close without any prompt, if another instance is running.
I do not think that what you are trying to do is an improvement to a user experience, quite on the contrary, anyway...
Remove your SetupMutex directive and use this code instead:
[Code]
const
SetupMutexName = 'MyProgSetup';
function InitializeSetup(): Boolean;
begin
Result := True;
if CheckForMutexes(SetupMutexName) then
begin
Log('Mutex exists, setup is running already, silently aborting');
Result := False;
end
else
begin
Log('Creating mutex');
CreateMutex(SetupMutexName);
end;
end;
(There's a negligible chance for a race condition between CheckForMutexes and CreateMutex)

Inno Setup uninstaller: An attempt was made to access WizardForm before it has been created

I've a problem with WizardForm's, when I trying to uninstall the program I have this error:
Runtime Error:
Internal error: An attempt was made to access WizardForm before it has been created.
I need to create soft abort uninstallation process with loop (e.g. when application is running and user run the uninstall, program must check processes and if application is running, notify user and if user press the cancel button the program abort uninstallation), I've tried with ExitProcess(0); but it isn't gentle.
Code section:
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
case CurUninstallStep of
usUninstall:
begin
if MsgBox('Close the {#AppName}, before uninstallation.', mbConfirmation, MB_YESNO) = IDYES then
begin
{ user clicked Yes }
end
else
begin
MsgBox('Error',mbError,MB_OK);
CancelWithoutPrompt := true;
{ ExitProcess(0); }
WizardForm.close;
end
end;
end;
end;
Your approach to implementing your problem is wrong, see at the end.
Anyway, to address your immediate issue: The WizardForm is an installer form. It does not exist in an uninstaller. In the uninstaller, you have UninstallProgressForm. See documentation.
But you do not want to call UninstallProgressForm.Close. That's wrong for the reasons given below.
Inno Setup has a built-in mechanism to prevent an (un)installer from proceeding, while an application is running. The AppMutex directive.
Even if you want to build your own solution, use the InitializeUninstall event function, where you can exit the uninstaller easily and cleanly, by returning False. And you can, of course, display any message you like, before you exit. Just use MsgBox function.
All this is covered in my answer to Uninstall fails because program is running. How do I make Inno Setup check for running process prior to attempting delete?

AppMutex with Inno Setup: Wait few seconds before prompt

Using Inno Setup together with an AppMutex works fine - when the setup is started and the mutex still exits, the user is prompted to close this application.
But following question:
Is there a way to tell Inno Setup to wait 2-3 seconds if the program closes itself before showing the user this prompt?
The reason is that I'm running the Inno Setup from the program itself for auto-update purpose. Directly after the setup file is executed the program closes itself, but obviously that takes too long (at least on some systems). So Inno Setup shows this - in this case - useless dialog to the user although the program is closing itself already.
Therefore I would like to accomplish that Inno Setup waits 2-3 seconds and only if the mutex still exists after that time it should show the prompt to the user.
Is there a way to accomplish this?
With such requirement, you cannot use the built-in AppMutex directive.
You have to implement the mutex check yourself using CheckForMutexes function in a loop, as you have been suggested to in your previous question:
[Code]
const
MutexName = 'MutexName';
function InitializeSetup: Boolean;
var
WaitInterval: Integer;
Wait: Integer;
begin
Wait := 3000;
WaitInterval := 250;
while (Wait > 0) and CheckForMutexes(MutexName) do
begin
Log('Application is still running, waiting');
Sleep(WaitInterval);
Wait := Wait - WaitInterval;
end;
while CheckForMutexes(MutexName) do
begin
if MsgBox(
FmtMessage(SetupMessage(msgSetupAppRunningError), ['MyApplication']),
mbError, MB_OKCANCEL) <> IDOK then
begin
Abort;
end;
end;
Result := True;
end;

How to get Inno setup to display message with only a cancel button so the install stops

I'm using Inno setup to deliver a software package. It detects the version of Access and pops up a message. I want to make the message tell the user they have downloaded the wrong version and halt the installation. Currently the Inno script uses
itd_downloadafter(NoRuntimePage.ID);
to display a message telling the user they need the AccessRuntime installed. When they user presses next it downloads the AccessRuntime and continues. I want to change this for my new script to tell the user they have the wrong version and then end the install script when they press next or just cancel. Can anyone help me abit on this?
Why to use InitializeSetup ?
If you want to conditionally exit the setup before the wizard starts, don't use InitializeWizard event function with the Abort exception raise. You'll be wasting your time, needed to create the whole wizard form. Use the InitializeSetup event function instead. There you can raise the Abort exception or better return False to its boolean result, and exit the function as was supposed to do - the final effect will be definitely the same.
Internally, the InitializeSetup function, raises just this Abort exception, when you return False to it from your script. Contrary to InitializeWizard event, when the InitializeSetup event is fired, the wizard form is not created yet, so you won't be wasting your time and never used system resources.
Code example:
In the following pseudo-code you need to have a function like UserDownloadedWrongVersion where, if you return True, the setup will be terminated, nothing happens oterwise.
[Code]
function UserDownloadedWrongVersion: Boolean;
begin
// make your check here and return True when you detect a wrong
// version, what causes the setup to terminate; False otherwise
end;
function InitializeSetup: Boolean;
begin
Result := not UserDownloadedWrongVersion;
if not Result then
begin
MsgBox('You''ve downloaded the wrong version. Setup will now exit!',
mbError, MB_OK);
Exit; // <-- or use Abort; instead, but there's no need for panic
end;
end;
** TLama's answer is more accurate. **
You could use the InitializeWizard procedure to run the access check at the beginning... if it fails you should be able to show your message box then call Abort() .
[code]
var CustomPage: TInputQueryWizardPage;
procedure InitializeWizard;
begin;
{your checking Access version and message box}
Abort();
end;

Resources