Inno Setup - How to skip files depending on radio button - inno-setup

I've only been experimenting with Inno for a few days so forgive my lack of knowledge!
In my Setup script I've added a TInputOptionWizardPage with two options:
Install everything
Only install system files (DLLs etc)
If the user selects the second option, how do I exclude certain files from installing and can I also prevent an icon from being created?

You can write a Check function for conditional installing of certain files. In this function you can decide whether the file should be installed or not depending on the state of your radio buttons. Here is example script which shows, how to conditionally create an icon if the first radio button is selected on the custom options page:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultGroupName=My Program
DefaultDirName={pf}\My Program
[Icons]
Name: "{group}\My Program"; Filename: "calc.exe"; WorkingDir: "{app}"; Check: ShouldInstallIcon
[Code]
var
MyOptionsPage: TInputOptionWizardPage;
procedure InitializeWizard;
begin
MyOptionsPage := CreateInputOptionPage(wpWelcome, 'Caption', 'Description',
'SubCaption', True, False);
MyOptionsPage.Add('Install icon');
MyOptionsPage.Add('Do not install icon');
MyOptionsPage.Values[0] := True;
end;
function ShouldInstallIcon: Boolean;
begin
// here write a condition, which if you return True will process an entry;
// in this example the setup creates the icon if the first radio button is
// selected
Result := MyOptionsPage.Values[0];
end;

Related

Why does the ShouldSkipPage procedure work for the WelcomePage?

In Inno Setup Help the next is written:
I write this code:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
DefaultGroupName=My Program
UninstallDisplayIcon={app}\MyProg.exe
Compression=lzma2
SolidCompression=yes
OutputDir=userdocs:Inno Setup Examples Output
[Files]
Source: "MyProg.exe"; DestDir: "{app}"
Source: "MyProg.chm"; DestDir: "{app}"
Source: "Readme.txt"; DestDir: "{app}"; Flags: isreadme
[Icons]
Name: "{group}\My Program"; Filename: "{app}\MyProg.exe"
[code]
function ShouldSkipPage(PageID: Integer): Boolean;
begin
if PageID = 1 then
Result := True;
end;
and then I press F7 for Step Into mode and what I see is that ShouldSkipPage is immediately called, PageId is 1, the result is True and as a result the WelcomePage is actually skipped.
I've read similar posts about this procedure and that it's called many times etc. but I still don't get it. Looks like Help is wrong.
Does anybody know for sure how this procedure works and why it's called for the WelcomePage ignoring the Help info?
Up-to-date documentation does not list wpWelcome:
function ShouldSkipPage(PageID: Integer): Boolean;
The wizard calls this event function to determine whether or not a particular page (specified by PageID) should be shown at all. If you return True, the page will be skipped; if you return False, the page may be shown.
Note: This event function isn't called for the wpPreparing, and wpInstalling pages, nor for pages that Setup has already determined should be skipped (for example, wpSelectComponents in an install containing no components).
According to version history, this has changed in 5.3.9 (2010-04-10):
Added new [Setup] section directive: DisableWelcomePage to hide the Welcome wizard page. Doing so is recommended by the Aero wizard guidelines. Additionally, the ShouldSkipPage event function is now also called for wpWelcome.
And actually, the current version of Inno Setup does not show that page default at all.
See Welcome page not showing, SelectDir page is showing first instead

Use Inno Setup UI as a self-extractor only - No installation

I use Inno Setup for many "standard" installers, but for this task I need to extract a bunch of temp files, run one of them, then remove them and exit the installer (without actually installing anything).
Basically I'm looking to make a self-extractor with without it being an "installer", and am after the best user experience possible with inno setup.
I have the following code which almost works fine:
[Files]
Source: "dist\*"; Flags: recursesubdirs ignoreversion dontcopy;
[Code]
function InitializeSetup(): Boolean;
var
ResultCode: Integer;
begin
Result := True;
MsgBox('Please wait a minute or two...', mbInformation, MB_OK);
ExtractTemporaryFiles('{tmp}\*');
Exec(ExpandConstant('{tmp}\MyScript.exe'), '', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
Abort();
end;
The problem is that the best I can do here is show a message box "Please wait a minute or two...", the user clicks [Ok], then waits as nothing appears to happen with nothing on-screen at all, then MyScript.exe starts.
What I'd like instead is a Wizard page saying "Please wait as temporary files are extracted..." with a npbstMarquee style progress bar, then is disappears once the files are extracted and my script starts.
I don't think there's a way to tell Inno Setup to display a progress bar while ExtractTemporaryFiles() is going (which would be ideal) and working this into a custom wizard page has got me baffled.
"Install" the files to {tmp}, instead of using ExtractTemporaryFiles;
Execute the files extracted to {tmp} from Run section (or use AfterInstall parameter or CurStepChanged to trigger Pascal Script code after files are installed);
Set Uninstallable to no;
Set CreateAppDir to no;
Use [Messages] section to edit the wizard texts that are too installer-centric for your needs.
[Setup]
Uninstallable=no
CreateAppDir=no
[Files]
Source: "dist\*"; DestDir: {tmp}; Flags: recursesubdirs
[Run]
FileName: "{tmp}\MyScript.exe"
Notes:
The {tmp} folder gets automatically deleted, when the "installer" is closing;
No need for ignoreversion flag, when installing to new empty folder.
A related question: Inno Setup installer that only runs a set of embedded installers
For an answer your literal question, see Inno setup: ExtractTemporaryFile causes wizard freeze. Or a more generic question on the topic: Inno Setup: How to modify long running script so it will not freeze GUI?
It seems that ExtractTemporaryFiles() essentially locks up the UI until it's finished, so there's no way to get a progress bar (or Marquee) animated in here.
Also getting a message on the screen at all while ExtractTemporaryFiles() is in progress was difficult. I solved it like this:
const
WM_SYSCOMMAND = 274;
SC_MINIMIZE = $F020;
//-------------------------------------------------------------------
procedure MinimizeButtonClick();
begin
PostMessage(WizardForm.Handle, WM_SYSCOMMAND, SC_MINIMIZE, 0);
end;
//-------------------------------------------------------------------
procedure CurPageChanged(CurPageID: Integer);
var
ResultCode: Integer;
begin
if CurPageID = wpPreparing then
begin
MinimizeButtonClick();
Exec(ExpandConstant('{tmp}\MyScript.exe'), '', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
end;
end;
//-------------------------------------------------------------------
function NextButtonClick(CurPageID: Integer): Boolean;
var
ProgressPage: TOutputProgressWizardPage;
begin
if CurPageID = wpReady then
begin
ProgressPage := CreateOutputProgressPage('Preparing files...', '');
ProgressPage.Show;
try
ProgressPage.Msg1Label.Caption := 'This process can take several minutes; please wait ...';
ExtractTemporaryFiles('{tmp}\*');
finally
ProgressPage.Hide;
end;
end;
Result := True;
end;
//-------------------------------------------------------------------
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssInstall then
begin
//MinimizeButtonClick() is called here as the Wizard flashes up for a second
// and minimizing it makes that 1/2 a second instead...
MinimizeButtonClick();
Abort();
end;
end;
I then changed the text on the "Ready" page to suit using the [Messages] section.
The result is:
one wizard page asking the user if they want to continue
one wizard page telling the user "please wait..." while the temp files are extracted
once the files are extracted the wizard is hidden and MyScript.exe from the temp folder is run
once MyScript.exe finishes the wizard exits cleanly and deletes the temp files

How to make Inno Setup to show a MsgBox and close it automatically after specified time

How to make Inno Setup show a MsgBox after a application is started at the endm when all files are extracted, and make the MsgBox close itself in, lets say, 5 seconds.
And that MsgBox would say something like "Starting World of Tanks Client v0.8.10".
The following script shows how to start an application without waiting for its execution to be finished and immediately after the application is started show a message box for 5 seconds. For this you will need to use the nowait flag for the [Run] section entry, have an AfterInstall function, and a message dialog which is able to close itself after a time period (I have used the one from this post).
The principle is easy; when the [Run] section entry with your application is processed, the application is started and thanks to nowait flag, the entry is taken as processed immediately after the app starts. And since the AfterInstall trigger function is called when the entry is processed, we can show that message dialog from its assigned function:
[Files]
Source: "MyProg.exe"; DestDir: "{app}"
[Run]
Filename: "{app}\MyProg.exe"; AfterInstall: ShowStartingMessageBox; Flags: nowait
[Code]
#ifdef UNICODE
#define AW "W"
#else
#define AW "A"
#endif
const
MB_ICONINFORMATION = $40;
function MessageBoxTimeout(hWnd: HWND; lpText: string; lpCaption: string;
uType: UINT; wLanguageId: Word; dwMilliseconds: DWORD): Integer;
external 'MessageBoxTimeout{#AW}#user32.dll stdcall';
procedure ShowStartingMessageBox;
begin
MessageBoxTimeout(WizardForm.Handle, 'The application is starting... ' +
'Ok, to be upright; it''s been started, but since its initialization ' +
'takes a long time, we usually say it''s starting. This message will ' +
'be automatically closed in 5 seconds!', 'Caption...',
MB_OK or MB_ICONINFORMATION, 0, 5000);
end;
That is not possible with Message Box (MsgBox() function) because it stops whole installation process and waits for user interaction.
You need to create
a) a new window which will be shown above installer window and
b) some kind of timer which will show/hide this window after appropriate time.
I think this can be easiier by writing simple C++/C#/Delphi plug-in than writing it in pure Pascal (Inno) code.
You could try to use vbscript's shell popup method.
The popup should show for 5 seconds ...
[Files]
Source: "MyProg.exe"; DestDir: "{app}"
[Run]
Filename: "{app}\MyProg.exe"; AfterInstall: ShowVBScriptPopup; Flags: nowait
[Code]
procedure ShowVBScriptPopup;
var
sh;
begin
sh := CreateOleObject('WScript.Shell');
sh.Popup('Huhu', 5, 'title');
end;
If you want a more customized implementation than the MessageBoxTimeout from #TLama's answer allows (like a countdown display or custom button captions):
Create a custom message box. For a start, see Inno Setup - Create custom message box (yes / no);
use SetTimer to implement the timeout/count down.
For a complete code, see MsgBox - Make unclickable OK Button and change to countdown - Inno Setup.

Inno Setup: Run program without showing a checkbox

I have the following lines:
[Run]
Filename: "{app}\MyApp.exe"; Flags: postinstall nowait
I would like my app to get started without showing a checkbox (which would disallow the user to do so).
Can somebody show me how, please?
Thank you.
There are few options I can think of. The first one is to run your application from the [Code] section of your script, the second one is to disable that check box for your [Run] section entry and the third one is to hide the RunList.
1. How to manually run an application when the wizard is finished ?
I would personally prefer this way, because it's more straightforward than adding a check box and hiding it later on. You will remove your current [Run] section entry and call one of the following functions from the NextButtonClick event method when its CurPageID parameter equals to wpFinished, which indicates the Finish button click:
Exec - executes the specified executable or batch file, using the same credentials as Setup/Uninstall.
ExecAsOriginalUser - executes the specified executable or batch file, using the (normally non-elevated) credentials of the user that started Setup initially
ShellExec - opens the specified file or performs another action specified by Verb, using the same credentials as Setup/Uninstall.
ShellExecAsOriginalUser - opens the specified file or performs another action specified by Verb, using the (normally non-elevated) credentials of the user that started Setup initially.
Because you haven't used the runascurrentuser nor shellexec flags, the setup internally calls a function similar to this:
function NextButtonClick(CurPageID: Integer): Boolean;
var
ResultCode: Integer;
begin
Result := True;
if CurPageID = wpFinished then
ExecAsOriginalUser(ExpandConstant('{app}\MyApp.exe'), '', '',
SW_SHOWNORMAL, ewNoWait, ResultCode);
end;
One weakness of this solution is that the program would be executed even if the restart is requested by the setup. To workaround a missing possibility to determine this request we can check if the YesRadio is visible (it is the Yes, restart the computer now radio button) and selected, which means that the user was asked to restart the computer and confirmed it. Here is the version considering the restart request:
function NextButtonClick(CurPageID: Integer): Boolean;
var
ResultCode: Integer;
begin
Result := True;
// if the "Finish" button was clicked and "Yes, restart the computer now"
// radio button was either not visible or not selected that time, then...
if (CurPageID = wpFinished) and ((not WizardForm.YesRadio.Visible) or
(not WizardForm.YesRadio.Checked))
then
ExecAsOriginalUser(ExpandConstant('{app}\MyApp.exe'), '', '',
SW_SHOWNORMAL, ewNoWait, ResultCode);
end;
2. How to disable the post install check box on the final page ?
Another option is to disable the check box. The user will see that the application is going to be executed, but won't be able to do anything against it (except killing the setup from Task Manager, of course). This time you will keep your [Run] section entry as it, but modify the RunList from the [Code] section:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName=My Program
[Files]
Source: "MyApp.exe"; DestDir: "{app}"
[Run]
Filename: "{app}\MyApp.exe"; Flags: postinstall nowait
[Code]
procedure CurPageChanged(CurPageID: Integer);
begin
// you must do this as late as possible, because the RunList is being modified
// after installation; so this will check if there's at least one item in the
// RunList and then set to the first item (indexing starts at 0) Enabled state
// to False
if (CurPageID = wpFinished) and (WizardForm.RunList.Items.Count > 0) then
WizardForm.RunList.ItemEnabled[0] := False;
end;
3. How to completely hide the RunList ?
This will, contrary to the second option, do what you asked for. It will keep the check box hidden, or to be more precise, it will hide the whole RunList, so if you were having more than one entry in the [Run] section with the postinstall flag specified, it won't be seen as well:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName=My Program
[Files]
Source: "MyApp.exe"; DestDir: "{app}"
[Run]
Filename: "{app}\MyApp.exe"; Flags: postinstall nowait
[Code]
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = wpFinished then
WizardForm.RunList.Visible := False;
end;
Works on version 5.5.7
Add the following code if you want to open a website automatically
[Code]
procedure CurPageChanged(CurPageID: Integer);
var
ErrorCode : Integer ;
begin
if CurPageID = wpFinished then
ShellExecAsOriginalUser('', ExpandConstant('http:\\www.google.pt'), '', '',SW_SHOWNORMAL, ewNoWait, ErrorCode);
end;

Change messages/texts at runtime (Inno Setup)

In an innosetup script it is possible to define messages like this:
[Messages]
WelcomeLabel2=This wizard will update [name] to version [name/ver]
Now I would like to change this message at runtime, like this:
procedure InitializeWizard;
begin
//this doesn't work
WelcomeLabel2=NEW MESSAGE
end;
What is the correct way to do this? I want to dynamically change the contents of the welcome page to display whether the setup is performing a new installation or update. Based on the existence of some executables in the installation directory.
One way;
[Languages]
Name: "en"; MessagesFile: "compiler:Default.isl"
[CustomMessages]
en.WelcomeLabel2_ForInstall=intstall {#SetupSetting("AppName")}, {#SetupSetting("AppVersion")}
en.WelcomeLabel2_ForUpdate=update {#SetupSetting("AppName")} to {#SetupSetting("AppVersion")}
[code]
procedure InitializeWizard();
var
message: string;
begin
//some logic
message := 'WelcomeLabel2_ForUpdate';
WizardForm.WelcomeLabel2.Caption := CustomMessage(message);
end;
procedure CurPageChanged(CurPageID: Integer);
begin
case CurPageID of
wpFinished : WizardForm.FinishedLabel.Caption := 'bla bla';
end;
end;
Hm, this won't work, I think. One way could be to create two pages for the installer - one with the layout for the installation process and one with the layout for the update process. Then, change the page sequence in a way that you manually decide which one to show.
An example for integrating a new page into the process can be found in my answer here.

Resources