Add additional controls to standard Inno Setup pages? - checkbox

How to add checkbox to the folder selection dialog created by the Inno Setup which is shown below in the image?
This is not a custom dialog. It is created by the Inno Setup automatically.

Set the Parent property of the checkbox to the WizardForm.SelectDirPage:
var
Checkbox: TNewCheckBox;
procedure InitializeWizard();
begin
Checkbox := TNewCheckBox.Create(WizardForm.SelectDirPage);
Checkbox.Parent := WizardForm.SelectDirPage;
Checkbox.Top := WizardForm.DirEdit.Top + WizardForm.DirEdit.Height + ScaleY(8);
Checkbox.Left := WizardForm.DirEdit.Left;
Checkbox.Caption := 'My checkbox';
// See https://stackoverflow.com/q/30469660/850848
Checkbox.Height := ScaleY(Checkbox.Height);
end;
For finding the page names, see:
Inno Setup built-in control names

Related

Inno Setup - How to bind a checkbox with a registry key, to check if the key may be written? [duplicate]

This question already has answers here:
How to make work the new added checkboxes with the tasks?
(2 answers)
Closed 10 months ago.
I need to create an installer with Inno Setup (version 6.2.1) in which I need to let the user select which file extension he want to associate with the installed app.
To achieve that I needed to create a custom page showing all the checkboxes I needed. This page respects a custom theme required by my company, for that reason I could not use the checkboxes automatically generated by the [Tasks] section.
However I cannot figure out how to associate the checkbox state with the registry key I want to install (or not).
For example, I have the following code:
[Code]
var
AssocABCCB: TNewCheckBox;
...
procedure InitializeWizard;
var
SelectAssocPage: TWizardPage;
begin
// select association custom page
SelectAssocPage := CreateCustomPage(wpLicense, ExpandConstant('{cm:SelectAssocTitle}'), '');
...
// .abc checkbox
AssocABCCB := TNewCheckBox.Create(SelectAssocPage);
AssocABCCB.Align := alTop;
AssocABCCB.Caption := ExpandConstant('{cm:AssocABC}');
AssocABCCB.Parent := SelectAssocPage.Surface;
AssocABCCB.OnClick := #AssocABCCBClick;
...
end;
Now I want to use the above checkbox to optionally write a key in the registry, let say something like that:
[Registry]
Root: HKCR; Subkey: "{#KeyAppName}.abc"; Flags: uninsdeletekeyifempty; Check: AssocABCCB.Checked
Of course the above code is not working, it raises a compilation error.
But is there a way to bind the above checkbox with the registry key, in order to determine if the key may be written or not? If yes, how may I achieve that?
So I finally found what was the issue.
In fact it was an if statement was not closed correctly in one of my functions. This forced the following end statement to be closed with a . instead of a ;
Here was my wrong code:
[Code]
...
procedure CurStepChanged(CurStep: TSetupStep);
begin
Log('CurStepChanged(' + IntToStr(Ord(CurStep)) + ') called');
if CurStep = ssPostInstall then
FinishedInstall := True;
end; // <= here was the issue
end.
function DoAssocABC: Boolean;
begin
Result := AssocABCCB.Checked;
end;
...
[Registry]
Root: HKCR; Subkey: "{#KeyAppName}.abc"; Flags: uninsdeletekeyifempty; Check: DoAssocABC
Because my function was located AFTER the dotted end, it WAS NOT VISIBLE from ANY other statements, for that reason my [Registry] statement didn't find the function I tried to bind.
Unfortunately the compiler didn't complain about that. I don't know if it's a bug from Inno Setup itself.
Correcting that, the Martin Prikryl comment became right, and this fixed my issue:
You cannot access a variable in the Check parameter directly. You have to wrap it to a function, as my answer shows. It does not matter if it is a [Files] or [Registry] section. –
Martin Prikryl

Executing a stored procedure twice using TAdoStoredProc in Delphi

I'm using Delphi 10.1 Berlin and I needed to use TAdoStoredProc in my project. I don't use any non-visual component in my forms or data modules. All my connection and db components are creating at run-time.
My Question: When I'm trying to execute TAdoStoredProc, it executes twice and my insert, update processes have worked twice.
var
mSp: TADOStoredProc;
i: Integer;
begin
mSp := TADOStoredProc.Create(nil);
mSp.Connection := conn;
mSp.ProcedureName := spname;
mSp.CommandTimeout := 600;
mSp.parameters.Refresh;
for i := 0 to parameters.Count - 1 do
begin
mSp.parameters.ParamByName(parameters[i].Name).Value := parameters[i].Value;
end;
mSp.ExecProc;
mSp.Open;
Result := mSp;
What should I do or change? Thanks.
As I see that your code required some return values. So you should use TAdoStoredProc like TAdoQuery. You don't need to use ExecProc function for execute, try to use only Open function.
You can just check out TADOStoredProc.ExecProc Method documentation from here.
If an application is only interested in the result set returned by a stored procedure, call Open method for the TADOStoredProc component or set its Active property to true.

Show Files in a ListBox Delphi

Im trying to create an mp3 player that later I may used as base to create a karaoke the only problem so far is that I want to show the *.mp3 files of a directory that the users select on a ListBox without having to add then manually 1 by 1 and that it only shows the song name not the current path. I have find some ways like using large functions or instead of a ListBox using a ComboBox but it isn't a easier way or transfer the files from the ComboBox to the Listbox?
Try this code it will add file name to ListBox and save its path to TStringList with same Index so you can use get both everywhere in your code
var
Form1: TForm1;
FilePath: TStringList;
implementation
{$R *.dfm}
procedure FindFiles(FilesList: TStrings; FilesPath: TStrings;
StartDir, FileMask: string);
var
SR: TSearchRec;
DirList: TStringList;
IsFound: Boolean;
i: integer;
begin
if StartDir[length(StartDir)] <> '\' then
StartDir := StartDir + '\';
IsFound := FindFirst(StartDir + FileMask, faAnyFile - faDirectory, SR) = 0;
while IsFound do
begin
FilesPath.Add(StartDir + SR.Name);
FilesList.Add(SR.Name);
IsFound := FindNext(SR) = 0;
end;
FindClose(SR);
DirList := TStringList.Create;
IsFound := FindFirst(StartDir + '*.*', faAnyFile, SR) = 0;
while IsFound do
begin
if ((SR.Attr and faDirectory) <> 0) and (SR.Name[1] <> '.') then
DirList.Add(StartDir + SR.Name);
IsFound := FindNext(SR) = 0;
end;
FindClose(SR);
for i := 0 to DirList.Count - 1 do
FindFiles(FilesList, FilePath, DirList[i], FileMask);
DirList.Free;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FilePath.Free;
end;
procedure TForm1.sButton1Click(Sender: TObject);
begin
FilePath := TStringList.Create;
FindFiles(sListBox1.Items, FilePath, EditStartDir.Text, '*.mp3');
{FilePath is where full file path saved, EditStartDir is where to search}
end;
procedure TForm1.sListBox1Click(Sender: TObject);
begin
If sListBox1.ItemIndex > -1 then
sEdit2.Text := FilePath.Strings[sListBox1.ItemIndex];
end;
end.
If you are interested only in listing all the files from specific folder without their icons then you might want to use FileListBox component from Win 3.1 tab.
You can easily define contents from which directory are shown in it by setting the Directory property. Note this property is not exposed to Object inspector to be used at design time but it is perfectly accessible at runtime.
The mentioned component also allows defining filters and even file attributes to show only files that you desire.
The only limitation of mentioned component is that it won't allow you to show files from subfolders which is something a lot of end users would probably like.
For that you would have to search for the files on your own and add them to your desired component one by one.
If you want to only display the filename instead of the whole file path you can use ExtractFileName procedure but keep in mind that you will still have to somehow keep the full path somewhere so that you know which file to open when certain file is selected on your desired component.
There are also some components available which mimic the file browsing behavior similar to Windows Explorer like TShellTreeView or TShellListView that shipped with older versions of Delphi.
And quick search on Google shows that there are even more similar components available.

how can use dynamic array in delphi

i use dynamic array in delphi.
var
var
frame3:array[0..10] of TFrame3
procedure TForm1.Button1Click(sender:TObject);
begin
frame3[count] := TFrame3.create(self);
gridpanel2.insertcontrol(frame3[count]);
but this code is 'A component named Frame3 alredy exists.'
this error what can ido?
If you need multible instances of TFrame3 you need to give it a new name after you created it.
so change
frame3[count] := TFrame3.create(self);
gridpanel2.insertcontrol(frame3[count]);
To
frame3[count] := TFrame3.create(self);
frame3[count].Name := 'Frame3_' + InttoStr(Count);
gridpanel2.insertcontrol(frame3[count]);
The other issue is that it is not seen in your code how you are changing count loop variable. Is it defined in advance?
You need to do something like this:
procedure TForm1.Button1Click(sender:TObject);
var count:byte;
begin
for count:=1 to 10 do
begin
frame3[count] := TFrame3.create(self);
...
end;
or use any other way to set count before each array member (class instance) creation. This code will even probably not require to set Name property at all.

Replacing Radio Buttons with Check Box on License Wizard Page in Inno Setup

Is there any easy way to replace standard 2 radio buttons on License Wizard Page with single (checked/unchecked) Check Box in Inno Setup whithout creating Custom Page?
Since there are no settings to switch between license radio buttons and some license check box (at least just because there's no component for it on the WizardForm) you need to create it by your own.
The following code hide the original license radio buttons and creates a check box on the same place at the wizard initialization. This license check box is simulating the radio buttons selections in its OnClick event handler to keep their original functionality. Here is the code, which allows you to access the license check box out of the scope of the wizard initialization event. If you don't need to access this check box later on, you can use this version of the post:
[code]
var
LicenseCheckBox: TNewCheckBox;
procedure OnLicenseCheckBoxClick(Sender: TObject);
var
LicenseAccepted: Boolean;
begin
LicenseAccepted := (Sender as TNewCheckBox).Checked;
WizardForm.LicenseAcceptedRadio.Checked := LicenseAccepted;
WizardForm.LicenseNotAcceptedRadio.Checked := not LicenseAccepted;
end;
procedure InitializeWizard;
begin
WizardForm.LicenseAcceptedRadio.Hide;
WizardForm.LicenseNotAcceptedRadio.Hide;
LicenseCheckBox := TNewCheckBox.Create(WizardForm);
LicenseCheckBox.Parent := WizardForm.LicensePage;
LicenseCheckBox.Left := 0;
LicenseCheckBox.Top := WizardForm.LicenseMemo.Top +
WizardForm.LicenseMemo.Height + 8;
LicenseCheckBox.Width := WizardForm.LicenseMemo.Width;
LicenseCheckBox.Caption := ' I accept the license agreement';
LicenseCheckBox.OnClick := #OnLicenseCheckBoxClick;
end;

Resources