Is it appropriate to create controls in the CurPageChanged procedure? - inno-setup

I have code in CurPageChanged that adds a button to the license window. My CurPageChanged starts like this:
procedure CurPageChanged(CurPageID: Integer);
var Button123 TButton;
begin
if CurPageID = wpLicense then begin
Button123 := TButton.Create(WizardForm.LicenseMemo.Parent);
My question is wouldn't that create a button each time the page is changed to the wpLicense page? So if a user clicks past the license dialog, then goes back to it, wouldn't that create another button? How can I ensure that only one button is created? What I'm looking for is the most appropriate procedure from which to add a control --once-- to an existing wp. Thanks

My question is wouldn't that create a button each time the page is changed to the wpLicense page? So if a user clicks past the license dialog, then goes back to it, wouldn't that create another button?
Yes, it would create multiple buttons each time. Because the pages do not get destroyed, the controls on them do not get destroyed. But you can actually take advantage of that fact to create a single control and then show/hide it when necessary.
To start, modify the InitializeWizard method, which is called only once before the wizard is displayed. Create the button in here, like so:
procedure InitializeWizard();
var
MyButton: TButton;
begin
MyButton := TButton.Create(WizardForm.LicenseMemo.Parent);
MyButton.Parent := WizardForm.LicenseMemo.Parent;
MyButton.Top := 0;
MyButton.Left := 0;
MyButton.Caption := 'My Custom Button';
...
end;

Related

Inno Setup: add fields to InputQueryPage depending on components selected

I have an input query page, which asks the user for ports depending on what components are selected.
procedure InitializeWizard;
begin
{ Create the page }
ConfigPage :=
CreateInputQueryPage(
wpSelectComponents, 'User input', 'User input',
'Please specify the following information, then click Next.');
{ Add items (False means it's not a password edit) }
if IsComponentSelected('broker') then
begin
ConfigPage.Add('MQTT Broker port:', False);
{ Set initial values (optional) }
ConfigPage.Values[0] := ExpandConstant('1883');
end;
end;
The issue I am finding here is that InitializeWizard is always called prior to component selection, so IsComponentSelected('broker') is always called.
Is there any way around this? How can I achieve this?
It's not easy. For a really generic solution, you would have to create the custom page only when leaving the components selection page (e.g. in NextButtonClick with CurPageID equal wpSelectComponents). That's doable, but Inno Setup allows user to go back to the components page. When the user does that, you would have to remove the custom page, re-creating it later. But you would lose the data the user might have entered on the custom page. So you would have to persist the data somehow. All that is doable, but lot of work.
If it is about few input boxes only, consider instead disabling the boxes that are not relevant for the current components selection:
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = ConfigPage.ID then
begin
ConfigPage.Edits[0].Enabled := IsComponentSelected('foo');
ConfigPage.PromptLabels[0].Enabled := ConfigPage.Edits[0].Enabled;
ConfigPage.Edits[1].Enabled := IsComponentSelected('bar');
ConfigPage.PromptLabels[1].Enabled := ConfigPage.Edits[1].Enabled;
end;
end;
A step further would be to hide the boxes instead of disabling them (use Visible instead of Enabled). But then you would have to rearrange the boxes. But that's still easier then re-building the page.

Inno Setup: How to display license page before custom page shows from procedure InitializeWizard();

I am using LicenseFile=D:\authorized\Builds\Integration\License.rtf to display license page and procedure InitializeWizard();.
The Problem is that the license page is displayed after the procedure InitializeWizard();. Is there any way we can display it before?
procedure InitializeWizard;
begin
{ Create the pages }
UsagePage := CreateInputOptionPage(wpWelcome,
'App setup information', 'How would you like to install App?',
'Would you like to install App as a service?.',
True, False);
UsagePage.Add('Yes');
UsagePage.Add('No');
UsagePage.Values[0] := true;
end;
It's a misunderstanding. The InitializeWizard function does not display anything. It just creates the custom page(s), it does not display them.
Try adding a MsgBox call at the end of the function. You will see that the message displays before the wizard form even pops up.
The order of the custom pages is determined by the AfterID parameter (the first one) of the Create*Page functions.
If you want the custom page to show after the license page, use wpLicense, instead of wpWelcome.
UsagePage := CreateInputOptionPage(wpLicense, ...);

In Inno Setup, how can I set which component gets an initial focus on "Select Components" page

When the wpSelectComponents page is shown, I'd like to set focus to a particular item/component in the list. Is there a way to do this?
Set ItemIndex property of WizardForm.ComponentsList, like:
WizardForm.ComponentsList.ItemIndex := 2;
Note that focus of the list item is not rendered, until the list itself receives a focus:
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = wpSelectComponents then
begin
WizardForm.ActiveControl := WizardForm.ComponentsList;
end;
end;
You need to use WinAPI to achieve this.
Unfortunately I could not find any Pascal example so have a look on this C++ code: Selecting and Highlighting an Item from List View.
Calling this code from Inno Setup requires to call WinApi dlls functions so maybe writing this feature as small C++ plugin could be easier.

cancel button not displayed for wizard page created with wpInfoAfter in inno setup

I have created a custom wizard page in inno, which needs to be shown after installing the files to {app} folder. This is achieved by giving the wpInfoAfter.
The problem is, its showing only the 'next' button, there is no cancel/back button, also the dialog's closing button on top right is also disabled. I understand that the back button isn't needed, as it needs to remove the files which are installed. Is there anyway the 'cancel' button can be displayed?
The Cancel button has no functionality at the after install stage, because InnoSetup doesn't expect to do further actions, that would require cancel, after the installation process is done. So, even if you show the button against that fact, you would get a button without any action.
Personally I would prefer to collect the information needed to setup your database before the installation starts, because consider the situation when the user installs your application and simply cancel the after installation wizard (what can easily happen). Doing it before, you'll be able to force your users to fill what you need before they actually get to the application itself. But if you still want to do it after install, here is a workaround for that missing cancel button.
As a workaround, you can create your own custom button, that will be on a same position with the same functionality. Here is a sample script, simulating a cancel button and showing it only on the custom page which is laying after the installation process. It's just a workaround, because you'd need at least fix this:
enable the closing cross of the wizard form (it's disabled after the installation stage is done)
handle the ESC key shortcut somehow (it invokes the exit prompt dialog too, but I couldn't find a way how to workaround this)
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
[Code]
procedure ExitProcess(uExitCode: UINT);
external 'ExitProcess#kernel32.dll stdcall';
var
CustomPage: TWizardPage;
CancelButton: TNewButton;
procedure OnCancelButtonClick(Sender: TObject);
begin
// confirmation "Exit setup ?" message, if user accept, then...
if ExitSetupMsgBox then
begin
// stop and rollback actions you did from your after install
// process and kill the setup process itself
ExitProcess(0);
end;
end;
procedure InitializeWizard;
begin
// create a custom page
CustomPage := CreateCustomPage(wpInfoAfter, 'Caption', 'Description');
// create a cancel button, set its parent, hide it, setup the bounds
// and caption by the original and assign the click event
CancelButton := TNewButton.Create(WizardForm);
CancelButton.Parent := WizardForm;
CancelButton.Visible := False;
CancelButton.SetBounds(
WizardForm.CancelButton.Left,
WizardForm.CancelButton.Top,
WizardForm.CancelButton.Width,
WizardForm.CancelButton.Height
);
CancelButton.Caption := SetupMessage(msgButtonCancel);
CancelButton.OnClick := #OnCancelButtonClick;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
// show your fake Cancel button only when you're on some of your after
// install pages; if you have more pages use something like this
// CancelButton.Visible := (CurPageID >= FirstPage.ID) and
// (CurPageID <= LastPage.ID);
// if you have just one page, use the following instead
CancelButton.Visible := CurPageID = CustomPage.ID;
end;

Show License Agreement link in Inno Setup while installation

I am using Inno Setup for my application. I want to show a link (License Agreement) in Inno Setup while installation (except separate License Agreement Wizard). I want combine this link with some task. When user clicks that link it will navigate to particular URL.
I know I'm quite late here... The following code script creates the License Agreement link label in the bottom left part of the wizard form. That label has a blue underlined font and a hand cursor on hover so it looks and feels like a common web page link. On its click event a specified URL is opened in a default web browser. This label is then visible on all wizard pages except the license page one:
[Code]
var
LicenseLinkLabel: TLabel;
procedure LicenseLinkClick(Sender: TObject);
var
ErrorCode: Integer;
begin
ShellExec('', 'http://www.stackoverflow.com', '', '', SW_SHOW, ewNoWait,
ErrorCode);
end;
procedure InitializeWizard;
begin
LicenseLinkLabel := TLabel.Create(WizardForm);
LicenseLinkLabel.Parent := WizardForm;
LicenseLinkLabel.Left := 8;
LicenseLinkLabel.Top := WizardForm.ClientHeight -
LicenseLinkLabel.ClientHeight - 8;
LicenseLinkLabel.Cursor := crHand;
LicenseLinkLabel.Font.Color := clBlue;
LicenseLinkLabel.Font.Style := [fsUnderline];
LicenseLinkLabel.Caption := 'License Agreement';
LicenseLinkLabel.OnClick := #LicenseLinkClick;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
LicenseLinkLabel.Visible := CurPageID <> wpLicense;
end;
And the result (click to enlarge):
Create an RTF formatted license text (with Wordpad for very small file size) and type the hyperlink in the text as pure text, no extra functions needed (eg. 'http://stackoverflow.com'). InnoSetup will display this URL and make it clickable. Be aware that e-mail links do not work properly.
Wanna try? Save this entire text Wordpad, save as RTF and link it to InnoSetup.
Dutch

Resources