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

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.

Related

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)

Running code only after successful uninstallation in 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.

Component Exist Message Box too Big - InnoSetup

I have a component list of more than 80 options,where user can select and then install.
The setup remembers the previous install components and automatically checks the Components, Now if user deselects all, the "Component Exist" Warning Message Box is shown.
Because user deselected all 80 options the list becomes to long and the Message box goes out of screen space and user is now stuck.
I know there is NoUninstallWarning in Messages which has the text for the warning message and takes one argument as %1
Is there a way I can change the argument value , rather than having all options listed in indiviual line , I would like to have them as comma separated?
Or if I can have a Scrollbar in the Message box?
Please help
No, this message is internal and you can't customise it like that without modifying Inno's own source code.
In that situation the user shouldn't be completely stuck -- they should be able to press ESC to return to the component selection window and then select everything again.
A simple way to avoid this problem is to not allow the user to deselect components, once installed. You can do this with a bit of code like this:
var
InstalledComponentsDisabled: Boolean;
procedure CurPageChanged(CurPageId: Integer);
var
i: Integer;
begin
if (CurPageId = wpSelectComponents) and
(WizardForm.PrevAppDir <> '') and
not InstalledComponentsDisabled then begin
InstalledComponentsDisabled := True;
for i := 0 to WizardForm.ComponentsList.Items.Count - 1 do begin
if WizardForm.ComponentsList.Checked[i] then begin
WizardForm.ComponentsList.ItemEnabled[i] := False;
end;
end;
end;
end;
This has a similar effect to making anything already installed on upgrades fixed.
An alternate option is to put disablenouninstallwarning on all of your components and then either implement the messagebox completely yourself, add a bit of static text warning about removing components permanently on the page, or even do something to actually support removing components (eg. [InstallDelete] entries or UninsHs).

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 do I know if a restart is needed in InnoSetup script?

TL;DR version:
In an InnoSetup script, how can I detect if a restart is needed because of files that were in use?
More detailed version:
I have an Inno Setup script with the following characteristics:
the ShouldSkipPage function is implemented so that all pages (except the welcome page) are skipped unless a custom "Advanced options" checkbox on the welcome page is checked:
function ShouldSkipPage(PageID: Integer): Boolean;
begin
if ((PageID = wpSelectDir) or
(PageID = wpSelectProgramGroup) or
(PageID = wpSelectTasks) or
(PageID = wpFinished) or
(PageID = wpReady)) then
begin
Result := not advancedCheckBox.Checked;
end;
end;
CloseApplications and RestartApplications are set to false (*), and some files have the restartreplace and uninsrestartdelete flags, so a restart will be required to complete the installation if the files were in use
Now, if a restart is needed, I want to show the Finished page regardless of the state of the "Advanced options" checkbox, because I don't want to cause a restart without prompting the user. So my code would be something like that:
function ShouldSkipPage(PageID: Integer): Boolean;
begin
if ((PageID = wpSelectDir) or
(PageID = wpSelectProgramGroup) or
(PageID = wpSelectTasks) or
(PageID = wpReady)) then
begin
Result := not advancedCheckBox.Checked;
end
else if ((PageID = wpFinished)) then
begin
Result := (not advancedCheckBox.Checked) and (not IsRestartNeeded);
end
end;
Unfortunately, there is no IsRestartNeeded function (NeedRestart exists, but it's an event function). I spent a long time looking at the documentation, but I didn't find any function that could give me this information.
The only option I can think of is to look at HKLM\System\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations to see if it contains any of my files, but it's a rather ugly solution...
(*) The files I want to replace or remove are a shell extension and some DLLs used by this extension. The reason why I'm not relying on the Restart Manager is because it doesn't seem to work with explorer.exe: the process is immediately restarted, and my files are locked again.
The usual recommendation is to call MakePendingFileRenameOperationsChecksum near the start of your installation process, and then again whenever you want to check whether a restart will be required. As long as it keeps returning the same value, a restart is not required.
Note that this won't take into account "forced restarts" eg. from you implementing NeedRestart and returning true or from a component marked with the restart flag; you're expected to be able to figure that out on your own, since you're in control of that.

Resources