Inno Setup - Show custom components on Ready to Install page - components

I would like to add my components and the selected user from the ini file to the Ready to Install page.
Is this even possible?
It should look like this example:
This is my ini file:
[Users]
user1=Program1,Program3
user2=Program1,Program2
user3=Program1,Program3
user4=Program1,Program2
And my script:
[Files]
Source: "TEST \Software\x64\Program_1"; DestDir: "{app}\Program_1"; \
Flags: ignoreversion recursesubdirs; Check: ShouldInstallProgram('Program1')
Source: "TEST \Software\x64\Program_2"; DestDir: "{app}\Program_2"; \
Flags: ignoreversion recursesubdirs; Check: ShouldInstallProgram('Program2')
Source: "TEST \Software\x64\Program_3"; DestDir: "{app}\Program_3"; \
Flags: ignoreversion recursesubdirs; Check: ShouldInstallProgram('Program3')
[Code]
function ShouldInstallProgram(ProgramName: string): Boolean;
var
UserName: string;
ProgramsStr: string;
Programs: TStringList;
begin
UserName := WizardSetupType(False);
ProgramsStr :=
GetIniString('Users', UserName, '', ExpandConstant('{src}\UserPrograms.ini'));
Programs := TStringList.Create;
Programs.CommaText := ProgramsStr;
Result := (Programs.IndexOf(ProgramName) >= 0);
Programs.Free;
end;

Implement UpdateReadyMemo event function. See Add text to 'Ready Page' in Inno Setup
Something like this:
function GetUserName: string;
begin
Result := WizardSetupType(False);
end;
function GetProgramsToInstall: TStrings;
begin
Result := TStringList.Create;
Result.CommaText :=
GetIniString('Users', GetUserName, '', ExpandConstant('{src}\UserPrograms.ini'));
end;
function ShouldInstallProgram(ProgramName: string): Boolean;
var
Programs: TStrings;
begin
Programs := GetProgramsToInstall;
Result := (Programs.IndexOf(ProgramName) >= 0);
Log(Format('Program [%s] - %d', [ProgramName, Result]));
Programs.Free;
end;
procedure AddToReadyMemo(var Memo: string; Info, NewLine: string);
begin
if Info <> '' then Memo := Memo + Info + Newline + NewLine;
end;
function UpdateReadyMemo(
Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo,
MemoGroupInfo, MemoTasksInfo: String): String;
var
Programs: TStrings;
I: Integer;
begin
AddToReadyMemo(Result, MemoUserInfoInfo, NewLine);
AddToReadyMemo(Result, MemoDirInfo, NewLine);
AddToReadyMemo(Result, MemoTypeInfo, NewLine);
AddToReadyMemo(Result, MemoComponentsInfo, NewLine);
AddToReadyMemo(Result, MemoGroupInfo, NewLine);
AddToReadyMemo(Result, MemoTasksInfo, NewLine);
Result :=
Result +
'Selected user:' + NewLine +
Space + GetUserName + NewLine + NewLine;
Programs := GetProgramsToInstall;
if Programs.Count > 0 then
begin
Result := Result + 'Components:' + NewLine;
for I := 0 to Programs.Count - 1 do
Result := Result + Space + Programs[I] + NewLine;
end;
Programs.Free;
end;

Related

ISDone (error) finish page

I am having a problem with ISdone library error finish page.
according to the library error page should be in red colour like this:
But i am not getting the red colour:
I know why this is happening,This is because of the code of stratching the image.
Now how can i get the red colour for FinishedLabel and FinishedHeadingLabel if ISDone error occures.
Thank You .
Script :
; --- Generated by InnoSetup Script Joiner version 3.0, Jul 22 2009, (c) Bulat Ziganshin <Bulat.Ziganshin#gmail.com>. More info at http://issjoiner.codeplex.com/
; --- Source: 2.iss ------------------------------------------------------------
// Setup.ini internal
#define MyAppName "Game"
#define MyAppVersion "2.0.0.0"
#define MyAppPublisher "Dante1995"
#define MyAppExeName "MyProg.exe"
#define NeedSize "5000000"
// only Arc, Disable PrecompInside
;#Define PrecompInside
[Setup]
WizardSmallImageFile=Include\WizModernSmallImage.bmp
WizardImageFile=Include\WizModernImage-IS.bmp
AppName={#MyAppName}
AppVerName={#MyAppName}
AppPublisher={#MyAppPublisher}
AppVersion={#MyAppVersion}
DefaultDirName={pf}\{#MyAppPublisher}\{#MyAppName}
OutputBaseFilename=Setup
OutputDir=Output
Compression=zip
InternalCompressLevel=Ultra64
SetupIconFile=include\icon.ico
UninstallDisplayIcon={uninstallexe}
VersionInfoCopyright={#MyAppPublisher}
#ifdef NeedSize
ExtraDiskSpaceRequired={#NeedSize}
#endif
DisableWelcomePage=False
DisableProgramGroupPage=yes
[Languages]
Name: "default"; MessagesFile: "compiler:Default.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}";
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked;
Name: DX; Description: Install Microsoft DirectX
Name: VC; Description: Install Microsoft Visual C++ Redist
[Icons]
Name: "{group}\Play {#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Check: CheckError
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"; Check: CheckError
Name: "{commondesktop}\Play {#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Check: CheckError; Tasks: desktopicon
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Check: CheckError; Tasks: quicklaunchicon
[Files]
#ifdef PrecompInside
Source: include\facompress.dll; DestDir: {tmp}; Flags: dontcopy
Source: include\CLS-precomp.dll; DestDir: {tmp}; Flags: dontcopy
Source: include\packjpg_dll.dll; DestDir: {tmp}; Flags: dontcopy
Source: include\packjpg_dll1.dll; DestDir: {tmp}; Flags: dontcopy
Source: include\precomp.exe; DestDir: {tmp}; Flags: dontcopy
Source: include\zlib1.dll; DestDir: {tmp}; Flags: dontcopy
#endif
#ifdef SrepInside
Source: include\CLS-srep.dll; DestDir: {tmp}; Flags: dontcopy
Source: include\cls.ini; DestDir: {tmp}; Flags: dontcopy
#endif
#ifdef MSC
Source: include\CLS-MSC.dll; DestDir: {tmp}; Flags: dontcopy
#endif
Source: include\English.ini; DestDir: {tmp}; Flags: dontcopy
Source: include\unarc.dll; DestDir: {tmp}; Flags: dontcopy
Source: include\ISDone.dll; DestDir: {tmp}; Flags: dontcopy
Source: include\CallbackCtrl.dll; Flags: dontcopy noencryption noencryption
Source: include\arc.ini; DestDir: {tmp}; Flags: dontcopy
Source: "Setup.ini"; Flags: dontcopy solidbreak;
[CustomMessages]
default.ORE=h
default.MINUTI=min
default.SECONDI=sec
default.RIMANENTE=Remaining Time:
default.ESTRAZIONE=Extracted Files:
default.TTime=Total Extraction Time :
default.Elapsed=Elapsed Time:
[UninstallDelete]
Type: filesandordirs; Name: "{app}"
Type: dirifempty; Name: "{pf}\{#MyAppPublisher}"
[Messages]
default.SetupWindowTitle=%1
[Code]
var
ElapsedTimeLbl,TotalTimeLbl,Percentuale,//RollingBack,
RemainingTimeLbl,LabelCurrFileName: TLabel;
ISDoneCancel:integer;
ISDoneError:boolean;
CancelBtn: TButton;
PBOldProc : Longint;
WFCaption : string;
eTime, sTime : DWORD;
type
#ifdef UNICODE
PChar = PAnsiChar;
#endif
TCallback = function (OveralPct,CurrentPct: integer;CurrentFile,TimeStr1,TimeStr2,TimeStr3:PAnsiChar): longword;
TPBProc = function (h:hWnd;Msg,wParam,lParam:Longint):Longint;
function SetWindowLong(hWnd: HWND; nIndex: Integer; dwNewLong: Longint): Longint; external 'SetWindowLongA#user32.dll stdcall';
function CallBackProc(P:TPBProc;ParamCount:integer):LongWord; external 'wrapcallbackaddr#files:CallbackCtrl.dll stdcall';
function CallWindowProc(lpPrevWndFunc: Longint; hWnd: HWND; Msg: UINT; wParam, lParam: Longint): Longint; external 'CallWindowProcA#user32.dll stdcall';
function GetTickCount: DWORD; external 'GetTickCount#kernel32.dll stdcall';
function WrapCallback(callback:TCallback; paramcount:integer):longword;external 'wrapcallback#files:ISDone.dll stdcall delayload';
function ISDoneInit(RecordFileName:AnsiString; TimeType,Comp1,Comp2,Comp3:Cardinal; WinHandle, NeededMem:longint; callback:TCallback):boolean; external 'ISDoneInit#files:ISDone.dll stdcall';
function ISArcExtract(CurComponent:Cardinal; PctOfTotal:double; InName, OutPath, ExtractedPath: AnsiString; DeleteInFile:boolean; Password, CfgFile, WorkPath: AnsiString; ExtractPCF: boolean ):boolean; external 'ISArcExtract#files:ISDone.dll stdcall delayload';
function IS7ZipExtract(CurComponent:Cardinal; PctOfTotal:double; InName, OutPath: AnsiString; DeleteInFile:boolean; Password: AnsiString):boolean; external 'IS7zipExtract#files:ISDone.dll stdcall delayload';
function ISRarExtract(CurComponent:Cardinal; PctOfTotal:double; InName, OutPath: AnsiString; DeleteInFile:boolean; Password: AnsiString):boolean; external 'ISRarExtract#files:ISDone.dll stdcall delayload';
function ISPrecompExtract(CurComponent:Cardinal; PctOfTotal:double; InName, OutFile: AnsiString; DeleteInFile:boolean):boolean; external 'ISPrecompExtract#files:ISDone.dll stdcall delayload';
function ISSRepExtract(CurComponent:Cardinal; PctOfTotal:double; InName, OutFile: AnsiString; DeleteInFile:boolean):boolean; external 'ISSrepExtract#files:ISDone.dll stdcall delayload';
function ISxDeltaExtract(CurComponent:Cardinal; PctOfTotal:double; minRAM,maxRAM:integer; InName, DiffFile, OutFile: AnsiString; DeleteInFile, DeleteDiffFile:boolean):boolean; external 'ISxDeltaExtract#files:ISDone.dll stdcall delayload';
function ISPackZIP(CurComponent:Cardinal; PctOfTotal:double; InName, OutFile: AnsiString;ComprLvl:integer; DeleteInFile:boolean):boolean; external 'ISPackZIP#files:ISDone.dll stdcall delayload';
function ShowChangeDiskWindow(Text, DefaultPath, SearchFile:AnsiString):boolean; external 'ShowChangeDiskWindow#files:ISDone.dll stdcall delayload';
function Exec2 (FileName, Param: PAnsiChar;Show:boolean):boolean; external 'Exec2#files:ISDone.dll stdcall delayload';
function ISFindFiles(CurComponent:Cardinal; FileMask:AnsiString; var ColFiles:integer):integer; external 'ISFindFiles#files:ISDone.dll stdcall delayload';
function ISPickFilename(FindHandle:integer; OutPath:AnsiString; var CurIndex:integer; DeleteInFile:boolean):boolean; external 'ISPickFilename#files:ISDone.dll stdcall delayload';
function ISGetName(TypeStr:integer):PAnsichar; external 'ISGetName#files:ISDone.dll stdcall delayload';
function ISFindFree(FindHandle:integer):boolean; external 'ISFindFree#files:ISDone.dll stdcall delayload';
function ISExec(CurComponent:Cardinal; PctOfTotal,SpecifiedProcessTime:double; ExeName,Parameters,TargetDir,OutputStr:AnsiString;Show:boolean):boolean; external 'ISExec#files:ISDone.dll stdcall delayload';
function SrepInit(TmpPath:PAnsiChar;VirtMem,MaxSave:Cardinal):boolean; external 'SrepInit#files:ISDone.dll stdcall delayload';
function PrecompInit(TmpPath:PAnsiChar;VirtMem:cardinal;PrecompVers:single):boolean; external 'PrecompInit#files:ISDone.dll stdcall delayload';
function FileSearchInit(RecursiveSubDir:boolean):boolean; external 'FileSearchInit#files:ISDone.dll stdcall delayload';
function ISDoneStop:boolean; external 'ISDoneStop#files:ISDone.dll stdcall';
function ChangeLanguage(Language:AnsiString):boolean; external 'ChangeLanguage#files:ISDone.dll stdcall delayload';
function SuspendProc:boolean; external 'SuspendProc#files:ISDone.dll stdcall';
function ResumeProc:boolean; external 'ResumeProc#files:ISDone.dll stdcall';
function ProgressCallback(OveralPct,CurrentPct: integer;CurrentFile,TimeStr1,TimeStr2,TimeStr3:PAnsiChar): longword;
begin
if OveralPct<=Wizardform.ProgressGauge.Max then
Wizardform.Progressgauge.Position := OveralPct;
Result := ISDoneCancel;
TotalTimeLbl.Caption:=ExpandConstant('{cm:TTime}')+TimeStr2;
with WizardForm.ProgressGauge do begin
LabelCurrFileName.Caption:=SetupMessage(msgStatusExtractFiles)+': '+MinimizePathName(CurrentFile, LabelCurrFileName.Font, LabelCurrFileName.Width-ScaleX(100));
end;
end;
function LongintToStringTime(t:Longint):string;
var
h,m,s:integer;
begin
h:=t div 3600;
t:=t-h*3600;
m:=t div 60;
s:=t-m*60;
Result:='';
if h>0 then Result:=Result+IntToStr(h)+ ExpandConstant(' {cm:ORE} ');
if (m>0) or (h>0) then Result:=Result+IntToStr(m)+ExpandConstant(' {cm:MINUTI} ');
if (m>0) or (h>0) or (s>0) then Result:=Result+IntToStr(s)+ExpandConstant(' {cm:SECONDI} ');
end;
function PBProc(h:hWnd;Msg,wParam,lParam:Longint):Longint;
var
R,A:Longint;
dt,at,pr,i1,i2:Extended;
p:string;
tc:DWORD;
begin
Result:=CallWindowProc(PBOldProc,h,Msg,wParam,lParam);
if (Msg=$402) and (WizardForm.ProgressGauge.Position>WizardForm.ProgressGauge.Min) then begin
i1:=WizardForm.ProgressGauge.Position-WizardForm.ProgressGauge.Min;
i2:=WizardForm.ProgressGauge.Max-WizardForm.ProgressGauge.Min;
tc:=GetTickCount;
if (tc-eTime)>=1000 then begin
dt:=(tc-sTime)/1000;
at:=i2*dt/i1;
R:=Round(at-dt)
A:=Round(dt)
RemainingTimeLbl.Caption:=ExpandConstant('{cm:RIMANENTE} ')+LongintToStringTime(R);
ElapsedTimeLbl.Caption:=ExpandConstant('{cm:Elapsed} ')+LongintToStringTime(A);
eTime:=tc;
end;
pr:=i1*100/i2;
p:=''+Format('%f',[pr])+'%';
StringChange(p,',','.');
Percentuale.Caption:=WFCaption+p;
end;
end;
procedure AllCancel;
begin
SetWindowLong(WizardForm.ProgressGauge.Handle,-4,PBOldProc);
Percentuale.Caption:=WFCaption;
end;
procedure CancelButtonOnClick(Sender: TObject);
begin
SuspendProc;
//RollingBack.Show;
if MsgBox(SetupMessage(msgExitSetupMessage), mbConfirmation, MB_YESNO) = IDYES then ISDoneCancel:=1;
ResumeProc;
//RollingBack.Hide;
end;
procedure HideControls;
begin
CancelBtn.Hide;
LabelCurrFileName.Hide;
RemainingTimeLbl.Hide;
ElapsedTimeLbl.Hide;
end;
procedure InitializeWizard1();
begin
WizardForm.ProgressGauge.Top := ScaleY(46);
ElapsedTimeLbl := TLabel.Create(WizardForm);
with ElapsedTimeLbl do begin
Parent := WizardForm.InstallingPage;
Font.Size:=10;
Font.Color:=clYellow;
Font.Style := [fsBold];
Font.Name:='calibri';
SetBounds(0,90,WizardForm.ClientWidth-40,14);
end;
RemainingTimeLbl:=TLabel.Create(WizardForm);
with RemainingTimeLbl do begin
Parent:=WizardForm.InstallingPage;
SetBounds(216,90,WizardForm.ClientWidth-40,14);
Font.Size:=10;
Font.Color:=clYellow;
Font.Style := [fsBold];
Font.Name:='calibri';
end;
Percentuale := TLabel.Create(WizardForm);
with Percentuale do begin
Parent:= WizardForm.InstallingPage;
SetBounds(150,130,WizardForm.ClientWidth-40,14);
Font.Size:=20;
Font.Color:=clYellow;
Font.Style := [fsBold];
Font.Name:='calibri';
end;
CancelBtn := TButton.Create(WizardForm);
with CancelBtn do begin
Name := 'Cancel';
Parent := WizardForm;
Left := WizardForm.CancelButton.Left;
Top := WizardForm.CancelButton.Top;
Width := WizardForm.CancelButton.Width;
Height := WizardForm.CancelButton.Height;
OnClick:=#CancelButtonOnClick;
Font.Size:=8;
Font.Name:='calibri';
end;
LabelCurrFileName := TLabel.Create(WizardForm);
with LabelCurrFileName do begin
Parent := WizardForm.InstallingPage;
AutoSize := False;
Width := WizardForm.ProgressGauge.Width+ScaleX(30);
Left := ScaleX(0);
Top := ScaleY(30);
Font.Size:=8;
Font.Color:=clYellow;
Font.Name:='calibri';
end;
TotalTimeLbl := TLabel.Create(WizardForm);
with TotalTimeLbl do begin
Parent := WizardForm.FinishedPage;
AutoSize := False;
Width := 300;
Left := 180;
Top := 200;
Font.Size:=14;
Font.Color:=clYellow;
Font.Style := [fsBold];
Font.Name:='calibri';
Height := 35;
end;
end;
procedure CurPageChanged1(CurPageID: integer);
begin
HideControls;
if CurPageID=wpWelcome then
begin
end;
if CurPageID=wpSelectDir then
begin
end;
if CurPageID=wpInstalling then
begin
CancelBtn.Show;
LabelCurrFileName.Show;
RemainingTimeLbl.Show;
ElapsedTimeLbl.Show;
end;
if CurPageID=wpFinished then
begin
RemainingTimeLbl.Hide;
AllCancel;
HideControls;
end;
if (CurPageID = wpFinished) and ISDoneError then
begin
WizardForm.Caption:= SetupMessage(msgErrorTitle);
WizardForm.FinishedLabel.Font.Color:= clRed;
WizardForm.FinishedLabel.Caption:= SetupMessage(msgSetupAborted);
end;
end;
function CheckError:boolean;
begin
result:= not ISDoneError;
end;
procedure CurStepChanged1(CurStep: TSetupStep);
var
res, i, ResultCode: integer;
Arc1, Arc2: Array of String;
begin
If CurStep = ssInstall then begin
WizardForm.StatusLabel.Caption:='Installing The Game...';
sTime:=GetTickCount;
eTime:=sTime;
PBOldProc:=SetWindowLong(WizardForm.ProgressGauge.Handle,-4,CallBackProc(#PBProc,4));
#ifdef PrecompInside
ExtractTemporaryFile('CLS-precomp.dll');
ExtractTemporaryFile('packjpg_dll.dll');
ExtractTemporaryFile('packjpg_dll1.dll');
ExtractTemporaryFile('precomp.exe');
ExtractTemporaryFile('zlib1.dll');
ExtractTemporaryFile('facompress.dll');
#endif
#ifdef SrepInside
ExtractTemporaryFile('CLS-srep.dll');
#endif
#ifdef MSC
ExtractTemporaryFile('CLS-MSC.dll');
#endif
ExtractTemporaryFile('arc.ini');
ExtractTemporaryFile('unarc.dll');
ExtractTemporaryFile('English.ini');
ISDoneError:=false;
i:=1;
if (GetIniString('FreearcFile' + IntToStr(i),'Archive','',ExpandConstant('{tmp}\Setup.ini')) <> '') then
begin
WizardForm.ProgressGauge.Max:=0;
repeat
WizardForm.ProgressGauge.Max:= WizardForm.ProgressGauge.Max + 1000;
i:= i + 1;
until (GetIniString('FreearcFile' + IntToStr(i),'Archive','',ExpandConstant('{tmp}\Setup.ini')) = '');
end;
if ISDoneInit(ExpandConstant('{tmp}\records.inf'), $F777, 0,0,0, MainForm.Handle, 512, #ProgressCallback) then begin
repeat
ChangeLanguage('English');
if not SrepInit('',512,0) then ISDoneError := True;
if not PrecompInit('',128,0) then ISDoneError := True;
if not FileSearchInit(true) then ISDoneError := True;
i:=1;
if (GetIniString('FreearcFile' + IntToStr(i),'Archive','',ExpandConstant('{tmp}\Setup.ini')) <> '') then
begin
SetArrayLength(Arc1,4);
SetArrayLength(Arc2,4);
repeat
Arc1[0]:=ExpandConstant(GetIniString('FreearcFile' + IntToStr(i),'Archive','',ExpandConstant('{tmp}\Setup.ini')));
Arc1[1]:=ExpandConstant(GetIniString('FreearcFile' + IntToStr(i),'Output','',ExpandConstant('{tmp}\Setup.ini')));
Arc1[2]:=ExpandConstant(GetIniString('FreearcFile' + IntToStr(i),'Disk','1',ExpandConstant('{tmp}\Setup.ini')));
if Arc1[0] <> '' then
begin
if not FileExists(Arc1[0]) then
begin
if MsgBox(SetupMessage(msgChangeDiskTitle) +' '+'( '+ Arc1[2]+' )', mbError, MB_OKCANCEL) = IDCANCEL then ISDoneError := True;
end else begin
if not ISArcExtract( 0, 0, Arc1[0], Arc1[1], '', false, Arc1[3], ExpandConstant('{tmp}\arc.ini'), ExpandConstant('{app}'), False) then ISDoneError := True;
i:= i + 1;
end;
end;
until ((GetIniString('FreearcFile' + IntToStr(i),'Archive','',ExpandConstant('{tmp}\Setup.ini')) = '') or (ISDoneError = True));
end;
until true;
ISDoneStop;
end;
AllCancel;
HideControls;
WizardForm.ProgressGauge.Hide;
end;
if (CurStep=ssPostInstall) and ISDoneError then begin
WizardForm.StatusLabel.Caption:=SetupMessage(msgStatusRollback);
TotalTimeLbl.Caption:='';
Exec(ExpandConstant('{uninstallexe}'), '/VERYSILENT','', sw_Hide, ewWaitUntilTerminated, ResultCode);
end;
end;
function InitializeSetup1: Boolean;
var
Uninstall,Location: string;
ResultCode: Integer;
begin
if not FileExists(ExpandConstant('{tmp}\CallbackCtrl.dll')) then ExtractTemporaryFile('CallbackCtrl.dll');
ExtractTemporaryFile('Setup.ini');
if RegQueryStringValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{#MyAppName}_is1','UninstallString', Uninstall) then
Uninstall:=RemoveQuotes(Uninstall);
begin
if not Exec(Uninstall, ' /SILENT', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then
RegQueryStringValue(HKLM, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{#MyAppName}_is1','InstallLocation', Location);
end;
Result:=True;
end;
[Setup]
; --- Source: 3.iss ------------------------------------------------------------
[code]
var
WelcomeLabel1, WelcomeLabel2, FinishedLabel, FinishedHeadingLabel: TLabel;
PageNameLabel, PageDescriptionLabel: TLabel;
procedure InitializeWizard2();
begin
WizardForm.WizardBitmapImage.Width := ScaleX(497);
WizardForm.WizardBitmapImage2.Width := ScaleX(497);
{ WelcomeLabel1 }
WizardForm.WelcomeLabel1.Hide;
WelcomeLabel1 := TLabel.Create(WizardForm);
with WizardForm.WelcomeLabel1 do
begin
WelcomeLabel1.Parent := Parent;
WelcomeLabel1.SetBounds(Left, Top, Width, Height);
WelcomeLabel1.AutoSize := AutoSize;
WelcomeLabel1.Font := Font;
WelcomeLabel1.Font.Color := clWhite;
WelcomeLabel1.Transparent := True;
WelcomeLabel1.WordWrap := WordWrap;
WelcomeLabel1.Caption := Caption;
end;
{ WelcomeLabel2 }
WizardForm.WelcomeLabel2.Hide;
WelcomeLabel2 := TLabel.Create(WizardForm);
with WizardForm.WelcomeLabel2 do
begin
WelcomeLabel2.Parent := Parent;
WelcomeLabel2.SetBounds(Left, Top, Width, Height);
WelcomeLabel2.AutoSize := AutoSize;
WelcomeLabel2.Font := Font;
WelcomeLabel2.Font.Color := clWhite;
WelcomeLabel2.Transparent := True;
WelcomeLabel2.WordWrap := WordWrap;
WelcomeLabel2.Caption := Caption;
end;
WizardForm.WizardSmallBitmapImage.SetBounds(ScaleX(0), ScaleY(0), WizardForm.MainPanel.Width, WizardForm.MainPanel.Height);
{ PageNameLabel }
WizardForm.PageNameLabel.Hide;
PageNameLabel := TLabel.Create(WizardForm);
with WizardForm.PageNameLabel do
begin
PageNameLabel.Parent := Parent;
PageNameLabel.SetBounds(Left, Top, Width, Height);
PageNameLabel.AutoSize := AutoSize;
PageNameLabel.Font := Font;
PageNameLabel.Font.Color := clYellow;
PageNameLabel.Transparent := True;
PageNameLabel.WordWrap := WordWrap;
end;
{ PageDescriptionLabel }
WizardForm.PageDescriptionLabel.Hide;
PageDescriptionLabel:= TLabel.Create(WizardForm);
with WizardForm.PageDescriptionLabel do
begin
PageDescriptionLabel.Parent := Parent;
PageDescriptionLabel.SetBounds(Left, Top, Width, Height);
PageDescriptionLabel.AutoSize := AutoSize;
PageDescriptionLabel.Font := Font;
PageDescriptionLabel.Font.Color := clYellow;
PageDescriptionLabel.Transparent := True;
PageDescriptionLabel.WordWrap := WordWrap;
end;
{ FinishedHeadingLabel }
WizardForm.FinishedHeadingLabel.Hide;
FinishedHeadingLabel := TLabel.Create(WizardForm);
with WizardForm.FinishedHeadingLabel do
begin
FinishedHeadingLabel.Parent := Parent;
FinishedHeadingLabel.SetBounds(Left, Top, Width, Height);
FinishedHeadingLabel.AutoSize := AutoSize;
FinishedHeadingLabel.Font := Font;
FinishedHeadingLabel.Font.Color := clWhite;
FinishedHeadingLabel.Transparent := True;
FinishedHeadingLabel.WordWrap := WordWrap;
FinishedHeadingLabel.Caption := Caption;
end;
{ FinishedLabel }
WizardForm.FinishedLabel.Hide;
FinishedLabel := TLabel.Create(WizardForm);
with WizardForm.FinishedLabel do
begin
FinishedLabel.Parent := Parent;
FinishedLabel.SetBounds(Left, Top, Width, Height);
FinishedLabel.AutoSize := AutoSize;
FinishedLabel.Font := Font;
FinishedLabel.Font.Color := clWhite;
FinishedLabel.Transparent := True;
FinishedLabel.WordWrap := WordWrap;
end;
end;
procedure CurPageChanged2(CurPageID: Integer);
begin
begin
PageNameLabel.Caption := WizardForm.PageNameLabel.Caption;
PageDescriptionLabel.Caption := WizardForm.PageDescriptionLabel.Caption;
FinishedLabel.Caption := WizardForm.FinishedLabel.Caption;
end;
if (CurPageID = wpFinished) and ISDoneError then
begin
WizardForm.Caption:= SetupMessage(msgErrorTitle);
WizardForm.FinishedLabel.Font.Color:= clRed;
WizardForm.FinishedLabel.Caption:= SetupMessage(msgSetupAborted);
end;
end;
[Setup]
; --- Dispatching code ------------------------------------------------------------
[Code]
procedure InitializeWizard();
begin
InitializeWizard1();
InitializeWizard2();
end;
procedure CurPageChanged(CurPageID: Integer);
begin
CurPageChanged1(CurPageID);
CurPageChanged2(CurPageID);
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
CurStepChanged1(CurStep);
end;
function InitializeSetup(): Boolean;
begin
Result := InitializeSetup1(); if not Result then exit;
end;
You'r Label's are messed up. If you are creating a new label in the place of an existing one make sure you use it everywhere. Dont mix it up!
Though i would not proceed with a code such as that in its current state...here's a fix.
Set the parent of FinishedLabel to WizardForm.FinishedPage
with WizardForm.FinishedLabel do begin
FinishedLabel.Parent:=WizardForm.FinishedPage;
....
end;
and use that FinishedLabel to display the error message.
if (CurPageID = wpFinished) and ISDoneError then
begin
WizardForm.Caption:= SetupMessage(msgErrorTitle);
FinishedLabel.Font.Color:= clRed;
WizardForm.FinishedLabel.Caption:= SetupMessage(msgSetupAborted);
end;
in procedure CurPageChanged2.
Btw the code is very clumsy. Please take some time to go through your code and organise it before you go any further.
Edit: The updated code. I have tested this code in my PC and its working fine. Replace the CurPageChanged2 with this.
procedure CurPageChanged2(CurPageID: Integer);
begin
begin
PageNameLabel.Caption := WizardForm.PageNameLabel.Caption;
PageDescriptionLabel.Caption := WizardForm.PageDescriptionLabel.Caption;
FinishedLabel.Caption := WizardForm.FinishedLabel.Caption;
end;
if (CurPageID = wpFinished) and ISDoneError then
begin
WizardForm.Caption:= SetupMessage(msgErrorTitle);
FinishedLabel.Font.Color:= clRed; // changed
FinishedHeadingLabel.Font.Color:= clRed; // changed
WizardForm.FinishedLabel.Caption:= SetupMessage(msgSetupAborted);
end;
end;

Using combo box to select what paths and registry keys to use

Purpose:
With Inno Setup I want to create an installer with a dropdown list in the install wizard.
The choice made in the wizards defines 2 variables:
One for the folder location and the other for the location in the registry.
Problem:
Variables are defined as global in [Code], but are not used in [Files] and [Registry]
Code:
The two variables are: strData1 & strData2
I was trying to retrieve them with functions: strData1returner & strData2returner
[Setup]
...
[Dirs]
Name: "C:\Program Files\CompanyName\{code:strData1returner}"
[Files]
Source: "C:\SomeDll.dll"; \
DestDir: "C:\Program Files\CompanyName\{code:strData1returner}\"; Flags: ignoreversion;
[Registry]
Root: HKCU; subkey: "{code:strData2returner}"; flags: createvalueifdoesntexist
[Code]
var
Button: TNewButton;
ComboBox: TNewComboBox;
CustomPage: TWizardPage;
strData1: string;
strData2: string;
procedure ComboBoxChange(Sender: TObject);
begin
case ComboBox.ItemIndex of
0:
begin
strData1 := 'Subfolder';
strData2 := 'SOFTWARE\CompanyName';
end;
end;
end;
procedure InitializeWizard;
var
DescLabel: TLabel;
begin
CustomPage := CreateCustomPage(wpSelectDir, 'Caption', 'Description');
DescLabel := TLabel.Create(WizardForm);
DescLabel.Parent := CustomPage.Surface;
DescLabel.Left := 0;
DescLabel.Top := 0;
DescLabel.Caption := 'Select an item...';
ComboBox := TNewComboBox.Create(WizardForm);
ComboBox.Parent := CustomPage.Surface;
ComboBox.Left := 0;
ComboBox.Top := DescLabel.Top + DescLabel.Height + 6;
ComboBox.Width := 220;
ComboBox.Style := csDropDownList;
ComboBox.Items.Add('Choice1');
ComboBox.ItemIndex := 0;
ComboBox.OnChange := #ComboBoxChange;
end;
function strData1returner(Param: String): String;
begin
Result := strData1;
end;
function strData2returner(Param: String): String;
begin
Result := strData2;
end;
There was only a single option: "Choice1" - So I added a second (Choice2), and alternative values for that second option, under index 1.
You should also initialize the two variables in InitializeWizard, in case the user doesn't change the combobox value. The ComboBoxChange procedure is only executed when the value actually changes, not when the default is accepted via no action.
Also, in trying to reproduce your problem I noticed a syntax problem causing compilation errors with createvalueifdoesntexistcreatevalueifdoesntexist - naturally, you just need one of those.
[Dirs]
Name: "C:\Program Files\CompanyName\{code:strData1returner}"
[Files]
Source: "C:\SomeDll.dll"; DestDir: "C:\Program Files\CompanyName\{code:strData1returner}\"; Flags: ignoreversion;
[Registry]
Root: HKCU; subkey:"{code:strData2returner}"; flags: createvalueifdoesntexist
[Code]
var
Button: TNewButton;
ComboBox: TNewComboBox;
CustomPage: TWizardPage;
strData1: string;
strData2: string;
procedure ComboBoxChange(Sender: TObject);
begin
case ComboBox.ItemIndex of
0:
begin
strData1 := 'Subfolder';
strData2 := 'SOFTWARE\CompanyName';
end;
1:
begin
strData1 := 'Subfolder2';
strData2 := 'SOFTWARE\CompanyName2';
end;
end;
end;
procedure InitializeWizard;
var
DescLabel: TLabel;
begin
CustomPage := CreateCustomPage(wpSelectDir, 'Caption', 'Description');
DescLabel := TLabel.Create(WizardForm);
DescLabel.Parent := CustomPage.Surface;
DescLabel.Left := 0;
DescLabel.Top := 0;
DescLabel.Caption := 'Select an item...';
ComboBox := TNewComboBox.Create(WizardForm);
ComboBox.Parent := CustomPage.Surface;
ComboBox.Left := 0;
ComboBox.Top := DescLabel.Top + DescLabel.Height + 6;
ComboBox.Width := 220;
ComboBox.Style := csDropDownList;
ComboBox.Items.Add('Choice1');
ComboBox.Items.Add('Choice2');
ComboBox.ItemIndex := 0;
ComboBox.OnChange := #ComboBoxChange;
strData1 := 'Subfolder';
strData2 := 'SOFTWARE\CompanyName';
end;
function strData1returner(Param: String): String;
begin
Result := strData1;
end;
function strData2returner(Param: String): String;
begin
Result := strData2;
end;
The code above is working as I think you expect it to here.
Actually your attempt to use global variables just complicates the code.
Access the ComboBox.ItemIndex directly from scripted constant implementations like:
[Dirs]
Name: "{app}\{code:GetSelectedSubfolder}"
[Files]
Source: "C:\SomeDll.dll"; DestDir: "{app}\{code:GetSelectedSubfolder}"
[Registry]
Root: HKCU; Subkey: "{code:GetSelectedSubkey}"
[Code]
var
ComboBox: TNewComboBox;
procedure InitializeWizard;
{ ... }
begin
{ ... }
ComboBox := TNewComboBox.Create(WizardForm);
{ ... }
ComboBox.Items.Add('Choice1');
ComboBox.Items.Add('Choice2');
ComboBox.ItemIndex := 0;
end;
function GetSelectedSubfolder(Param: String): String;
begin
case ComboBox.ItemIndex of
0: Result := 'Subfolder1';
1: Result := 'Subfolder2';
end;
end;
function GetSelectedSubkey(Param: String): String;
begin
case ComboBox.ItemIndex of
0: Result := 'SOFTWARE\CompanyName1';
1: Result := 'SOFTWARE\CompanyName2';
end;
end;
You can create global variables like this:
#define CustomVarName "Value"
More specific information about here: #define

How to modify the Local.config from Innosetup script

I'm having some issues getting this code to function correctly. What I'm trying to accomplish is a user puts in a ConnectionString (during the setup) and its places in a already formatted file. The file is Local.config in the {app}\local directory. I was able to get it to work a few times in the {app} director but now I have nothing.
Source: "Local\Local.config"; DestDir: "{app}\Local"; AfterInstall: ConvertConfig('Local.config'); Flags: ignoreversion
var
UserPage: TInputQueryWizardPage;
xmlFileName: String;
procedure InitializeWizard;
begin
UserPage := CreateInputQueryPage(wpWelcome,
'Pryme Connection String', 'SQL Connecton String', 'Please Enter In SQL Connection String then click Next.');
UserPage.Add('connectionString:', False);
end;
procedure ConvertConfig(xmlFileName: String);
var
xmlFile: String;
xmlInhalt: TArrayOfString;
strName: String;
strTest: String;
tmpConfigFile: String;
k: Integer;
begin
xmlFile := ExpandConstant('{app}') + '\' + 'Local.config';
tmpConfigFile:= ExpandConstant('{app}') + '\config.tmp';
strName := UserPage.Values[0];
if (FileExists(xmlFile)) then begin
//alles in string array speichern
LoadStringsFromFile(xmlFile, xmlInhalt);
//durch Array iterieren
for k:=0 to GetArrayLength(xmlInhalt)-1 do
begin
strTest := xmlInhalt[k];
if (Pos('name="Pryme"', strTest) <> 0 ) then
begin
strTest := ' <add name="Pryme" connectionString="' + strName + '"/> ';
end;
SaveStringToFile(tmpConfigFile, strTest + #13#10, True);
end;
DeleteFile(xmlFile); //delete the old exe.config
RenameFile(tmpConfigFile,xmlFile);
end;
end;
I didn't point to the correct directory.Below is the correct working code.
Source: "Local\Local.config"; DestDir: "{app}\Local"; AfterInstall: ConvertConfig('Local.config'); Flags: ignoreversion
var
UserPage: TInputQueryWizardPage;
xmlFileName: String;
procedure InitializeWizard;
begin
UserPage := CreateInputQueryPage(wpWelcome,
'Pryme Connection String', 'SQL Connecton String', 'Please Enter In SQL Connection String then click Next.');
UserPage.Add('connectionString:', False);
end;
procedure ConvertConfig(xmlFileName: String);
var
xmlFile: String;
xmlInhalt: TArrayOfString;
strName: String;
strTest: String;
tmpConfigFile: String;
k: Integer;
begin
xmlFile := ExpandConstant('{app}\local') + '\' + 'Local.config';
tmpConfigFile:= ExpandConstant('{app}\local') + '\config.tmp';
strName := UserPage.Values[0];
if (FileExists(xmlFile)) then begin
//alles in string array speichern
LoadStringsFromFile(xmlFile, xmlInhalt);
//durch Array iterieren
for k:=0 to GetArrayLength(xmlInhalt)-1 do
begin
strTest := xmlInhalt[k];
if (Pos('name="Pryme"', strTest) <> 0 ) then
begin
strTest := ' <add name="Pryme" connectionString="' + strName + '"/> ';
end;
SaveStringToFile(tmpConfigFile, strTest + #13#10, True);
end;
DeleteFile(xmlFile); //delete the old exe.config
RenameFile(tmpConfigFile,xmlFile);
end;
end;

Inno Setup remember Custom checkboxes state in next install

is there a way to remember state (selected/deselected) of custom checkboxes on custom pages when user is running setup next time or reinstall? Something like in classic ComponentsList.
Installer has cca. 100 options (custom checkboxes/radiobuttons) on 7 custom pages. It would be nice if users have predefined their choices from previous install.
My code looks like this:
[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program
[Files]
Source: ReadMe1.rtf; Flags: dontcopy
Source: ReadMe2.rtf; Flags: dontcopy
Source: ReadMe3.rtf; Flags: dontcopy
Source: Image1.bmp; Flags: dontcopy
Source: Image2.bmp; Flags: dontcopy
Source: Image3.bmp; Flags: dontcopy
Source: Files\*; DestDir: {app}\add; Flags: ignoreversion recursesubdirs createallsubdirs; Check: CheckedBox(2)
[Code]
var
Page: TWizardPage;
ListBox: TNewCheckListBox;
Memo: TRichEditViewer;
CheckLabel: TLabel;
MouseY: integer;
BitmapImage: TBitmapImage;
InfoBmp: array of TBitmap;
function CheckedBox(ItemNumber: integer): Boolean;
begin
Result:= ListBox.Checked[ItemNumber];
end;
procedure CheckOnClick (Sender: TObject);
begin
if MouseY < ListBox.Items.Count then
begin
ListBox.Checked[MouseY]:= Not(ListBox.Checked[MouseY]);
end;
end;
procedure CheckMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
MouseY:= Y/ScaleY(16);
if MouseY < ListBox.Items.Count then
begin
Memo.RTFText:= TStrings(ListBox.ItemObject[MouseY]).Text;
BitmapImage.Bitmap:= InfoBmp[MouseY];
end;
end;
procedure InitializeWizard();
var
i: integer;
begin
ExtractTemporaryFile('ReadMe1.rtf'); ˙
ExtractTemporaryFile('ReadMe2.rtf');
ExtractTemporaryFile('ReadMe3.rtf');
ExtractTemporaryFile('Image1.bmp');
ExtractTemporaryFile('Image2.bmp');
ExtractTemporaryFile('Image3.bmp');
Page:=CreateCustomPage(wpWelcome, 'Title', 'Description')
ListBox:= TNewCheckListBox.Create(Page);
with ListBox do
begin
Left := 15
Top := 0
Width := 200
Height := 149
Parent := Page.Surface
AddCheckBox('Global', '', 0, True, True, True, True, TStringList.Create);
AddCheckBox('Option 1', '', 1, True, True, False, True, TStringList.Create);
AddCheckBox('Option 2', '', 1, True, True, False, True, TStringList.Create);
TStrings(ItemObject[0]).LoadFromFile(ExpandConstant('{tmp}\ReadMe1.rtf'));
TStrings(ItemObject[1]).LoadFromFile(ExpandConstant('{tmp}\ReadMe2.rtf'));
TStrings(ItemObject[2]).LoadFromFile(ExpandConstant('{tmp}\ReadMe3.rtf'));
end;
Memo:= TRichEditViewer.Create(Page);
with Memo do
begin
Left := ListBox.Left + ListBox.Width + 8;
Top := ListBox.Top;
Width := ListBox.Width;
Height := ListBox.Height;
Color := clBtnFace;
Enabled := False;
BorderStyle := bsNone;
Parent := Page.Surface;
end;
CheckLabel:= TLabel.Create(Page);
with CheckLabel do
begin
Width :=ListBox.Width;
Height :=ListBox.Height;
Autosize :=False;
Transparent :=True;
OnMouseMove :=#CheckMouseMove;
OnClick :=#CheckOnClick;
Parent :=ListBox;
Cursor := 1;
end;
BitmapImage := TBitmapImage.Create(Page);
with BitmapImage do
begin
AutoSize := True;
Left := ListBox.Left;
Top := ListBox.Top + ListBox.Height + 8;
Width := ListBox.Width;
Height := 32;
Parent := Page.Surface;
end;
for i:=0 to ListBox.Items.Count - 1 do
begin
SetArrayLength(InfoBmp, i+1);
InfoBmp[i]:= TBitmap.Create;
end;
InfoBmp[0].LoadFromFile(ExpandConstant('{tmp}\Image1.bmp'));
InfoBmp[1].LoadFromFile(ExpandConstant('{tmp}\Image2.bmp'));
InfoBmp[2].LoadFromFile(ExpandConstant('{tmp}\Image3.bmp'));
end;
Yes, use the GetPreviousData/SetPreviousData functions and see the CodeDlg.iss and Setup.iss example scripts:
http://www.jrsoftware.org/ishelp/index.php?topic=isxfunc_getpreviousdata
http://www.jrsoftware.org/ishelp/index.php?topic=isxfunc_setpreviousdata
https://jrsoftware.github.io/issrc/Examples/CodeDlg.iss
https://jrsoftware.github.io/issrc/setup.iss

INNO Setup: "About" button position

I'm having problems with the About button in the components page.
It works fine in the first page, when it is smaller but it looks like this (see the following screenshot) in this part.
The code is this one:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
DefaultGroupName=My Program
UninstallDisplayIcon={app}\MyProg.exe
OutputDir=userdocs:Inno Setup Examples Output
[Types]
Name: "full"; Description: "Full installation"
Name: "compact"; Description: "Compact installation"
Name: "custom"; Description: "Custom installation"; Flags: iscustom
[Components]
Name: "program"; Description: "Program Files"; Types: full compact custom; Flags: fixed
Name: "help"; Description: "Help File"; Types: full
Name: "readme"; Description: "Readme File"; Types: full
Name: "readme\en"; Description: "English"; Flags: exclusive
Name: "readme\de"; Description: "German"; Flags: exclusive
[Code]
procedure AboutButtonOnClick(Sender: TObject);
begin
MsgBox('This is a demo of how to create a button!', mbInformation, mb_Ok);
end;
procedure CreateAboutButton(ParentForm: TSetupForm; CancelButton: TNewButton);
var
AboutButton: TNewButton;
begin
AboutButton := TNewButton.Create(ParentForm);
AboutButton.Left := ParentForm.ClientWidth - CancelButton.Left - CancelButton.Width;
AboutButton.Top := CancelButton.Top;
AboutButton.Width := CancelButton.Width;
AboutButton.Height := CancelButton.Height;
AboutButton.Caption := '&About...';
AboutButton.OnClick := #AboutButtonOnClick;
AboutButton.Parent := ParentForm;
end;
procedure InitializeWizard1();
begin
CreateAboutButton(WizardForm, WizardForm.CancelButton);
end;
type
TPositionStorage = array of Integer;
var
CompPageModified: Boolean;
CompPagePositions: TPositionStorage;
procedure SaveComponentsPage(out Storage: TPositionStorage);
begin
SetArrayLength(Storage, 10);
Storage[0] := WizardForm.Height;
Storage[1] := WizardForm.NextButton.Top;
Storage[2] := WizardForm.BackButton.Top;
Storage[3] := WizardForm.CancelButton.Top;
Storage[4] := WizardForm.ComponentsList.Height;
Storage[5] := WizardForm.OuterNotebook.Height;
Storage[6] := WizardForm.InnerNotebook.Height;
Storage[7] := WizardForm.Bevel.Top;
Storage[8] := WizardForm.BeveledLabel.Top;
Storage[9] := WizardForm.ComponentsDiskSpaceLabel.Top;
end;
procedure LoadComponentsPage(const Storage: TPositionStorage;
HeightOffset: Integer);
begin
if GetArrayLength(Storage) <> 10 then
RaiseException('Invalid storage array length.');
WizardForm.Height := Storage[0] + HeightOffset;
WizardForm.NextButton.Top := Storage[1] + HeightOffset;
WizardForm.BackButton.Top := Storage[2] + HeightOffset;
WizardForm.CancelButton.Top := Storage[3] + HeightOffset;
WizardForm.ComponentsList.Height := Storage[4] + HeightOffset;
WizardForm.OuterNotebook.Height := Storage[5] + HeightOffset;
WizardForm.InnerNotebook.Height := Storage[6] + HeightOffset;
WizardForm.Bevel.Top := Storage[7] + HeightOffset;
WizardForm.BeveledLabel.Top := Storage[8] + HeightOffset;
WizardForm.ComponentsDiskSpaceLabel.Top := Storage[9] + HeightOffset;
end;
procedure InitializeWizard2();
begin
CompPageModified := False;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
if CurpageID = wpSelectComponents then
begin
SaveComponentsPage(CompPagePositions);
LoadComponentsPage(CompPagePositions, 200);
CompPageModified := True;
end
else
if CompPageModified then
begin
LoadComponentsPage(CompPagePositions, 0);
CompPageModified := False;
end;
end;
procedure InitializeWizard();
begin
InitializeWizard1();
InitializeWizard2();
end;
Could anyone help me? Thanks so much in advanced.
Due to a lack of missing Anchors property you will have to move that button by yourself when the form is being resized. So, what you can do in your script is publish the button instance and extend an existing position storage of the vertical position of your button. In code it may look like this:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
DefaultGroupName=My Program
UninstallDisplayIcon={app}\MyProg.exe
OutputDir=userdocs:Inno Setup Examples Output
[Types]
Name: "full"; Description: "Full installation"
Name: "compact"; Description: "Compact installation"
Name: "custom"; Description: "Custom installation"; Flags: iscustom
[Components]
Name: "program"; Description: "Program Files"; Types: full compact custom; Flags: fixed
Name: "help"; Description: "Help File"; Types: full
Name: "readme"; Description: "Readme File"; Types: full
Name: "readme\en"; Description: "English"; Flags: exclusive
Name: "readme\de"; Description: "German"; Flags: exclusive
[Code]
type
TPositionStorage = array of Integer;
var
AboutButton: TNewButton;
CompPageModified: Boolean;
CompPagePositions: TPositionStorage;
procedure AboutButtonOnClick(Sender: TObject);
begin
MsgBox('This is a demo of how to create a button!', mbInformation, mb_Ok);
end;
function CreateAboutButton(ParentForm: TSetupForm; CancelButton: TNewButton): TNewButton;
begin
Result := TNewButton.Create(ParentForm);
Result.Left := ParentForm.ClientWidth - CancelButton.Left - CancelButton.Width;
Result.Top := CancelButton.Top;
Result.Width := CancelButton.Width;
Result.Height := CancelButton.Height;
Result.Caption := '&About...';
Result.OnClick := #AboutButtonOnClick;
Result.Parent := ParentForm;
end;
procedure SaveComponentsPage(out Storage: TPositionStorage);
begin
SetArrayLength(Storage, 11);
Storage[0] := AboutButton.Top;
Storage[1] := WizardForm.Height;
Storage[2] := WizardForm.NextButton.Top;
Storage[3] := WizardForm.BackButton.Top;
Storage[4] := WizardForm.CancelButton.Top;
Storage[5] := WizardForm.ComponentsList.Height;
Storage[6] := WizardForm.OuterNotebook.Height;
Storage[7] := WizardForm.InnerNotebook.Height;
Storage[8] := WizardForm.Bevel.Top;
Storage[9] := WizardForm.BeveledLabel.Top;
Storage[10] := WizardForm.ComponentsDiskSpaceLabel.Top;
end;
procedure LoadComponentsPage(const Storage: TPositionStorage;
HeightOffset: Integer);
begin
if GetArrayLength(Storage) <> 11 then
RaiseException('Invalid storage array length.');
AboutButton.Top := Storage[0] + HeightOffset;
WizardForm.Height := Storage[1] + HeightOffset;
WizardForm.NextButton.Top := Storage[2] + HeightOffset;
WizardForm.BackButton.Top := Storage[3] + HeightOffset;
WizardForm.CancelButton.Top := Storage[4] + HeightOffset;
WizardForm.ComponentsList.Height := Storage[5] + HeightOffset;
WizardForm.OuterNotebook.Height := Storage[6] + HeightOffset;
WizardForm.InnerNotebook.Height := Storage[7] + HeightOffset;
WizardForm.Bevel.Top := Storage[8] + HeightOffset;
WizardForm.BeveledLabel.Top := Storage[9] + HeightOffset;
WizardForm.ComponentsDiskSpaceLabel.Top := Storage[10] + HeightOffset;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
if CurpageID = wpSelectComponents then
begin
SaveComponentsPage(CompPagePositions);
LoadComponentsPage(CompPagePositions, 200);
CompPageModified := True;
end
else
if CompPageModified then
begin
LoadComponentsPage(CompPagePositions, 0);
CompPageModified := False;
end;
end;
procedure InitializeWizard();
begin
CompPageModified := False;
AboutButton := CreateAboutButton(WizardForm, WizardForm.CancelButton);
end;
In my case I put an about button in the same row as the back and next and cancel buttons.
In this way it does not matter if a page is resized.
The code looks as:
// Create an About button
AboutButton := TButton.Create(WizardForm);
with AboutButton do
begin
Parent := WizardForm;
Left := WizardForm.ClientWidth - CancelButton.Left - CommonWidth;
Top := CancelButton.Top;
Width := CommonWidth;
Height := CommonHeight;
Caption := ExpandConstant('{cm:About}');
OnClick := #HelpButtonClick;
ShowHint := True;
Hint := ExpandConstant('{cm:AboutHint}');
Name := 'AboutButton';
end;
In the initialize setup routine I put the lines:
CommonWidth := ScaleX(75); // Standard width for new buttons
CommonHeight := ScaleY(23); // Standard heigth for new buttons

Resources