Inno Download Plugin - how detect modal buttons? - inno-setup

For our purposes, we decided to use Inno Download Plugin and Inno Setup version 6.2.0
We switched the installer to silent mode to get rid of unnecessary windows and buttons. It turned out somehow like this (I don’t attach idp.iss, it’s unchanged)
[code]https://pastebin.com/g7xb6iWj
Everything works fine, but there are a couple of but:
1 There is a Downloading window called by IDP, click on the cross to close the window and in the modal window that appears, confirm with Yes
Instead of aborting the download, it tries to proceed with the installation and creates shortcuts
2 There is a Downloading window called by IDP, turn off wifi, in the modal window that appears where they say "Internet is gone" and ask "Retry or Cancel?" click Cancel
Instead of aborting the download, it tries to proceed with the installation and creates shortcuts
I found an explanation here
Exit from Inno Setup installation from [Code]
But I can't figure out exactly how to catch buttons in specific modal windows.
And if I'm not mistaken, the second interrupt case is not native and only applies to IDP
Any ideas to right cancelation of installation of those 2 cases would be great.

My friend did a solution
procedure CurPageChanged(CurPageID: Integer);
begin
WizardForm.Bevel1.Visible := false;
WizardForm.MainPanel.Visible := false;
WizardForm.InnerNotebook.Top := 50;
WizardForm.OuterNotebook.height := 400;
if CurPageID = wpInstalling then begin
Downloaded := idpFilesDownloaded();
if not(Downloaded) then begin
ExitProcess(553);
end;
end;
end;
procedure CancelButtonClick(CurPageID: Integer; var Cancel, Confirm: Boolean);
begin
if Cancel = True then begin
ExitProcess(554);
end;
end;

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.

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?

Run installation using Inno Setup silently without any Next button or Install button

I want my installation should be silent without any Next or Install buttons clicked by the user. I tried to disable all pages still, I am getting the "Ready to Install" page. I want avoid this install page.
To run an installer built in Inno Setup without any interaction with the user or even without any window, use the /SILENT or /VERYSILENT command-line parameters:
Instructs Setup to be silent or very silent. When Setup is silent the wizard and the background window are not displayed but the installation progress window is. When a setup is very silent this installation progress window is not displayed. Everything else is normal so for example error messages during installation are displayed and the startup prompt is (if you haven't disabled it with DisableStartupPrompt or the '/SP-' command line option explained above).
You may also consider using the /SUPPRESSMSGBOXES parameter.
If you want to make your installer run "silently" without any additional command-line switches (what is imo very wrong approach), you can:
Use the ShouldSkipPage event function to skip most pages.
Use a timer to skip the "Ready to Install" page (which cannot be skipped using the ShouldSkipPage). You can use the technique shown in How to close finished Inno Setup installer after a certain time?
[Code]
function ShouldSkipPage(PageID: Integer): Boolean;
begin
Result := True;
end;
function SetTimer(hWnd, nIDEvent, uElapse, lpTimerFunc: LongWord): LongWord;
external 'SetTimer#User32.dll stdcall';
function KillTimer(hWnd, nIDEvent: LongWord): LongWord;
external 'KillTimer#User32.dll stdcall';
var
SubmitPageTimer: LongWord;
procedure KillSubmitPageTimer;
begin
KillTimer(0, SubmitPageTimer);
SubmitPageTimer := 0;
end;
procedure SubmitPageProc(
H: LongWord; Msg: LongWord; IdEvent: LongWord; Time: LongWord);
begin
WizardForm.NextButton.OnClick(WizardForm.NextButton);
KillSubmitPageTimer;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = wpReady then
begin
SubmitPageTimer := SetTimer(0, 0, 100, CreateCallback(#SubmitPageProc));
end
else
begin
if SubmitPageTimer <> 0 then
begin
KillSubmitPageTimer;
end;
end;
end;
For CreateCallback function, you need Inno Setup 6. If you are stuck with Inno Setup 5, you can use WrapCallback function from InnoTools InnoCallback library.
Another approach is to send CN_COMMAND to the Next button, as shown here: How to skip all the wizard pages and go directly to the installation process?
Another option (with its own caveats) is respawning the installer with the /[VERY]SILENT switch. You can use the technique described here:
Inno Setup specify log name within the installer
For a similar question with different answers, see How to make the silent installation by using Inno Setup?

How to call an exe when Inno Setup installation fails (within the installer itself)?

I've been using Inno Setup for several months now, but I'm struggling to find how to detect, from within the installer itself, an error that would cause Inno Setup to end with a non-zero exit code.
I've thought about using CurStepChanged with the ssDone step, or even DeinitializeSetup, but I can't find how to get access to the wizard's exit-code.
Did I miss something? There must be a way to do it...
I'd like to know if anything went wrong so that I can start a rollback procedure on the machine. Your proposed answer did the trick.
You cannot find out installer exit code from the Pascal Scripting.
If you want to detect that the installer failed, remember if CurStepChanged was called with ssDone and test that in DeinitializeSetup.
var
Succeeded: Boolean;
procedure DeinitializeSetup();
begin
if Succeeded then
begin
Log('Installation succeeded');
end
else
begin
Log('Installation failed');
end;
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssDone then
begin
Succeeded := True;
end;
end;
There are edge cases, when ssDone is used even, if the installer fails.
For example, when it fails because a machine was not restarted to complete the previous installation. In this case the CurStepChanged is not called with ssPostInstall. So you may want to check for both steps, if this scenario can happen in your installer.

How to change order of pages in InnoSetup?

I would like to swap the SelectDir page with the Components page in my setup.
I found a solution where the content of the other page is assigned to the current page.
Procedure CurPageChanged(CurPageID: Integer);
Begin
Case CurPageID of
wpSelectDir:
begin
WizardForm.SelectDirPage.Notebook.ActivePage:= WizardForm.SelectComponentsPage;
WizardForm.PageNameLabel.Caption:= SetupMessage(msgWizardSelectComponents)
WizardForm.Hint:= WizardForm.PageDescriptionLabel.Caption;
WizardForm.PageDescriptionLabel.Caption:= SetupMessage(msgSelectComponentsDesc)
end;
wpSelectComponents:
begin
WizardForm.SelectComponentsPage.Notebook.ActivePage:= WizardForm.SelectDirPage;
WizardForm.DiskSpaceLabel.Caption:= WzardForm.ComponentsDiskSpaceLabel.Caption;
WizardForm.PageNameLabel.Caption:= SetupMessage(msgWizardSelectDir)
WizardForm.PageDescriptionLabel.Caption:= WizardForm.Hint
end;
end;
End;
The problem using this method is that only the content but not the actual page is changed. Message boxes and error messages are not affected. I wrote many lines of code to work around these problems but I encounter more and more problems...
Is there a better solution? I hope you can help me!
Edit: After experimenting a bit I came up with this:
procedure RedesignWizard;
var
Page: TWizardPage;
begin
Page := CreateCustomPage(wpWelcome, 'bla', 'bla');
WizardForm.ComponentsList.Parent := Page.Surface;
//Here I am changing the layout of the pages...
end;
procedure InitializeWizard;
begin
RedesignWizard;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
if (CurPageID = Page.ID) then
begin
//perform your actions specific to the Custom page here.
end;
end;
This way the components list appears before the SelctDirPage and I do not have any more problems with those message boxes.
There is absolutely no way to safely swap the order of any of the builtin pages. (And usually, the only time people ask is when they are trying to replicate the flow of a different installation system. Relax and let it go; Inno works differently, embrace it instead of fighting it.)
Having said that, it is possible to give the appearance of swapping the pages, by recreating one or the other of them as a custom page. However by doing this you will forfeit all of the built-in functionality associated with that page -- eg. if you replace the components page then you cannot use the [Components] section or parameters, and if you replace the directory page then you cannot use {app} (not even in those places that use it implicitly, such as the UninstallFilesDir).
If you're willing to put in a lot of time and effort (especially testing), it can be done. But everything is worse off as a result -- so normally you're better off not doing so.
To add to what Miral said:
[Setup]
DisableDirPage=yes // disable the built-in page
[Code]
var
ApacheDirPage: TInputDirWizardPage;
ApacheDir: AnsiString;
procedure InitializeWizard;
begin
{ Create the custom wizard pages }
ApacheDirPage :=
CreateInputDirPage( wpSelectComponents, // display AFTER select Type/Components page
'Select Apache Directory',
'Select the Apache x.x Directory' + #13#10 + '(the one that contains the BIN folder)',
'Select the Apache directory, then click Next.',
False, '' );
ApacheDirPage.Add( '');
ApacheDirPage.Values[0] := csApacheLocation;
end;

Resources