The Inno Setup action I want after CreateInputQueryPage happens before. Why? - inno-setup

When Running my Inno Setup built installer, the action that I want to have happen as a result of selections in the CreateInputQueryPage happens before the CreateInputQueryPage opens and gets input from the user. What concept am I missing?
Is it that I need to use NextButtonClick?
Here is my Pascal code based on code taken from (http://www.jrsoftware.org/ishelp):
[Code]
procedure UserGroup;
Var Page : TInputQueryWizardPage;
GroupName : String;
Message: String;
ResultCode: Integer;
begin
// Create page
Page := CreateInputQueryPage(wpWelcome,
'Users Group Required',
'Please specify group, then click Next',
'A Windows security group must be created.'
);
// Add items (False means it's not a password edit)
Page.Add('GroupName:', False);
Page.Values[0] := 'SomeGroup';
// Read values into variables
GroupName := Page.Values[0];
if Exec('net.exe', Format( 'localgroup %s /add',[GroupName]), '', SW_SHOW,
ewWaitUntilTerminated, ResultCode) then
begin
// success
Message := Format('The user group %s has been added to the local machine.', [GroupName]);
MsgBox( Message, mbInformation, MB_OK);
end
else begin
// failure i
Message := Format('The installer was not able to set up the %s security group. Please do so manually. (Inno Error Code: %i)', [GroupName, ResultCode]);
MsgBox( Message, mbInformation, MB_OK);
end;
end;
But the MsgBox shows before the CreateInputQueryPage does.

Related

Getting "You must enter a name" and "Cannot focus a disabled or invisible window" on some machines with hidden UserInfoPage Inno Setup page

I have made a quick installer and in some PC I have found problems when installing. I have "serial number" system and when I press "Next" it gives me an error
You must enter a name
and then:
Cannot focus a disabled or invisible window
But in many other PCs with same SO this works normal. This is the code that I am using:
[Setup]
WizardStyle=modern
UserInfoPage=yes
[Code]
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = wpUserInfo then begin
WizardForm.UserInfoOrgLabel.Hide();
WizardForm.UserInfoOrgEdit.Hide();
WizardForm.UserInfoNameLabel.Hide();
WizardForm.UserInfoNameEdit.Hide();
end;
end;
// Presence of the CheckSerial event function displays the serial number box.
// But here we accept any non-empty serial.
// We will validate it only in the NextButtonClick,
// as the online validation can take long.
function CheckSerial(Serial: String): Boolean;
begin
Result := (Serial <> '');
end;
function NextButtonClick(CurPageID: Integer): Boolean;
var
WinHttpReq: Variant;
Url: string;
begin
Result := True;
if CurPageID = wpUserInfo then
begin
WinHttpReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');
Url := 'Link that i use to check the serial number' +
WizardForm.UserInfoSerialEdit.Text;
WinHttpReq.Open('GET', Url, False);
WinHttpReq.Send('');
// Depending on implementation of the server,
// use either HTTP status code (.Status)
// or contents of returned "page" (.ResponseText)
// Here we use the HTTP status code:
// 200 = serial is valid, anything else = serial is invalid,
// and when invalid, we display .ResponseText
Result := (WinHttpReq.Status = 200);
if not Result then
MsgBox(WinHttpReq.ResponseText, mbError, MB_OK);
end;
end;
With UserInfoPage enabled, filling in the "User name" box is mandatory. The box is pre-filled with a value of RegisteredOwner registry value. If that value happens to be empty, and consequently the box, you cannot leave the page, until you fill it in manually. You get the "You must enter a name" error and Inno Setup moves the focus to the box. That fails with "Cannot focus a disabled or invisible window", as you have the box hidden.
If you do not care about the username, just fill in some dummy value:
WizardForm.UserInfoNameEdit.Text := 'foo';

Display custom page and save inputs to a file only when specific component is selected in Inno setup

I'm trying to build a setup for my application , which contains two parts: server and client. The client part needs to have an IP address entered by the user. I'm using a custom page to prompt for the IP address. But I need to display the custom page, only if user selects "Client" component.
[Components]
Name: "Serveur"; Description: "Server installation"; Types: Serveur; Flags: exclusive;
Name: "Client"; Description: "Client installation"; Types: Client; Flags: exclusive
[Types]
Name: "Serveur"; Description: "Server Installation"
Name: "Client"; Description: "Client Installation"
[Code]
var
Page: TInputQueryWizardPage;
ip: String;
procedure InitializeWizard();
begin
Page := CreateInputQueryPage(wpWelcome,
'IP Adresse du serveur', 'par exemple : 192.168.1.120',
'Veuillez introduire l''adresse IP du serveur :');
Page.Add('IP :', False);
Page.Values[0] := ExpandConstant('192.168.x.x');
end;
function NextButtonClick(CurPageID: Integer): Boolean;
begin
if (CurPageID = Page.ID) then
begin
ip := Page.Values[0];
SaveStringToFile('C:\Program Files\AppClient\ipAddress.txt', ip, False);
end;
Result := True;
end;
Your custom page must go only after the "Select Components" page, so you need to pass wpSelectComponents to CreateInputQueryPage:
var
Page: TInputQueryWizardPage;
procedure InitializeWizard();
begin
Page :=
CreateInputQueryPage(
wpSelectComponents, 'IP Adresse du serveur', 'par exemple : 192.168.1.120',
'Veuillez introduire l''adresse IP du serveur :');
Page.Add('IP :', False);
Page.Values[0] := '192.168.x.x';
end;
(Also note that there's no point in calling ExpandConstant on a string literal that does not include any constants).
Skip the custom page, when the "Client" component is not selected:
function IsClient: Boolean;
begin
Result := IsComponentSelected('Client');
end;
function ShouldSkipPage(PageID: Integer): Boolean;
begin
Result := False;
if PageID = Page.ID then
begin
Result := not IsClient;
end;
end;
See also Skipping custom pages based on optional components in Inno Setup.
Well behaving installer should not make any modifications to a system, before the user finally confirms the installation. So make any changes only, once installation really starts, not already when user click "Next" on the custom page.
Also, you cannot hard-code a path to the file, use {app} constant.
procedure CurStepChanged(CurStep: TSetupStep);
var
IP: string;
begin
if (CurStep = ssInstall) and IsClient() then
begin
IP := Page.Values[0];
SaveStringToFile(ExpandConstant('{app}\ipAddress.txt'), IP, False);
end;
end;

Inno Setup: CreateInputQueryPage isn't returning any value

Here is the script I'm using on Inno Setup. It is my first script, please understand if I'm asking something obvious.
It seems that the variable ServerAddress never has a value, even if I fill the input field. It looks like Page.Values[0] always returns an empty result. What is wrong with my code?
As you can see, I have made a test with a testvar variable to exclude it was a matter of variable scope, but it's not the case.
[Code]
var
Page: TInputQueryWizardPage;
ServerAddress: String;
testvar: String;
procedure InitializeWizard();
begin
Page := CreateInputQueryPage(wpWelcome,
'Server Informations', '',
'Please specify the IP address, then click Next.');
{ Add items (False means it's not a password edit) }
Page.Add('IP Address:', False);
ServerAddress := Page.Values[0];
testvar := 'testvalue';
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall then begin
MsgBox(ExpandConstant('{app} '+testvar+' : '+ServerAddress),mbInformation,MB_OK);
SaveStringToFile(ExpandConstant('{app}')+'\config.txt', 'test'+ServerAddress, True);
end;
end;
The InitializeWizard event function is called (and finishes) before the wizard window is even shown.
So a value (that the user will enter in the future) can hardly be known at that point. You have to read the value only after the custom page is shown. Like in your CurStepChanged(ssPostInstall):
procedure CurStepChanged(CurStep: TSetupStep);
var
ServerAddress: string;
begin
if CurStep = ssPostInstall then
begin
{ This is the right time to read the value }
ServerAddress := Page.Values[0];
SaveStringToFile(ExpandConstant('{app}') + '\config.txt', ServerAddress, True);
end;
end;

Correct code for opening a file with an external editor

Is the following code it right or not and, if it is wrong, please correct it.
Note: I want to open the file with "WordPad.exe" not with "Microsoft Office Word" until if "Microsoft Office Word" is the default program.
My code:
function InitializeSetup: Boolean;
var
S: AnsiString;
begin
// Show the contents of Readme.txt (non Unicode) in a message box
ExtractTemporaryFile('Info.rtf');
Result := True;
end;
procedure AboutButtonOnClick(Sender: TObject);
var
ErrorCode: Integer;
begin
ShellExec('open', ExpandConstant('{tmp}\Info.rtf'), '', '', SW_SHOWNORMAL, ewNoWait,
ErrorCode);
end;
ShellExec('open','Documentname'....); will open with the program associated with the extension of the file. If there is no program associated it will prompt you to select which program you want to view it with.
You could look for WordPad.exe and if it's found you could call ShellExec using the WordPad.EXE directly. Then pass the documentName as a parameter.
Updated with function to do this
procedure OpenDocumentInWordPad(Document : String);
var
WordPad : String;
ErrorCode : Integer;
begin
// Typical Location on XP and later.
WordPad := ExpandConstant('{pf}') + '\Windows NT\Accessories\WordPad.exe'
// Find word pad
if Not FileExists(WordPad) then
begin
// Location in Windows 95/98
WordPad := ExpandConstant('{pf}') + '\Accessories\WordPad.exe'
if Not FileExists(WordPad) then
begin
// Fall back to anything associated with document.
WordPad := Document;
Document := '';
end;
end;
if not ShellExec('open',WordPad,Document,'',SW_SHOW,ewNoWait,ErrorCode) then
begin
MsgBox(SysErrorMessage(ErrorCode),mbError,MB_OK);
end;
end;

InnoSetup: need to add validate URL by adding test button on CreateInputQueryPage

I have on CreateInputQueryPage, in that box user will type URL...Now i want to have Test button next to that text box so i can ping and validate that URL...is that possible ?
Using the Standard Support Functions, you are unable to do this.
You can call an external dll, which would allow you to do this.
You can also call COM interfaces, which would also allow you do to this.
Specifically you could use WinHTTPRequest COM object to perform this check.
You have a couple of options to deal with the validation. Both are demonstrated in the following script. The first is to create a button just for validation, the 2nd is to hook the Next Button and have it occur automatically before moving to the next page.
[Setup]
AppName='Test Script'
AppVerName='Test Script'
DefaultDirName={pf}\test
[Code]
const
InputQueryPageID = 100; //Determined by watching in Debugger.
var
Page : TInputQueryWizardPage;
procedure ClickEvent(Sender : TObject);
begin
MsgBox('Could Validate Here',mbInformation,MB_OK);
end;
procedure InitializeWizard();
var
Button : TButton;
begin
Page := CreateInputQueryPage(wpWelcome,
'Add URL', 'Test2','Test3');
Page.Add('URL:', False);
Button := TButton.Create(Page);
Button.Parent := Page.Surface;
Button.Caption := 'Button Text';
Button.Top := 100;
Button.Left := 10;
Button.OnClick := #ClickEvent;
end;
function NextButtonClick(CurrPageID: Integer) : Boolean;
begin
case CurrPageID of
InputQueryPageID : begin
MsgBox('Could Validate Here',mbInformation,MB_OK);
result := true; // Results of EXE Validation
end;
else result := true;
end;
end;

Resources