How to change order of pages in InnoSetup? - inno-setup

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;

Related

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 alter the default target directory ({app}) after User Info page in Inno Setup

I need to create a setup package that will allow multiple instances of the same application to be installed on the same PC/server. So, I wish to dynamically amend the default "install to" location after the UserInfo page has been processed.
i.e. in the NextButtonClick event I wish to change the value on the SelectDir wizard page when the CurPageID=wpUserInfo. Something like this below (which throws an exception). I'm also assuming that I can access the user name by expanding {userinfoname}. Any help would be appreciated.
function NextButtonClick(CurPageID: Integer): Boolean;
var
Page: TInputDirWizardPage;
begin
case CurPageID of
........
wpUserInfo:
begin
Page := TInputDirWizardPage(PageFromID(wpSelectDir));
Page.Values[0] := MyAppDirFunction;
end;
end;
Result := True;
end;
To access the "Destination folder" box, use WizardForm.DirEdit:
WizardForm.DirEdit.Text := Path;
See TWizardForm reference.

How to store serial numbers in a Sharepoint List, for to call from Inno Setup and verify if is autorized user?

I continue looking for the better way to distribute my application making use of Inno Setup, therefore I would to know if is possible to do a (check-serial).
I tried with the follows methods:
CustomPage for Serial Number in Inno Setup
How to create dynamically changing serial numbers using Inno Setup?
I want some similar like this. But with the exception that I have where to save my passwords (I think that SharePoint List could be helpful, I am not sure!)
How to do a dynamic password in Inno Setup?
Not Is enough for my boss! and I want to believe that is possible do something more elegant.
Finally, I have a SharePoint account and I would like do some in my code of Inno Setup for to control of installations, i.e. Whether I have 123 number like a serial then it works normal until I change this value in the List.
I don't want that always be a same serial
Thanks again!
To check a serial number against an HTTP resource, you can use the below code.
I do not know SharePoint, so I cannot give you details on how to adjust it to SharePoint.
[Setup]
UserInfoPage=yes
[Code]
var
SerialNumber: string;
function InitializeSetup(): Boolean;
var
WinHttpReq: Variant;
begin
Result := True;
try
WinHttpReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');
WinHttpReq.Open('GET', 'https://www.example.com/serial.php', false);
WinHttpReq.Send();
if WinHttpReq.Status = 200 then
begin
SerialNumber := Trim(WinHttpReq.ResponseText);
end;
except
end;
if SerialNumber = '' then
begin
MsgBox('Cannot retrieve serial number.', mbError, MB_OK);
Result := False;
end;
end;
function CheckSerial(Serial: String): Boolean;
begin
Result := (SerialNumber = Serial);
end;
For a similar question, see:
Inno Setup - How to validate serial number online

Inno setup: create a log of selected items

I'd like to know how to create a log of the selected components at the setup.
I've surfed the net to find it but without any success.
To print out which components the user selected you'll need to iterate the ComponentsList check list box, check if the item is in checked state and if so, print its attribute, most probably ItemCaption. The following script shows how to log the selected components as a simple list:
[Code]
procedure CurStepChanged(CurStep: TSetupStep);
var
I: Integer;
begin
if CurStep = ssInstall then
begin
Log('Selected components:');
for I := 0 to WizardForm.ComponentsList.Items.Count - 1 do
if WizardForm.ComponentsList.Checked[I] then
Log('Component: ' + WizardForm.ComponentsList.ItemCaption[I]);
end;
end;
And a screenshot of an Inno Setup component script example log in IDE:

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