Port range validation for data input in Inno Setup - inno-setup

I try to set specific range of values that accepted from user inputs within installation. For example, port field just accept range from 10000-20000.
I try to use this condition in NextButtonClick or even other. I searched in Pascal documentation, but I didn't find how to do that, else there is no question asked before here to set data validation for specific range.
My code as below:
[Code]
var
AdminDataPage: TInputQueryWizardPage;
Name, SuperPassword, ServerName, ServerPort : String;
function CreateAdminDataPage(): Integer;
begin
AdminDataPage := CreateInputQueryPage(wpSelectDir, 'Required Information', '', '');
AdminDataPage.Add('Name', False);
AdminDataPage.Add('SuperPassword', True);
AdminDataPage.Add('ServerName', False);
AdminDataPage.Add('ServerPort', False);
end;
procedure CreateAdminDataPage();
begin
CreateDataInputPage();
end;
function NextButtonClick(CurPageID: Integer): Boolean;
begin
if CurPageID = AdminDataPage.ID then
begin
Name := AdminDataPage.values[0];
SuperPassword := AdminDataPage.values[1];
ServerName := AdminDataPage.values[2];
ServerPort := AdminDataPage.values[3];
end;
end;

Just validate the input, display error message and make sure the NextButtonClick event function returns False:
function NextButtonClick(CurPageID: Integer): Boolean;
var
ServerPortInt: Integer;
begin
Result := True;
if CurPageID = AdminDataPage.ID then
begin
ServerPort := AdminDataPage.Values[3];
ServerPortInt := StrToIntDef(ServerPort, -1);
if (ServerPortInt < 10000) or (ServerPortInt > 20000) then
begin
MsgBox('Please enter port in range 10000-20000.', mbError, MB_OK);
WizardForm.ActiveControl := AdminDataPage.Edits[3];
Result := False;
end;
end;
end;

Related

Inno Setup: How to show (hide/unhide) password on checkbox checked

I am adding a checkbox to my input query page to use it to show me the password uncovered, when is checked. But I don't know how to do that.
I already created the following procedure. But this procedure does not change me the true false value on add input. This procedure adds me new textbox that do the job.
Could you please help me?
procedure SPCheckBoxChecked(Sender: TObject);
begin
if Assigned(SPCheckBox) then
begin
if SPCheckBox.Checked then
CredentialsPage.Add('Password:', False)
if not SPCheckBox.Checked then
CredentialsPage.Add('Password:', True)
end;
end;
Use TPasswordEdit.Password property:
[Code]
var
InputQueryPage: TInputQueryWizardPage;
procedure ShowPasswordCheckClick(Sender: TObject);
begin
InputQueryPage.Edits[0].Password := not TNewCheckBox(Sender).Checked;
end;
procedure InitializeWizard();
var
ShowPasswordCheck: TNewCheckBox;
begin
InputQueryPage := CreateInputQueryPage(
wpWelcome, 'Password prompt', 'Please enter your password', '');
InputQueryPage.Add('Password:', True);
ShowPasswordCheck := TNewCheckBox.Create(WizardForm);
ShowPasswordCheck.Parent := InputQueryPage.Surface;
ShowPasswordCheck.Top :=
InputQueryPage.Edits[0].Top + InputQueryPage.Edits[0].Height + ScaleY(8);
ShowPasswordCheck.Height := ScaleY(ShowPasswordCheck.Height);
ShowPasswordCheck.Caption := '&Show password';
ShowPasswordCheck.OnClick := #ShowPasswordCheckClick;
end;

Run Files and Programs according to custom checkboxes after clicking on Finish Button in Inno Setup

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).

How to Stop all Pipeline tasks correctly

how to stop Pipleline tasks correctly, I've tried but when i press Abort button i get an AV, i'm not too good at debugging,i have reached to DoOnStop(task); in OtlParallel then i couldn't figure out what to do next, i believe there is something missing ?
type
procedure SetInProcess(const Value: Boolean);
private
FInProcess: Boolean;
property inProcess: Boolean read FInProcess write SetInProcess;
public
FStopAll: Boolean;
procedure FlushData;
procedure Retriever(const input: TOmniValue; var output: TOmniValue);
...
procedure TForm1.SetInProcess(const Value: Boolean);
var
I: Integer;
begin
if Value = InProcess then exit;
memo1.ReadOnly := Value;
FInProcess := Value;
if Value then
Memo1.Lines.Clear;
Timer1.Enabled := Value;
If not Value then
begin
FlushData;
pipeline := nil;
end;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
If not InProcess then exit;
FlushData;
if Pipeline.Output.IsFinalized then
InProcess := False;
end;
procedure TForm1.StartButton(Sender: TObject);
var
i : integer;
urlList : TStrings;
U, S : string;
value : TOmniValue;
begin
urlList := Memo2.Lines;
pipeline := Parallel.Pipeline;
pipeline.Stage(Retriver).NumTasks(StrToInt(Edit12.Text)).Run;
for U in urlList do
pipeline.Input.Add(U);
pipeline.Input.CompleteAdding;
inProcess := True;
end;
procedure TForm1.FlushData;
var v: TOmniValue;
begin
if pipeline = nil then exit;
if pipeline.Output = nil then exit;
Memo1.Lines.BeginUpdate;
try
while pipeline.Output.TryTake(v) do
Memo1.Lines.Add(v.AsString);
if FStopAll then
begin
Pipeline.Cancel;
end;
Memo1.Lines.EndUpdate;
except
on E: Exception do
begin
Memo1.Lines.Add(E.Message);
end;
end;
Memo1.Lines.EndUpdate;
end;
procedure TForm1.Retriver(const input: TOmniValue; var output: TOmniValue);
var
lHTTP : TIdHTTP;
Params : TStrings;
Reply,String1,String2 : string;
begin
X := Input.AsString;
Params := TStringList.Create;
string1 := Extract1(X);
string2 := Extract2(X);;
Params.Add('username=' + string1);
Params.Add('password=' + string2);
lHTTP := TIdHTTP.Create(nil);
try
...
Reply := lHTTP.Post('https://www.instagram.com/accounts/login/ajax/', Params);
if AnsiContainsStr(Reply, 'no')
then
begin
Alive.Add(string1+string2+' Client ok'); ///Alive is Global Var stringlist created earlier
end;
except
on E: EIdHTTPProtocolException do
Exit
end;
lHTTP.Free;
end;
procedure TForm1.AbortButton(Sender: TObject);
begin
try
FStopAll := False;
finally
FStopAll := True;
end;
end;
In your case of over-simplified one-stage pipeline suffice would be moving check into the worker stage itself.
procedure Retriever(const input: TOmniValue; var output: TOmniValue);
var
....
begin
if FStopAll then exit;
X := Input.AsString;
....
PS. I want to repeat that your code leaks memory badly, and that you ignored all my notes I stated before.
PPS. This code not also makes little sense (there is not point in flip-vloppign the variable to one value then to another) but is syntactically incorrect and would not compile. Thus it is not the same code you actually run. It is some different code.
procedure TForm1.AbortButton(Sender: TObject);
begin
try
FStopAll := False;
finally
FStopAll := True;
end;
end;

INNO setup - CreateInputQueryPage after install has completed returns initial values, not the ones edited

I am new to INNO and getting better every but I am having a problem with the CreateInputQueryPage that is running after the install is complete. It is returning the initial values that I put in as the defaults, not the edited values the user has edited.
Here is the code that creates the page. This seems to be fine.
procedure InitializeWizard();
var
ret : boolean;
begin
SvrSetup := CreateInputQueryPage(wpInfoAfter,
'i2x Server setup', '',
'Please specify your Company name, Listener host name and Port. then click Next.');
SvrSetup.Add('Company name:', False);
SvrSetup.Add('Listener host name:', False);
SvrSetup.Add('Port:', False);
SvrSetup.Values[1] := 'computer name'
SvrSetup.Values[2] := '5551';
end;
I run this code on the NEXTBUTTONCLICK event to validate my input
function NextButtonClick(CurPageID: Integer): Boolean;
begin
Result := true;
{ Validate certain pages before allowing the user to proceed }
if CurPageID = SvrSetup.ID then
begin
if SvrSetup.Values[0] = '' then begin
MsgBox('You must enter company name.', mbError, MB_OK);
Result := False;
end;
if SvrSetup.Values[1] = '' then begin
MsgBox('You must enter listner host.', mbError, MB_OK);
Result := False;
end;
if SvrSetup.Values[2] = '' then begin
MsgBox('You must enter listner port.', mbError, MB_OK);
Result := False;
end;
end;
end;
Now when the install is over but before the final page I do this.
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall then
begin
WriteXML;
end;
end;
And WriteXML is this.
procedure WriteXML;
var
FileData: String;
begin
FileData := ''
LoadStringFromFile(ExpandConstant('{app}\EMailer\EMailer.exe.config'), FileData);
StringChange(FileData, '!OVERRIDE_COMP!',ExpandConstant('{code:GetEmailerCompany}'));
SaveStringToFile(ExpandConstant('{app}\EMailer\EMailer.exe.config'), FileData, False);
end;
With the value I need to insert into the XML as code:GetEmailerCompanyas
function GetEmailerCompany(Param: String): String;
begin
// Return the company for email
Result := SvrSetup.Values[0];
end;
Aagain, It is returning the initial values that I put in as the defaults, not the edited values the user has edited. What am I missing?
Thanks

Required a number in text box in Inno Setup

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.

Resources