Inno setup+isdone counter timer - inno-setup

Help modify the time I am not getting much time is left and the elapsed time of installation is appearing on the page status has to appear on the page installing I got here on the site script time can someone check my script and point out the error The script I use isdone more time Sample image of what I want I am not able to post complete script.iss download link full
enter link description here
[Code]
////////////////////////////////////ISDONE///////////////////////////
const
PCFonFLY=true;
notPCFonFLY=false;
var
LabelPct1,LabelCurrFileName,LabelTime1,LabelTime2: TLabel; //Desativa - LabelTime3
ISDoneProgressBar1: TNewProgressBar;
MyCancelButton: TButton;
ISDoneCancel:integer;
ISDoneError:boolean;
PCFVer:double;
type
TCallback = function (OveralPct,CurrentPct:
integer;CurrentFile,TimeStr1,TimeStr2,TimeStr3:PAnsiChar): longword;
function WrapCallback(callback:TCallback; paramcount:integer):longword;external
'wrapcallback#files:ISDone.dll stdcall delayload';
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 ISDoneInit(RecordFileName:AnsiString; TimeType,Comp1,Comp2,Comp3:Cardinal;
WinHandle, NeededMem:longint; callback:TCallback):boolean; external
'ISDoneInit#files:ISDone.dll stdcall';
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<=1000 then ISDoneProgressBar1.Position := OveralPct;
LabelPct1.Caption := IntToStr(OveralPct div 10)+'.'+chr(48 + OveralPct mod 10)+'%';
// LabelCurrFileName.Caption:='Instalando arquivos.. '+MinimizePathName(CurrentFile,
LabelCurrFileName.Font, LabelCurrFileName.Width-ScaleX(100));
LabelCurrFileName.Caption:=ExpandConstant('')+MinimizePathName(ExpandConstant('{app}\
')+CurrentFile, LabelCurrFileName.Font,WizardForm.FilenameLabel.Width);
LabelTime1.Caption:=ExpandConstant('{cm:ElapsedTime} ')+TimeStr2;
LabelTime2.Caption:=ExpandConstant('{cm:RemainingTime} ')+TimeStr1;
// LabelTime3.Caption:=ExpandConstant('{cm:AllElapsedTime}')+TimeStr3;
Result := ISDoneCancel;
end;
procedure CancelButtonOnClick(Sender: TObject);
begin
SuspendProc;
if MsgBox(SetupMessage(msgExitSetupMessage), mbConfirmation, MB_YESNO) = IDYES then
ISDoneCancel:=1;
ResumeProc;
end;
procedure HideControls;
begin
WizardForm.FileNamelabel.Hide;
ISDoneProgressBar1.Hide;
LabelPct1.Hide;
LabelCurrFileName.Hide;
LabelTime1.Hide;
LabelTime2.Hide;
MyCancelButton.Hide;
end;
procedure CreateControls;
var PBTop:integer;
begin
PBTop:=ScaleY(165); //165
ISDoneProgressBar1 := TNewProgressBar.Create(WizardForm);
with ISDoneProgressBar1 do begin
Parent := WizardForm; //:= WizardForm.InstallingPage;
Height := ScaleY(20); //WizardForm.ProgressGauge.Height;
Left := ScaleX(65);
Top := PBTop;
Width := ScaleX(470);
Max := 1000;
end;
LabelPct1 := TLabel.Create(WizardForm);
with LabelPct1 do begin
Parent := WizardForm;
AutoSize := true;
Font.Height:=-25;
Left := ISDoneProgressBar1.Left -30 + ISDoneProgressBar1.Width div 2;
Top := ISDoneProgressBar1.Top + ScaleY(80);
Width := ScaleX(80);
end;
LabelCurrFileName := TLabel.Create(WizardForm);
with LabelCurrFileName do begin
Parent := WizardForm;
AutoSize := False;
Width := ISDoneProgressBar1.Width+ScaleX(30);
Left := ScaleX(65);
Top := ScaleY(140);
Height :=ScaleY(25);
// Font.Color:= clWhite;
Font.Size:= 10;
end;
LabelTime1 := TLabel.Create(WizardForm);
with LabelTime1 do begin
Parent := WizardForm;
AutoSize := False;
Width := ISDoneProgressBar1.Width div 2;
Left := ScaleX(65);
Top := PBTop + ScaleY(30);
Height :=ScaleY(25);
Font.Size:= 8;
end;
LabelTime2 := TLabel.Create(WizardForm);
with LabelTime2 do begin
Parent := WizardForm;
AutoSize := False;
Width := ScaleX(200);
Left := Scalex (360); //Original 335 fonte 10
Top := LabelTime1.Top;
Height :=ScaleY(25);
Font.Size:= 8;
end;
// LabelTime3 := TLabel.Create(WizardForm);
// with LabelTime3 do begin
// Parent := WizardForm; //FinishedPage para aparecer na ultima pagina
// AutoSize := False;
// Font.Color:= clWhite; //Black
// Width := 250;
// Left := 10;
// Top := 330;
// Height :=ScaleY(25);
// Font.Size:= 8;
// end;
MyCancelButton:=TButton.Create(WizardForm);
with MyCancelButton do begin
Parent := WizardForm;
Top := ScaleY(360);
Left := ScaleX(410);
Width := ScaleX(90);
Height := ScaleY(25);
Caption := 'Cancelar';
Top:=WizardForm.cancelbutton.top;
OnClick:=#CancelButtonOnClick;
end;
end;
////////////////////////////////////CONTADOR/COUNTER/////////////////////////
function GetTickCount: DWORD; external 'GetTickCount#kernel32.dll stdcall';
var
StartTick: DWORD;
PercentLabel: TNewStaticText;
ElapsedLabel: TNewStaticText;
RemainingLabel: TNewStaticText;
function TicksToStr(Value: DWORD): string;
var
I: DWORD;
Hours, Minutes, Seconds: Integer;
begin
I := Value div 1000;
Seconds := I mod 60;
I := I div 60;
Minutes := I mod 60;
I := I div 60;
Hours := I mod 24;
Result := Format('%.2d:%.2d:%.2d', [Hours, Minutes, Seconds]);
end;
procedure InitializeWizard4();
begin
PercentLabel := TNewStaticText.Create(WizardForm);
PercentLabel.Parent := WizardForm;
PercentLabel.AutoSize := true;
PercentLabel.Font.Height:=-25; //SetBounds(245,220,150,20)
PercentLabel.Left := ScaleX(245); //esquerda
PercentLabel.Top := ScaleY(220); //altura de cima para baixo
PercentLabel.Width := ScaleX(150); //comprimento
PercentLabel.Height := ScaleY(20); //tamanho
ElapsedLabel := TNewStaticText.Create(WizardForm);
ElapsedLabel.Parent := WizardForm;
ElapsedLabel.AutoSize := False;
ElapsedLabel.Font.Size:= 8; //SetBounds(65,190,150,20)
ElapsedLabel.Left := ScaleX(65);
ElapsedLabel.Top := ScaleY(190);
ElapsedLabel.Width := ScaleX(150);
ElapsedLabel.Height := ScaleY(20);
RemainingLabel := TNewStaticText.Create(WizardForm);
RemainingLabel.Parent := WizardForm;
RemainingLabel.AutoSize := False;
RemainingLabel.Font.Size:= 8; // SetBounds(410,190,150,20)
RemainingLabel.Left := ScaleX(410);
RemainingLabel.Top := ScaleY(190);
RemainingLabel.Width := ScaleX(150);
RemainingLabel.Height := ScaleY(20);
end;
procedure CurPageChanged5(CurPageID: Integer);
begin
PercentLabel.Visible := CurPageID = wpInstalling;
ElapsedLabel.Visible := CurPageID = wpInstalling;
RemainingLabel.Visible := CurPageID = wpInstalling;
StartTick := GetTickCount;
end;
procedure CancelButtonClick(CurPageID: Integer; var Cancel, Confirm: Boolean);
begin
if CurPageID= wpInstalling then
begin
Cancel := False;
if ExitSetupMsgBox then
begin
Cancel := True;
Confirm := False;
PercentLabel.Visible := False;
ElapsedLabel.Visible := False;
RemainingLabel.Visible := False;
end;
end;
end;
procedure CurInstallProgressChanged(CurProgress, MaxProgress: Integer);
var
CurTick: DWORD;
begin
CurTick := GetTickCount;
PercentLabel.Caption :=
Format('%.2f %%', [(CurProgress * 100.0) / MaxProgress]);
ElapsedLabel.Caption :=
Format('Decorido: %s', [TicksToStr(CurTick - StartTick)]);
if CurProgress > 0 then
begin
RemainingLabel.Caption :=
Format('Restante: %s', [TicksToStr(
((CurTick - StartTick) / CurProgress) * (MaxProgress - CurProgress))]);
end;
end;

You gonna have to change your ISDoneInit "$F777" to "$1111"
It's something like this 👇
if ISDoneInit(ExpandConstant('{src}\records.inf'), $1111, Comps1,Comps2,Comps3, MainForm.Handle, 512, #ProgressCallback) then
begin
and you don't have to add a another time count function to get this...just remove it...

Related

Inno Setup - Define music button and error with language selector?

This is the code with the error:
#include "Music\botva2.iss"
#include "Music\BASS_Module.iss"
[Code]
function ShellExecute(hwnd: HWND; lpOperation: string; lpFile: string;
lpParameters: string; lpDirectory: string; nShowCmd: Integer): THandle;
external 'ShellExecuteW#shell32.dll stdcall';
var
LanguageForm: TSetupForm;
SelectLabel: TNewStaticText;
CancelButton: TNewButton;
procedure LangChange(Sender : TObject);
begin
case TNewComboBox(Sender).ItemIndex of
0: { English }
begin
SelectLabel.Caption := 'Select the language to the installation:';
CancelButton.Caption := 'Cancel';
LanguageForm.Caption := 'PH';
end;
1: { Español }
begin
SelectLabel.Caption := 'Selecciona el idioma de la instalación:';
CancelButton.Caption := 'Cancelar';
LanguageForm.Caption := 'PH';
end;
end;
end;
procedure SelectLanguage();
var
OKButton: TNewButton;
LangCombo: TNewComboBox;
Languages: TStrings;
Params: string;
Instance: THandle;
P, I: Integer;
S, L: string;
begin
Languages := TStringList.Create();
Languages.Add('eng=English');
Languages.Add('spa=Español');
LanguageForm := CreateCustomForm;
LanguageForm.Caption := SetupMessage(msgSelectLanguageTitle);
LanguageForm.ClientWidth := ScaleX(240);
LanguageForm.ClientHeight := ScaleY(125);
LanguageForm.BorderStyle := bsDialog;
LanguageForm.Center;
CancelButton := TNewButton.Create(LanguageForm);
CancelButton.Parent := LanguageForm;
CancelButton.Left := ScaleX(140);
CancelButton.Top := ScaleY(93);
CancelButton.Width := ScaleY(90);
CancelButton.Height := ScaleY(23);
CancelButton.TabOrder := 3;
CancelButton.ModalResult := mrCancel;
CancelButton.Caption := SetupMessage(msgButtonCancel);
OKButton := TNewButton.Create(LanguageForm);
OKButton.Parent := LanguageForm;
OKButton.Left := ScaleX(10);
OKButton.Top := ScaleY(93);
OKButton.Width := ScaleX(90);
OKButton.Height := ScaleY(23);
OKButton.Caption := SetupMessage(msgButtonOK);
OKButton.Default := True
OKButton.ModalResult := mrOK;
OKButton.TabOrder := 2;
LangCombo := TNewComboBox.Create(LanguageForm);
LangCombo.Parent := LanguageForm;
LangCombo.Left := ScaleX(16);
LangCombo.Top := ScaleY(56);
LangCombo.Width := ScaleX(206);
LangCombo.Height := ScaleY(21);
LangCombo.Style := csDropDownList;
LangCombo.DropDownCount := 16;
LangCombo.TabOrder := 1;
SelectLabel := TNewStaticText.Create(LanguageForm);
SelectLabel.Parent := LanguageForm;
SelectLabel.Left := ScaleX(16);
SelectLabel.Top := ScaleY(15);
SelectLabel.Width := ScaleX(273);
SelectLabel.Height := ScaleY(39);
SelectLabel.AutoSize := False
SelectLabel.Caption := SetupMessage(msgSelectLanguageLabel);
SelectLabel.TabOrder := 0;
SelectLabel.WordWrap := True;
for I := 0 to Languages.Count - 1 do
begin
P := Pos('=', Languages.Strings[I]);
L := Copy(Languages.Strings[I], 0, P - 1);
S := Copy(Languages.Strings[I], P + 1, Length(Languages.Strings[I]) - P);
LangCombo.Items.Add(S);
if L = ActiveLanguage then
LangCombo.ItemIndex := I;
LangCombo.OnChange := #LangChange;
end;
if LanguageForm.ShowModal = mrOK then
begin
// Collect current instance parameters
for I := 1 to ParamCount do
begin
S := ParamStr(I);
// Unique log file name for the elevated instance
if CompareText(Copy(S, 1, 5), '/LOG=') = 0 then
begin
S := S + '-localized';
end;
// Do not pass our /SL5 switch
if CompareText(Copy(S, 1, 5), '/SL5=') <> 0 then
begin
Params := Params + AddQuotes(S) + ' ';
end;
end;
L := Languages.Strings[LangCombo.ItemIndex];
P := Pos('=', L);
L := Copy(L, 0, P-1);
// ... and add selected language
Params := Params + '/LANG=' + L;
Instance := ShellExecute(0, '', ExpandConstant('{srcexe}'), Params, '', SW_SHOW);
if Instance <= 32 then
begin
MsgBox(
Format('Running installer with selected language failed. Code: %d', [Instance]),
mbError, MB_OK);
end;
end;
end;
function InitializeSetup(): Boolean;
var
Language: string;
begin
Result := True;
Language := ExpandConstant('{param:LANG}');
if Language = '' then
begin
Log('No language specified, showing language dialog');
SelectLanguage();
Result := False;
Exit;
end
else
begin
Log('Language specified, proceeding with installation');
end;
end;
procedure RedesignWizardForm;
begin
with WizardForm do
begin
BorderIcons:=[];
Bevel1.Hide;
AutoScroll := False;
ClientHeight := ScaleY(349);
end;
with WizardForm.CancelButton do
begin
Top := ScaleY(319);
end;
with WizardForm.NextButton do
begin
Top := ScaleY(319);
end;
with WizardForm.BackButton do
begin
Top := ScaleY(319);
end;
with WizardForm.WizardBitmapImage do
begin
Width := ScaleX(500);
end;
with WizardForm.WelcomeLabel2 do
begin
Visible := False;
end;
with WizardForm.WelcomeLabel1 do
begin
Visible := False;
end;
with WizardForm.WizardSmallBitmapImage do
begin
Left := ScaleX(0);
Width := ScaleX(500);
Height := ScaleY(60);
end;
with WizardForm.PageDescriptionLabel do
begin
Visible := False;
end;
with WizardForm.PageNameLabel do
begin
Visible := False;
end;
with WizardForm.WizardBitmapImage2 do
begin
Width := ScaleX(500);
ExtractTemporaryFile('WizardForm.WizardBitmapImage2.bmp');
Bitmap.LoadFromFile(ExpandConstant('{tmp}\WizardForm.WizardBitmapImage2.bmp'));
end;
with WizardForm.FinishedLabel do
begin
Visible := False;
end;
with WizardForm.FinishedHeadingLabel do
begin
Visible := False;
end;
end;
procedure InitializeWizard1();
begin
RedesignWizardForm;
WizardForm.DiskSpaceLabel.Visible := False;
end;
procedure InitializeWizard2();
begin
ExtractTemporaryFile('BASS.dll');
ExtractTemporaryFile('CallbackCtrl.dll');
ExtractTemporaryFile('botva2.dll');
ExtractTemporaryFile('MusicButton.png');
ExtractTemporaryFile('Music.mp3');
BASS_Init('{tmp}\Music.mp3')
BASS_CreateOnOffButton(WizardForm, '{tmp}\MusicButton.png', 20, 320, 36, 36, 4)
end;
procedure InitializeWizard();
begin
InitializeWizard1();
InitializeWizard2();
end;
procedure DeinitializeSetup();
begin
BASS_DeInit; //Îñâîáîæäàåì ïðîöåññ
gdipShutdown
end;
This code includes the language selector Inno Setup - How to change a label caption [or other controls in general], when selected value in combox box changes and a code that define music and music button. If i delete all about language selector, the code works fine. What is the problem?
The code of music and button includes: botva2.iss, BASS_Module.iss, botva2.dll, CallbackCtrl.dll.
This error appears when you select accept or cancel on the language selector.
The DeinitializeSetup is called, even when the setup is aborted by returning False from the InitializeSetup.
So I guess the BASS_DeInit (or the gdipShutdown) fails, because an equivalent BASS_Init was never called.
You have to avoid calling the code in the DeinitializeSetup, when the BASS_Init was never called.
var
BASS_Initialized: Boolean;
procedure InitializeWizard2();
begin
ExtractTemporaryFile('BASS.dll');
ExtractTemporaryFile('CallbackCtrl.dll');
ExtractTemporaryFile('botva2.dll');
ExtractTemporaryFile('MusicButton.png');
ExtractTemporaryFile('Music.mp3');
BASS_Init('{tmp}\Music.mp3')
BASS_CreateOnOffButton(WizardForm, '{tmp}\MusicButton.png', 20, 320, 36, 36, 4);
BASS_Initialized := True;
end;
procedure DeinitializeSetup();
begin
if BASS_Initialized then
begin
BASS_DeInit;
gdipShutdown;
end;
end;

Inno Setup: Enlarge component page only with preview and description

I need help from you to merge two scripts found here to have preview image on a maximized components windows:
Add image into the components list - component description
Long descriptions on Inno Setup components
Edit: Thanks to Martin Prikryl. With his patience and his help, I successfully merge these two scripts.
Your preview image should have a resolution of 208x165 in .bmp
[Files]
...
Source: "1.bmp"; Flags: dontcopy
Source: "2.bmp"; Flags: dontcopy
Source: "3.bmp"; Flags: dontcopy
Source: "InnoCallback.dll"; Flags: dontcopy
[Code]
var
LastMouse: TPoint;
type
TTimerProc = procedure(H: LongWord; Msg: LongWord; IdEvent: LongWord; Time: LongWord);
function GetCursorPos(var lpPoint: TPoint): BOOL; external 'GetCursorPos#user32.dll stdcall';
function SetTimer(hWnd: longword; nIDEvent, uElapse: LongWord; lpTimerFunc: LongWord): LongWord; external 'SetTimer#user32.dll stdcall';
function ScreenToClient(hWnd: HWND; var lpPoint: TPoint): BOOL; external 'ScreenToClient#user32.dll stdcall';
function ClientToScreen(hWnd: HWND; var lpPoint: TPoint): BOOL; external 'ClientToScreen#user32.dll stdcall';
function ListBox_GetItemRect(const hWnd: HWND; const Msg: Integer; Index: LongInt; var Rect: TRect): LongInt; external 'SendMessageW#user32.dll stdcall';
const
LB_GETITEMRECT = $0198;
LB_GETTOPINDEX = $018E;
function WrapTimerProc(Callback: TTimerProc; ParamCount: Integer): LongWord; external 'wrapcallback#files:InnoCallback.dll stdcall';
function FindControl(Parent: TWinControl; P: TPoint): TControl;
var
Control: TControl;
WinControl: TWinControl;
I: Integer;
P2: TPoint;
begin
for I := 0 to Parent.ControlCount - 1 do
begin
Control := Parent.Controls[I];
if Control.Visible and
(Control.Left <= P.X) and (P.X < Control.Left + Control.Width) and
(Control.Top <= P.Y) and (P.Y < Control.Top + Control.Height) then
begin
if Control is TWinControl then
begin
P2 := P;
ClientToScreen(Parent.Handle, P2);
WinControl := TWinControl(Control);
ScreenToClient(WinControl.Handle, P2);
Result := FindControl(WinControl, P2);
if Result <> nil then Exit;
end;
Result := Control;
Exit;
end;
end;
Result := nil;
end;
function PointInRect(const Rect: TRect; const Point: TPoint): Boolean;
begin
Result := (Point.X >= Rect.Left) and (Point.X <= Rect.Right) and
(Point.Y >= Rect.Top) and (Point.Y <= Rect.Bottom);
end;
function ListBoxItemAtPos(ListBox: TCustomListBox; Pos: TPoint): Integer;
var
Count: Integer;
ItemRect: TRect;
begin
Result := SendMessage(ListBox.Handle, LB_GETTOPINDEX, 0, 0);
Count := ListBox.Items.Count;
while Result < Count do
begin
ListBox_GetItemRect(ListBox.Handle, LB_GETITEMRECT, Result, ItemRect);
if PointInRect(ItemRect, Pos) then Exit;
Inc(Result);
end;
Result := -1;
end;
var
CompLabel: TLabel;
CompImage: TBitmapImage;
LoadingImage: Boolean;
procedure HoverComponentChanged(Index: Integer);
var
Description: string;
Image: string;
ImagePath: string;
begin
case Index of
0: begin Description := 'Component 1'; Image := '1.bmp'; end;
1: begin Description := 'Component 2'; Image := '2.bmp'; end;
2: begin Description := 'Component 3'; Image := '3.bmp'; end;
else
Description := 'Move your mouse over a component to see its description.';
end;
CompLabel.Caption := Description;
if Image <> '' then
begin
// The ExtractTemporaryFile pumps the message queue, prevent recursion
if not LoadingImage then
begin
LoadingImage := True;
try
ImagePath := ExpandConstant('{tmp}\' + Image);
if not FileExists(ImagePath) then
begin
ExtractTemporaryFile(Image);
end;
CompImage.Bitmap.LoadFromFile(ImagePath);
finally
LoadingImage := False;
end;
end;
CompImage.Visible := True;
end
else
begin
CompImage.Visible := False;
end;
end;
procedure HoverTimerProc(H: LongWord; Msg: LongWord; IdEvent: LongWord; Time: LongWord);
var
P: TPoint;
Control: TControl;
Index: Integer;
begin
GetCursorPos(P);
if P <> LastMouse then // just optimization
begin
LastMouse := P;
ScreenToClient(WizardForm.Handle, P);
if (P.X < 0) or (P.Y < 0) or
(P.X > WizardForm.ClientWidth) or (P.Y > WizardForm.ClientHeight) then
begin
Control := nil;
end
else
begin
Control := FindControl(WizardForm, P);
end;
Index := -1;
if Control = WizardForm.ComponentsList then
begin
P := LastMouse;
ScreenToClient(WizardForm.ComponentsList.Handle, P);
Index := ListBoxItemAtPos(WizardForm.ComponentsList, P);
end;
HoverComponentChanged(Index);
end;
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] + ScaleY(150);
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 InitializeWizard1();
var
HoverTimerCallback: LongWord;
begin
HoverTimerCallback := WrapTimerProc(#HoverTimerProc, 4);
SetTimer(0, 0, 50, HoverTimerCallback);
CompLabel := TLabel.Create(WizardForm);
CompLabel.Parent := WizardForm.SelectComponentsPage;
CompLabel.Left := WizardForm.ComponentsList.Left;
CompLabel.Width := WizardForm.ComponentsList.Width div 2;
CompLabel.Height := ScaleY(64);
CompLabel.Top := WizardForm.ComponentsList.Top + WizardForm.ComponentsList.Height - CompLabel.Height + ScaleY(150);
CompLabel.AutoSize := false;
CompLabel.WordWrap := True;
CompImage := TBitmapImage.Create(WizardForm);
CompImage.Parent := WizardForm.SelectComponentsPage;
CompImage.Top := CompLabel.Top;
CompImage.Width := CompImage.Width + ScaleX(128);
CompImage.Height := CompLabel.Height + ScaleX(128);
CompImage.Left := WizardForm.ComponentsList.Left + WizardForm.ComponentsList.Width - CompLabel.Width;
WizardForm.ComponentsList.Height := WizardForm.ComponentsList.Height - CompLabel.Height - ScaleY(8);
end;
procedure InitializeWizard2();
begin
CompPageModified := False;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
if CurpageID = wpSelectComponents then
begin
SaveComponentsPage(CompPagePositions);
LoadComponentsPage(CompPagePositions, ScaleY(250));
CompPageModified := True;
end
else
if CompPageModified then
begin
LoadComponentsPage(CompPagePositions, 0);
CompPageModified := False;
end;
end;
procedure InitializeWizard();
begin
InitializeWizard1();
InitializeWizard2();
end;
Just copy both codes and merge the InitializeWizard implementations according to this guide:
Merging event function (InitializeWizard) implementations from different sources.
Though, actually, the InitializeWizard in the Larger “Select Components” page in Inno Setup is noop. You can skip that. And you do not need to merge anything.
The only other change you need to do, is not to enlarge the ComponentsList in the LoadComponentsPage.

Adding MouseOver descriptions for InnoSetup [duplicate]

I am building an install with Inno Setup and I am using the components section to allow the end user to select optional items to install.
Some of these items need a longer description in order for the user to have enough information to intelligently select them.
Is there a way to add more in-depth descriptions somewhere?
This solution uses only Inno Setup proper (not the obsolete 3rd party build of the Inno Setup of suspicious origin).
The solution is partially based on my answer to Inno Setup: OnHover event.
Adjust the HoverComponentChanged procedure to your needs.
[Code]
var
LastMouse: TPoint;
CompLabel: TLabel;
function GetCursorPos(var lpPoint: TPoint): BOOL;
external 'GetCursorPos#user32.dll stdcall';
function SetTimer(
hWnd: longword; nIDEvent, uElapse: LongWord; lpTimerFunc: LongWord): LongWord;
external 'SetTimer#user32.dll stdcall';
function ScreenToClient(hWnd: HWND; var lpPoint: TPoint): BOOL;
external 'ScreenToClient#user32.dll stdcall';
function ClientToScreen(hWnd: HWND; var lpPoint: TPoint): BOOL;
external 'ClientToScreen#user32.dll stdcall';
function ListBox_GetItemRect(
const hWnd: HWND; const Msg: Integer; Index: LongInt; var Rect: TRect): LongInt;
external 'SendMessageW#user32.dll stdcall';
const
LB_GETITEMRECT = $0198;
LB_GETTOPINDEX = $018E;
function FindControl(Parent: TWinControl; P: TPoint): TControl;
var
Control: TControl;
WinControl: TWinControl;
I: Integer;
P2: TPoint;
begin
for I := 0 to Parent.ControlCount - 1 do
begin
Control := Parent.Controls[I];
if Control.Visible and
(Control.Left <= P.X) and (P.X < Control.Left + Control.Width) and
(Control.Top <= P.Y) and (P.Y < Control.Top + Control.Height) then
begin
if Control is TWinControl then
begin
P2 := P;
ClientToScreen(Parent.Handle, P2);
WinControl := TWinControl(Control);
ScreenToClient(WinControl.Handle, P2);
Result := FindControl(WinControl, P2);
if Result <> nil then Exit;
end;
Result := Control;
Exit;
end;
end;
Result := nil;
end;
function PointInRect(const Rect: TRect; const Point: TPoint): Boolean;
begin
Result :=
(Point.X >= Rect.Left) and (Point.X <= Rect.Right) and
(Point.Y >= Rect.Top) and (Point.Y <= Rect.Bottom);
end;
function ListBoxItemAtPos(ListBox: TCustomListBox; Pos: TPoint): Integer;
var
Count: Integer;
ItemRect: TRect;
begin
Result := SendMessage(ListBox.Handle, LB_GETTOPINDEX, 0, 0);
Count := ListBox.Items.Count;
while Result < Count do
begin
ListBox_GetItemRect(ListBox.Handle, LB_GETITEMRECT, Result, ItemRect);
if PointInRect(ItemRect, Pos) then Exit;
Inc(Result);
end;
Result := -1;
end;
procedure HoverComponentChanged(Index: Integer);
var
Description: string;
begin
case Index of
0: Description := 'This is the description of Main Files';
1: Description := 'This is the description of Additional Files';
2: Description := 'This is the description of Help Files';
else
Description := 'Move your mouse over a component to see its description.';
end;
CompLabel.Caption := Description;
end;
procedure HoverTimerProc(
H: LongWord; Msg: LongWord; IdEvent: LongWord; Time: LongWord);
var
P: TPoint;
Control: TControl;
Index: Integer;
begin
GetCursorPos(P);
if P <> LastMouse then { just optimization }
begin
LastMouse := P;
ScreenToClient(WizardForm.Handle, P);
if (P.X < 0) or (P.Y < 0) or
(P.X > WizardForm.ClientWidth) or (P.Y > WizardForm.ClientHeight) then
begin
Control := nil;
end
else
begin
Control := FindControl(WizardForm, P);
end;
Index := -1;
if (Control = WizardForm.ComponentsList) and
(not WizardForm.TypesCombo.DroppedDown) then
begin
P := LastMouse;
ScreenToClient(WizardForm.ComponentsList.Handle, P);
Index := ListBoxItemAtPos(WizardForm.ComponentsList, P);
end;
HoverComponentChanged(Index);
end;
end;
procedure InitializeWizard();
begin
SetTimer(0, 0, 50, CreateCallback(#HoverTimerProc));
CompLabel := TLabel.Create(WizardForm);
CompLabel.Parent := WizardForm.SelectComponentsPage;
CompLabel.Left := WizardForm.ComponentsList.Left;
CompLabel.Width := WizardForm.ComponentsList.Width;
CompLabel.Height := ScaleY(32);
CompLabel.Top :=
WizardForm.ComponentsList.Top + WizardForm.ComponentsList.Height -
CompLabel.Height;
CompLabel.AutoSize := False;
CompLabel.WordWrap := True;
WizardForm.ComponentsList.Height :=
WizardForm.ComponentsList.Height - CompLabel.Height - ScaleY(8);
end;
For CreateCallback function, you need Inno Setup 6. If you are stuck with Inno Setup 5, you can use WrapCallback function from InnoTools InnoCallback library. Use the Unicode version of Inno Setup 5.
To make this work correctly in resized/resizable/modern wizard, you will need some adjustments. See Inno Setup - how to center an animated gif in resized wizard and Long components descriptions in enlarged Inno Setup wizard.
Use this advanced compiler (download link is somewhere below).
It supports more classes and events than the standard compiler. You can access the property "OnItemMouseMove". Using this you can store a description for every item that is shown by a label. Here is an example:
var
CompLabel: TLabel;
procedure OnItemMouseMove(Sender: TObject; X, Y: Integer; Index: Integer; Area: TItemArea);
begin
case Index of
0: CompLabel.Caption := 'This is the description of Component 1';
1: CompLabel.Caption := 'This is the description of Component 2';
2: CompLabel.Caption := 'This is the description of Component 3';
3: CompLabel.Caption := 'This is the description of Component 4'
else
CompLabel.Caption := 'Move your mouse over a component to see its description.';
end;
end;
procedure OnMouseLeave(Sender: TObject);
begin
CompLabel.Caption := 'Move your mouse over a component to see its description.';
end;
procedure InitializeWizard();
begin
CompLabel := TLabel.Create(WizardForm);
CompLabel.Parent := WizardForm.SelectComponentsPage;
CompLabel.SetBounds(WizardForm.ComponentsList.Left,180,WizardForm.ComponentsList.Width,200);
CompLabel.Caption := 'Move your mouse over a component to see its description.';
WizardForm.ComponentsList.OnItemMouseMove := #OnItemMouseMove;
WizardForm.ComponentsList.OnMouseLeave := #OnMouseLeave;
WizardForm.ComponentsList.Height := WizardForm.ComponentsList.Height - 40;
end;

Long descriptions on Inno Setup components

I am building an install with Inno Setup and I am using the components section to allow the end user to select optional items to install.
Some of these items need a longer description in order for the user to have enough information to intelligently select them.
Is there a way to add more in-depth descriptions somewhere?
This solution uses only Inno Setup proper (not the obsolete 3rd party build of the Inno Setup of suspicious origin).
The solution is partially based on my answer to Inno Setup: OnHover event.
Adjust the HoverComponentChanged procedure to your needs.
[Code]
var
LastMouse: TPoint;
CompLabel: TLabel;
function GetCursorPos(var lpPoint: TPoint): BOOL;
external 'GetCursorPos#user32.dll stdcall';
function SetTimer(
hWnd: longword; nIDEvent, uElapse: LongWord; lpTimerFunc: LongWord): LongWord;
external 'SetTimer#user32.dll stdcall';
function ScreenToClient(hWnd: HWND; var lpPoint: TPoint): BOOL;
external 'ScreenToClient#user32.dll stdcall';
function ClientToScreen(hWnd: HWND; var lpPoint: TPoint): BOOL;
external 'ClientToScreen#user32.dll stdcall';
function ListBox_GetItemRect(
const hWnd: HWND; const Msg: Integer; Index: LongInt; var Rect: TRect): LongInt;
external 'SendMessageW#user32.dll stdcall';
const
LB_GETITEMRECT = $0198;
LB_GETTOPINDEX = $018E;
function FindControl(Parent: TWinControl; P: TPoint): TControl;
var
Control: TControl;
WinControl: TWinControl;
I: Integer;
P2: TPoint;
begin
for I := 0 to Parent.ControlCount - 1 do
begin
Control := Parent.Controls[I];
if Control.Visible and
(Control.Left <= P.X) and (P.X < Control.Left + Control.Width) and
(Control.Top <= P.Y) and (P.Y < Control.Top + Control.Height) then
begin
if Control is TWinControl then
begin
P2 := P;
ClientToScreen(Parent.Handle, P2);
WinControl := TWinControl(Control);
ScreenToClient(WinControl.Handle, P2);
Result := FindControl(WinControl, P2);
if Result <> nil then Exit;
end;
Result := Control;
Exit;
end;
end;
Result := nil;
end;
function PointInRect(const Rect: TRect; const Point: TPoint): Boolean;
begin
Result :=
(Point.X >= Rect.Left) and (Point.X <= Rect.Right) and
(Point.Y >= Rect.Top) and (Point.Y <= Rect.Bottom);
end;
function ListBoxItemAtPos(ListBox: TCustomListBox; Pos: TPoint): Integer;
var
Count: Integer;
ItemRect: TRect;
begin
Result := SendMessage(ListBox.Handle, LB_GETTOPINDEX, 0, 0);
Count := ListBox.Items.Count;
while Result < Count do
begin
ListBox_GetItemRect(ListBox.Handle, LB_GETITEMRECT, Result, ItemRect);
if PointInRect(ItemRect, Pos) then Exit;
Inc(Result);
end;
Result := -1;
end;
procedure HoverComponentChanged(Index: Integer);
var
Description: string;
begin
case Index of
0: Description := 'This is the description of Main Files';
1: Description := 'This is the description of Additional Files';
2: Description := 'This is the description of Help Files';
else
Description := 'Move your mouse over a component to see its description.';
end;
CompLabel.Caption := Description;
end;
procedure HoverTimerProc(
H: LongWord; Msg: LongWord; IdEvent: LongWord; Time: LongWord);
var
P: TPoint;
Control: TControl;
Index: Integer;
begin
GetCursorPos(P);
if P <> LastMouse then { just optimization }
begin
LastMouse := P;
ScreenToClient(WizardForm.Handle, P);
if (P.X < 0) or (P.Y < 0) or
(P.X > WizardForm.ClientWidth) or (P.Y > WizardForm.ClientHeight) then
begin
Control := nil;
end
else
begin
Control := FindControl(WizardForm, P);
end;
Index := -1;
if (Control = WizardForm.ComponentsList) and
(not WizardForm.TypesCombo.DroppedDown) then
begin
P := LastMouse;
ScreenToClient(WizardForm.ComponentsList.Handle, P);
Index := ListBoxItemAtPos(WizardForm.ComponentsList, P);
end;
HoverComponentChanged(Index);
end;
end;
procedure InitializeWizard();
begin
SetTimer(0, 0, 50, CreateCallback(#HoverTimerProc));
CompLabel := TLabel.Create(WizardForm);
CompLabel.Parent := WizardForm.SelectComponentsPage;
CompLabel.Left := WizardForm.ComponentsList.Left;
CompLabel.Width := WizardForm.ComponentsList.Width;
CompLabel.Height := ScaleY(32);
CompLabel.Top :=
WizardForm.ComponentsList.Top + WizardForm.ComponentsList.Height -
CompLabel.Height;
CompLabel.AutoSize := False;
CompLabel.WordWrap := True;
WizardForm.ComponentsList.Height :=
WizardForm.ComponentsList.Height - CompLabel.Height - ScaleY(8);
end;
For CreateCallback function, you need Inno Setup 6. If you are stuck with Inno Setup 5, you can use WrapCallback function from InnoTools InnoCallback library. Use the Unicode version of Inno Setup 5.
To make this work correctly in resized/resizable/modern wizard, you will need some adjustments. See Inno Setup - how to center an animated gif in resized wizard and Long components descriptions in enlarged Inno Setup wizard.
Use this advanced compiler (download link is somewhere below).
It supports more classes and events than the standard compiler. You can access the property "OnItemMouseMove". Using this you can store a description for every item that is shown by a label. Here is an example:
var
CompLabel: TLabel;
procedure OnItemMouseMove(Sender: TObject; X, Y: Integer; Index: Integer; Area: TItemArea);
begin
case Index of
0: CompLabel.Caption := 'This is the description of Component 1';
1: CompLabel.Caption := 'This is the description of Component 2';
2: CompLabel.Caption := 'This is the description of Component 3';
3: CompLabel.Caption := 'This is the description of Component 4'
else
CompLabel.Caption := 'Move your mouse over a component to see its description.';
end;
end;
procedure OnMouseLeave(Sender: TObject);
begin
CompLabel.Caption := 'Move your mouse over a component to see its description.';
end;
procedure InitializeWizard();
begin
CompLabel := TLabel.Create(WizardForm);
CompLabel.Parent := WizardForm.SelectComponentsPage;
CompLabel.SetBounds(WizardForm.ComponentsList.Left,180,WizardForm.ComponentsList.Width,200);
CompLabel.Caption := 'Move your mouse over a component to see its description.';
WizardForm.ComponentsList.OnItemMouseMove := #OnItemMouseMove;
WizardForm.ComponentsList.OnMouseLeave := #OnMouseLeave;
WizardForm.ComponentsList.Height := WizardForm.ComponentsList.Height - 40;
end;

wpLicese Page check if ScrollBars position is max (Inno Setup)

Is it possible to check the position of ScrollBar in wpLicense Page in Inno Setup without having to write custom memo page?
e.g.
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = wpLicense then
WizardForm.LicenseAcceptedRadio.Enabled := False;
WizardForm.LicenseNotAcceptedRadio.Enabled := False;
if ScrollBar.Position := ScrollBar.Max then
WizardForm.LicenseAcceptedRadio.Enabled := True;
WizardForm.LicenseNotAcceptedRadio.Enabled := True;
end;
There is no direct access to those scroll bars, however you can use the GetScrollInfo function this way:
[code]
const
SB_VERT = 1;
SIF_RANGE = 1;
SIF_POS = 4;
SIF_PAGE = 2;
type
TScrollInfo = record
cbSize: UINT;
fMask: UINT;
nMin: Integer;
nMax: Integer;
nPage: UINT;
nPos: Integer;
nTrackPos: Integer;
end;
function GetScrollInfo(hWnd: HWND; BarFlag: Integer;
var ScrollInfo: TScrollInfo): BOOL;
external 'GetScrollInfo#user32.dll stdcall';
procedure CurPageChanged(CurPageID: Integer);
var
ScrollInfo: TScrollInfo;
begin
if CurPageID = wpLicense then
begin
ScrollInfo.cbSize := SizeOf(ScrollInfo);
ScrollInfo.fMask := SIF_RANGE or SIF_POS or SIF_PAGE;
if GetScrollInfo(WizardForm.LicenseMemo.Handle, SB_VERT, ScrollInfo) then
if ScrollInfo.nPos = ScrollInfo.nMax - ScrollInfo.nPage then
MsgBox('You are at the end of the license!', mbInformation, MB_OK);
end;
end;
That is what I have now. It works, however if you find any issues, just say as I like comments.
procedure OnScrollPosition(Wnd: HWND; Msg: UINT; TimerID: UINT_PTR;
SysTime: DWORD);
var
ScrollInfo: TScrollInfo;
begin
ScrollInfo.cbSize := SizeOf(ScrollInfo);
ScrollInfo.fMask := SIF_RANGE or SIF_POS or SIF_PAGE;
if GetScrollInfo(WizardForm.LicenseMemo.Handle, SB_VERT, ScrollInfo) then
if ScrollInfo.nPos = ScrollInfo.nMax - ScrollInfo.nPage then
begin
WizardForm.LicenseAcceptedRadio.Enabled := True;
WizardForm.LicenseNotAcceptedRadio.Enabled := True;
end;
end;
procedure ScrollPosition();
var
TimerCallback: LongWord;
begin
TimerCallback := WrapTimerProc(#OnScrollPosition, 4);
TimerID := SetTimer(0, 0, 500, TimerCallback);
end;
procedure CurPageChanged(CurPageID: Integer);
var
ScrollInfo: TScrollInfo;
begin
if CurPageID = wpInstalling then
StartSlideTimer
else
KillSlideTimer;
if CurPageID = wpLicense then
WizardForm.LicenseAcceptedRadio.Enabled := False;
WizardForm.LicenseNotAcceptedRadio.Enabled := False;
ScrollPosition
end;

Resources