I am using restartreplace flag to replace the locked file, so it will prompt a message at the end of the installation to restart the machine. But I don't want to display it, and it should be set to restart later by default. Is there any way?
You can hide Yes/No restart radio buttons. And update the screen text accordingly.
procedure CurPageChanged(CurPageID: Integer);
var
S: string;
begin
if CurPageID = wpFinished then
begin
WizardForm.YesRadio.Visible := False;
WizardForm.NoRadio.Visible := False;
WizardForm.NoRadio.Checked := True;
S := SetupMessage(msgFinishedLabelNoIcons);
StringChangeEx(S, '[name]', 'My Program', True);
WizardForm.FinishedLabel.Caption := S;
WizardForm.AdjustLabelHeight(WizardForm.FinishedLabel);
end;
end;
Related
I have created some custom checkboxes in the finished page of Inno Setup.
For example launching an app, opening a text file etc.
I need when the user clicks on the finish button I check those checkboxes and do whatever that is needed. How can I do such a thing in Inno Setup?
Here is the code:
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = wpFinished then
begin
Launch := TNewCheckBox.Create(WizardForm);
Launch.Parent := WizardForm;
Launch.Left := WizardForm.ClientWidth - 350;
Launch.Top := WizardForm.CancelButton.Top;
Launch.Width := 120;
Launch.Height := WizardForm.CancelButton.Height;
Launch.Caption := 'Launch';
end;
end;
In NextButtonClick event handler, test if your checkbox is checked and act accordingly.
function NextButtonClick(CurPageID: Integer): Boolean;
var
ResultCode: Integer;
Path: string;
Message: string;
begin
if CurPageID = wpFinished then
begin
if Launch.Checked then
begin
Path := ExpandConstant('{app}\MyProg.exe');
if ExecAsOriginalUser(Path, '', '', SW_SHOW, ewNoWait, ResultCode) then
begin
Log('Executed MyProg');
end
else
begin
Message := 'Error executing MyProg: ' + SysErrorMessage(ResultCode);
MsgBox(Message, mbError, MB_OK);
end;
end;
end;
Result := True;
end;
Simply check the checkbox state:
if (Launch.Checked = True) then
begin
// checkbox is checked
end
else
begin
// Checkbox is unchecked
end;
The best place is to use function NextButtonClick(CurPageID: Integer): Boolean;
however in that case you need to make your checkbox a global variable (so it is accessible).
My Inno Setup program have a custom "input file page" that was created using CreateInputFilePage.
How can I disable the NextButton in this page until the file path is properly picked by the user?
In other words, I need to make the NextButton unclickable while the file selection form is empty, and clickable when the file selection form is filled.
Thank you.
The easiest way is to use NextButtonClick to validate the inputs and display an error message when the validation fails.
var
FilePage: TInputFileWizardPage;
procedure InitializeWizard();
begin
FilePage := CreateInputFilePage(wpSelectDir, 'caption', 'description', 'sub caption');
FilePage.Add('prompt', '*.*', '.dat');
end;
function NextButtonClick(CurPageID: Integer): Boolean;
begin
Result := True;
if (CurPageID = FilePage.ID) and
(Length(FilePage.Edits[0].Text) = 0) then
begin
MsgBox('Please select a file.', mbError, MB_OK);
WizardForm.ActiveControl := FilePage.Edits[0];
Result := False;
end;
end;
If you really want to update the "Next" button state while the input changes, it is a bit more complicated:
procedure FilePageEditChange(Sender: TObject);
begin
WizardForm.NextButton.Enabled := (Length(TEdit(Sender).Text) > 0);
end;
procedure FilePageActivate(Sender: TWizardPage);
begin
FilePageEditChange(TInputFileWizardPage(Sender).Edits[0]);
end;
procedure InitializeWizard();
var
Page: TInputFileWizardPage;
Edit: TEdit;
begin
Page := CreateInputFilePage(wpSelectDir, 'caption', 'description', 'sub caption');
{ To update the Next button state when the page is entered }
Page.OnActivate := #FilePageActivate;
Edit := Page.Edits[Page.Add('prompt', '*.*', '.dat')];
{ To update the Next button state when the edit contents changes }
Edit.OnChange := #FilePageEditChange;
end;
I have a custom page SelectPage that I am creating two custom check boxes on. The relevant parts of the code from InitializeWizard procedure are below:
//Define the Restart Services Checkbox
RestartServicesCheckBox := TNewCheckBox.Create(WizardForm);
with RestartServicesCheckBox do
begin
Parent := SelectPage.Surface;
Caption := 'Restart Services';
Left := OptionsLabel.Left;
Top := OptionsLabel.Top + ScaleY(20);
Checked := True;
end;
//Define the Restart Server Checkbox
RestartServerCheckBox := TNewCheckBox.Create(WizardForm);
with RestartServerCheckBox do
begin
Parent := SelectPage.Surface;
Caption := 'Restart Server';
Left := OptionsLabel.Left;
Top := RestartServicesCheckBox.Top + ScaleY(22);
Checked := False
end;
This works and I get the check boxes that I want and they perform the actions that I assign to them. What I am struggling to work out is how to assign a dependency between the two, so that if one is checked, the other is automatically unchecked. However, I do not want a radio buttons type dependency, as both checkboxes might need to be unchecked. I was looking at trying to intercept the OnClick event something like this:
var
DefaultOnClick: TNotifyEvent;
procedure InitializeWizard();
begin
//Store the original OnClick event procedure and assign custom procedure
DefaultOnClick := WizardForm.TCheckBox.OnClick;
WizardForm.TCheckBox.OnClick := #OnClick;
end;
//Uncheck and Restart Services if Restart Server is checked and vice versa
procedure UpdateOptions();
begin
with RestartServicesCheckBox do
begin
if RestartServicesCheckBox.Checked then
begin
Checked := False;
end;
end;
with RestartServerCheckBox do
begin
if RestartServerCheckBox.Checked then
begin
Checked := False;
end;
end;
end;
//Update the options check boxes if the states change and restore the original event handler procedures
procedure OnClick(Sender: TObject);
begin
DefaultOnClick(Sender);
UpdateOptions;
end;
However, I do not know what the full event name is that I need to intercept. It clearly isn't WizardForm.TCheckBox.OnClick anyway. What would this event name be and will this method work? Alternatively, is there a simpler way to do this?
It is the TCheckBox.OnClick event that you need to use.
var
RestartServicesCheckBox: TNewCheckBox;
RestartServerCheckBox: TNewCheckBox;
procedure RestartServicesCheckBoxClick(Sender: TObject);
begin
if RestartServicesCheckBox.Checked then
RestartServerCheckBox.Checked := False;
end;
procedure RestartServerCheckBoxClick(Sender: TObject);
begin
if RestartServerCheckBox.Checked then
RestartServicesCheckBox.Checked := False;
end;
procedure InitializeWizard();
begin
// Define the Restart Services Checkbox
RestartServicesCheckBox := TNewCheckBox.Create(WizardForm);
with RestartServicesCheckBox do
begin
...
Checked := True;
OnClick := #RestartServicesCheckBoxClick;
end;
// Define the Restart Server Checkbox
RestartServerCheckBox := TNewCheckBox.Create(WizardForm);
with RestartServerCheckBox do
begin
...
Checked := False;
OnClick := #RestartServerCheckBoxClick;
end;
end;
Though I think that three radio buttons might be better:
Do not restart
Restart service only
Restart server
I found a code here that I needed. To only allow write numbers in a text box. But I still wanted more, which does not offer up the "Next" button without write the number in this text box.
Can help me?
procedure NumbersOnly(Sender: TObject; var Key: Char);
var
S: string;
begin
S := ('1234567890'#8);
if Pos(Key, S) = 0 then
Key := #0;
end;
You can setup the next button to be enabled or disabled in the CurPageChanged event when the user reaches the page where resides your edit box. Except that you need to monitor changes of that edit box to enable or disable the next button according to whether there's something entered in that edit box. For this you need to write a handler for the OnChange event. Here is an example:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
[Code]
var
MyEdit: TNewEdit;
MyPage: TWizardPage;
procedure MyEditChange(Sender: TObject);
begin
{ enable the next button if the edit box is not empty; disable otherwise }
WizardForm.NextButton.Enabled := MyEdit.Text <> '';
end;
procedure MyEditKeyPress(Sender: TObject; var Key: Char);
var
KeyCode: Integer;
begin
{ allow only numbers }
KeyCode := Ord(Key);
if not ((KeyCode = 8) or ((KeyCode >= 48) and (KeyCode <= 57))) then
Key := #0;
end;
procedure InitializeWizard;
begin
MyPage := CreateCustomPage(wpWelcome, 'Caption', 'Description');
MyEdit := TNewEdit.Create(WizardForm);
MyEdit.Parent := MyPage.Surface;
MyEdit.Left := 0;
MyEdit.Top := 0;
MyEdit.Width := 150;
MyEdit.OnChange := #MyEditChange;
MyEdit.OnKeyPress := #MyEditKeyPress;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
{ if the currently turned wizard page is the one with the edit box, enable }
{ the next button if the edit box is not empty; disable otherwise }
if CurPageID = MyPage.ID then
WizardForm.NextButton.Enabled := MyEdit.Text <> '';
end;
There are two flaws in the #TLama's answer:
A user can bypass the check by using Paste command from edit box context menu (and possibly by other kinds of input methods).
To fix this, you can introduce a last resort check in NextButtonClick.
I would also suggest adding the check for an empty input there, instead of MyEditChange, as it allows providing feedback to the user, explaining what is wrong.
On the other hand, Ctrl+C, Ctrl+V and Ctrl+X keys are not working. Particularly a lack of Ctrl+V is not comfortable.
To fix this, allow these control characters in the MyEditKeyPress.
[Code]
var
MyEdit: TNewEdit;
MyPage: TWizardPage;
procedure ValidateMyEdit;
begin
{ enable the next button if the edit box is not empty; disable otherwise }
WizardForm.NextButton.Enabled := (MyEdit.Text <> '');
end;
procedure MyEditChange(Sender: TObject);
begin
ValidateMyEdit;
end;
function IsDigit(C: Char): Boolean;
begin
Result := (C >= '0') and (C <= '9')
end;
procedure MyEditKeyPress(Sender: TObject; var Key: Char);
begin
if not ((Key = #8) or { Tab key }
(Key = #3) or (Key = #22) or (Key = #24) or { Ctrl+C, Ctrl+V, Ctrl+X }
IsDigit(Key)) then
begin
Key := #0;
end;
end;
procedure InitializeWizard;
begin
MyPage := CreateCustomPage(wpWelcome, 'Caption', 'Description');
MyEdit := TNewEdit.Create(WizardForm);
MyEdit.Parent := MyPage.Surface;
MyEdit.Left := 0;
MyEdit.Top := 0;
MyEdit.Width := 150;
MyEdit.OnChange := #MyEditChange;
MyEdit.OnKeyPress := #MyEditKeyPress;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = MyPage.ID then
begin
ValidateMyEdit;
end;
end;
function NextButtonClick(CurPageID: Integer): Boolean;
var
I: Integer;
begin
Result := True;
if CurPageID = MyPage.ID then
begin
for I := 1 to Length(MyEdit.Text) do
begin
if not IsDigit(MyEdit.Text[I]) then
begin
MsgBox('Only numbers are allowed', mbError, MB_OK);
Result := False;
Break;
end;
end;
end;
end;
This is the way I use based on keys from ASCII code:
procedure justNumbers(Sender: TObject; var Key: Char);
begin
if not ((Key = #8) or (Key = #43) or ((Key >= #48) and (Key <= #57)))
then
begin
Key := #0;
end;
end;
Could work for validate others characters too.
I'm trying to override Next/Cancel buttons on wpFinished page - NextButton should show downloaded file and exit the installator - it's working ok but CancelButton doesn't do nothing - it should close the installator with standard confirm. I wonder it is possible with standard inno events or I need to write own code to exit the application and show the confirm?
function NextButtonClick(CurPage: Integer): Boolean;
begin
if CurPage = wpFinished then begin
ShowDownloadedFile();
end;
Result := True;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = wpFinished then begin
WizardForm.NextButton.Caption := SetupMessage(msgButtonInstall);
WizardForm.CancelButton.Caption := SetupMessage(msgButtonFinish);
WizardForm.CancelButton.Visible := True;
end;
end;
Here it is, but don't do this at home kids :-)
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
[Code]
procedure ExitProcess(uExitCode: UINT);
external 'ExitProcess#kernel32.dll stdcall';
function NextButtonClick(CurPage: Integer): Boolean;
begin
Result := True;
// if the fake Finish button was clicked...
if CurPage = wpFinished then
MsgBox('Welcome to the next installation!', mbInformation, MB_OK);
end;
procedure CancelButtonClickFinishedPage(Sender: TObject);
begin
// display the "Exit Setup ?" message box and if the user selects "Yes",
// then exit the process; it is currently the only way how to exit setup
// process manually
if ExitSetupMsgBox then
ExitProcess(0);
end;
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = wpFinished then
begin
WizardForm.NextButton.Caption := SetupMessage(msgButtonInstall);
WizardForm.CancelButton.Caption := SetupMessage(msgButtonFinish);
WizardForm.CancelButton.Visible := True;
// bind your own OnClick event for the Cancel button; the original one
// is already disconnected at this stage
WizardForm.CancelButton.OnClick := #CancelButtonClickFinishedPage;
end;
end;
The proper alternative to what you're trying to do is to include a [Run] entry like so:
[Run]
Filename: {app}\yourfile.exe; Description: Run my application; Flags: postinstall nowait
This will display a checkbox on the wpFinished page giving them the choice to run the app or not.