Custom Uninstall page (not MsgBox)
You can modify the uninstall form to behave like the install form (with pages and the Next/Back buttons).
In the InitializeUninstallProgressForm
:
- Create the new pages and insert them to the
UninstallProgressForm.InnerNotebook
(or the.OuterNotebook
). - Implement the "Next" and the "Back" buttons.
- You can also make the "Cancel" button working.
- Run modal loop of the form using
UninstallProgressForm.ShowModal
. - Only after the modal loop exits, restore original layout of the form and let the uninstallation continue.
[Code]
var
UninstallFirstPage: TNewNotebookPage;
UninstallSecondPage: TNewNotebookPage;
UninstallBackButton: TNewButton;
UninstallNextButton: TNewButton;
procedure UpdateUninstallWizard;
begin
if UninstallProgressForm.InnerNotebook.ActivePage = UninstallFirstPage then
begin
UninstallProgressForm.PageNameLabel.Caption := 'First uninstall wizard page';
UninstallProgressForm.PageDescriptionLabel.Caption :=
'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';
end
else
if UninstallProgressForm.InnerNotebook.ActivePage = UninstallSecondPage then
begin
UninstallProgressForm.PageNameLabel.Caption := 'Second uninstall wizard page';
UninstallProgressForm.PageDescriptionLabel.Caption :=
'Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.';
end;
UninstallBackButton.Visible :=
(UninstallProgressForm.InnerNotebook.ActivePage <> UninstallFirstPage);
if UninstallProgressForm.InnerNotebook.ActivePage <> UninstallSecondPage then
begin
UninstallNextButton.Caption := SetupMessage(msgButtonNext);
UninstallNextButton.ModalResult := mrNone;
end
else
begin
UninstallNextButton.Caption := 'Uninstall';
{ Make the "Uninstall" button break the ShowModal loop }
UninstallNextButton.ModalResult := mrOK;
end;
end;
procedure UninstallNextButtonClick(Sender: TObject);
begin
if UninstallProgressForm.InnerNotebook.ActivePage = UninstallSecondPage then
begin
UninstallNextButton.Visible := False;
UninstallBackButton.Visible := False;
end
else
begin
if UninstallProgressForm.InnerNotebook.ActivePage = UninstallFirstPage then
begin
UninstallProgressForm.InnerNotebook.ActivePage := UninstallSecondPage;
end;
UpdateUninstallWizard;
end;
end;
procedure UninstallBackButtonClick(Sender: TObject);
begin
if UninstallProgressForm.InnerNotebook.ActivePage = UninstallSecondPage then
begin
UninstallProgressForm.InnerNotebook.ActivePage := UninstallFirstPage;
end;
UpdateUninstallWizard;
end;
procedure InitializeUninstallProgressForm();
var
PageText: TNewStaticText;
PageNameLabel: string;
PageDescriptionLabel: string;
CancelButtonEnabled: Boolean;
CancelButtonModalResult: Integer;
begin
if not UninstallSilent then
begin
{ Create the first page and make it active }
UninstallFirstPage := TNewNotebookPage.Create(UninstallProgressForm);
UninstallFirstPage.Notebook := UninstallProgressForm.InnerNotebook;
UninstallFirstPage.Parent := UninstallProgressForm.InnerNotebook;
UninstallFirstPage.Align := alClient;
PageText := TNewStaticText.Create(UninstallProgressForm);
PageText.Parent := UninstallFirstPage;
PageText.Top := UninstallProgressForm.StatusLabel.Top;
PageText.Left := UninstallProgressForm.StatusLabel.Left;
PageText.Width := UninstallProgressForm.StatusLabel.Width;
PageText.Height := UninstallProgressForm.StatusLabel.Height;
PageText.AutoSize := False;
PageText.ShowAccelChar := False;
PageText.Caption := 'Press Next to proceeed with uninstallation.';
UninstallProgressForm.InnerNotebook.ActivePage := UninstallFirstPage;
PageNameLabel := UninstallProgressForm.PageNameLabel.Caption;
PageDescriptionLabel := UninstallProgressForm.PageDescriptionLabel.Caption;
{ Create the second page }
UninstallSecondPage := TNewNotebookPage.Create(UninstallProgressForm);
UninstallSecondPage.Notebook := UninstallProgressForm.InnerNotebook;
UninstallSecondPage.Parent := UninstallProgressForm.InnerNotebook;
UninstallSecondPage.Align := alClient;
PageText := TNewStaticText.Create(UninstallProgressForm);
PageText.Parent := UninstallSecondPage;
PageText.Top := UninstallProgressForm.StatusLabel.Top;
PageText.Left := UninstallProgressForm.StatusLabel.Left;
PageText.Width := UninstallProgressForm.StatusLabel.Width;
PageText.Height := UninstallProgressForm.StatusLabel.Height;
PageText.AutoSize := False;
PageText.ShowAccelChar := False;
PageText.Caption := 'Press Uninstall to proceeed with uninstallation.';
UninstallNextButton := TNewButton.Create(UninstallProgressForm);
UninstallNextButton.Parent := UninstallProgressForm;
UninstallNextButton.Left :=
UninstallProgressForm.CancelButton.Left -
UninstallProgressForm.CancelButton.Width -
ScaleX(10);
UninstallNextButton.Top := UninstallProgressForm.CancelButton.Top;
UninstallNextButton.Width := UninstallProgressForm.CancelButton.Width;
UninstallNextButton.Height := UninstallProgressForm.CancelButton.Height;
UninstallNextButton.OnClick := @UninstallNextButtonClick;
UninstallBackButton := TNewButton.Create(UninstallProgressForm);
UninstallBackButton.Parent := UninstallProgressForm;
UninstallBackButton.Left :=
UninstallNextButton.Left - UninstallNextButton.Width -
ScaleX(10);
UninstallBackButton.Top := UninstallProgressForm.CancelButton.Top;
UninstallBackButton.Width := UninstallProgressForm.CancelButton.Width;
UninstallBackButton.Height := UninstallProgressForm.CancelButton.Height;
UninstallBackButton.Caption := SetupMessage(msgButtonBack);
UninstallBackButton.OnClick := @UninstallBackButtonClick;
UninstallBackButton.TabOrder := UninstallProgressForm.CancelButton.TabOrder;
UninstallNextButton.TabOrder := UninstallBackButton.TabOrder + 1;
UninstallProgressForm.CancelButton.TabOrder := UninstallNextButton.TabOrder + 1;
{ Run our wizard pages }
UpdateUninstallWizard;
CancelButtonEnabled := UninstallProgressForm.CancelButton.Enabled
UninstallProgressForm.CancelButton.Enabled := True;
CancelButtonModalResult := UninstallProgressForm.CancelButton.ModalResult;
UninstallProgressForm.CancelButton.ModalResult := mrCancel;
if UninstallProgressForm.ShowModal = mrCancel then Abort;
{ Restore the standard page payout }
UninstallProgressForm.CancelButton.Enabled := CancelButtonEnabled;
UninstallProgressForm.CancelButton.ModalResult := CancelButtonModalResult;
UninstallProgressForm.PageNameLabel.Caption := PageNameLabel;
UninstallProgressForm.PageDescriptionLabel.Caption := PageDescriptionLabel;
UninstallProgressForm.InnerNotebook.ActivePage :=
UninstallProgressForm.InstallingPage;
end;
end;
See also Inno Setup - How to create a OuterNotebook/welcome page in the uninstaller?
Luckily Inno Setup gives enough abilities to build own forms so you can imitate any page of uninstall form on another modal form.
Here's what I managed to create. The form takes dimensions from UninstallForm
, contains a TNewNotebook
control and buttons to jump between pages and to cancel the dialog.
const
ControlGap = 5; // determined empirically
// Set Back/Next buttons state according to current selected notebook page
procedure UpdateButtonsState(Form: TSetupForm);
var
Notebook: TNewNotebook;
BtnBack, BtnNext: TButton;
begin
Notebook := TNewNotebook(Form.FindComponent('Notebook'));
BtnBack := TButton(Form.FindComponent('BtnBack'));
BtnNext := TButton(Form.FindComponent('BtnNext'));
// Update buttons state
BtnBack.Enabled := (Notebook.ActivePage <> Notebook.Pages[0]);
if Notebook.ActivePage <> Notebook.Pages[Notebook.PageCount - 1] then
begin
BtnNext.Caption := SetupMessage(msgButtonNext)
BtnNext.ModalResult := mrNone;
end
else
begin
BtnNext.Caption := SetupMessage(msgButtonFinish);
BtnNext.ModalResult := mrYes;
end;
end;
// Change notebook page
procedure BtnPageChangeClick(Sender: TObject);
var
NextPage: TNewNotebookPage;
Notebook: TNewNotebook;
Form: TWinControl;
Button, BtnBack, BtnNext: TButton;
begin
Button := TButton(Sender);
Form := Button;
while not (Form is TSetupForm) do
Form := Form.Parent;
Notebook := TNewNotebook(Form.FindComponent('Notebook'));
BtnBack := TButton(Form.FindComponent('BtnBack'));
BtnNext := TButton(Form.FindComponent('BtnNext'));
// Avoid cycled style of Notebook's page looping
if (Button = BtnBack) and (Notebook.ActivePage = Notebook.Pages[0]) then
NextPage := nil
else
if (Button = BtnNext) and (Notebook.ActivePage = Notebook.Pages[Notebook.PageCount - 1]) then
NextPage := nil
else
NextPage := Notebook.FindNextPage(Notebook.ActivePage, Button = BtnNext);
Notebook.ActivePage := NextPage;
UpdateButtonsState(TSetupForm(Form));
end;
// Add a new page to notebook and return it
function AddPage(NotebookForm: TSetupForm): TNewNotebookPage;
var
Notebook: TNewNotebook;
begin
Notebook := TNewNotebook(NotebookForm.FindComponent('Notebook'));
Result := TNewNotebookPage.Create(Notebook);
Result.Notebook:=Notebook;
Result.Parent:=Notebook;
Result.Align := alClient;
if Notebook.ActivePage = nil then
Notebook.ActivePage := Result;
UpdateButtonsState(NotebookForm);
end;
// Create a form with notebook and 3 buttons: Back, Next, Cancel
function CreateNotebookForm: TSetupForm;
var
Notebook: TNewNotebook;
NotebookPage: TNewNotebookPage;
Pan: TPanel;
TmpLabel: TLabel;
MaxWidth, i: Integer;
BtnBack, BtnNext, BtnCancel: TButton;
BtnLabelMsgIDs: array of TSetupMessageID;
begin
Result := CreateCustomForm;
Result.SetBounds(0, 0, UninstallProgressForm.Width, UninstallProgressForm.Height);
Result.Position := poOwnerFormCenter;
Notebook := TNewNotebook.Create(Result);
Notebook.Parent := Result;
Notebook.Name := 'Notebook'; // will be used for searching
Notebook.Align := alClient;
Pan := TPanel.Create(Result);
Pan.Parent := Notebook;
Pan.Caption := '';
Pan.Align := alBottom;
// Create buttons
BtnNext := TNewButton.Create(Result);
with BtnNext do
begin
Parent := Pan;
Name := 'BtnNext'; // will be used for searching
Caption := SetupMessage(msgButtonNext);
OnClick := @BtnPageChangeClick;
ParentFont := True;
end;
BtnBack := TNewButton.Create(Result);
with BtnBack do
begin
Parent := Pan;
Caption := SetupMessage(msgButtonBack);
Name := 'BtnBack'; // will be used for searching
OnClick := @BtnPageChangeClick;
ParentFont := True;
end;
BtnCancel := TNewButton.Create(Result);
with BtnCancel do
begin
Parent := Pan;
Name := 'BtnCancel'; // will be used for searching
Caption := SetupMessage(msgButtonCancel);
ModalResult := mrCancel;
Cancel := True;
ParentFont := True;
end;
// Determine dimensions of buttons. Should use TCanvas.TextWidth here
// but it doesn't allow Font property assignment :(
TmpLabel := TLabel.Create(Result);
with TmpLabel do
begin
Left := 0;
Top := 0;
Parent := Pan;
ParentFont := True;
Visible := False;
WordWrap := False;
Autosize := True;
end;
// Determine max label width among these labels: Back, Next, Cancel, Finish
SetArrayLength(BtnLabelMsgIDs, 4);
BtnLabelMsgIDs[0] := msgButtonBack;
BtnLabelMsgIDs[1] := msgButtonNext;
BtnLabelMsgIDs[2] := msgButtonCancel;
BtnLabelMsgIDs[3] := msgButtonFinish;
MaxWidth := 0;
for i := Low(BtnLabelMsgIDs) to High(BtnLabelMsgIDs) do
begin
TmpLabel.Caption := SetupMessage(BtnLabelMsgIDs[i]) + 'WWW'; // Add letters for surrounding spaces
if MaxWidth < TmpLabel.Width then
MaxWidth := TmpLabel.Width;
end;
TmpLabel.Caption := 'Yy'; // Determine height
// Assign sizes and positions
Pan.ClientHeight := TmpLabel.Height*4;
with BtnBack do
begin
Width := MaxWidth;
Height := TmpLabel.Height*2;
Left := Parent.ClientWidth - 3*(MaxWidth + ScaleX(ControlGap));
Top := (Parent.ClientHeight - Height) div 2;
end;
with BtnNext do
begin
Width := MaxWidth;
Height := TmpLabel.Height*2;
Left := Parent.ClientWidth - 2*(MaxWidth + ScaleX(ControlGap));
Top := (Parent.ClientHeight - Height) div 2;
end;
with BtnCancel do
begin
Width := MaxWidth;
Height := TmpLabel.Height*2;
Left := Parent.ClientWidth - 1*(MaxWidth + ScaleX(ControlGap));
Top := (Parent.ClientHeight - Height) div 2;
end;
end;
Usage is like
// UninstallProgressForm is about to be shown
// Show modal dialog which allows to select additional components to uninstall
procedure InitializeUninstallProgressForm;
var
Form: TSetupForm;
i: Integer;
NotebookPage: TNewNotebookPage;
ModResult: Integer;
begin
Form := CreateNotebookForm;
for i := 1 to 4 do
begin
NotebookPage := AddPage(Form);
with NotebookPage do
begin
Color := clWindow;
with TLabel.Create(Form) do
begin
Parent := NotebookPage;
SetBounds(0, 0, 50, 30);
Autosize := true;
Font.Size := 14;
Caption := 'Label ' + IntToStr(i);
end;
end;
end;
ModResult := Form.ShowModal;
if ModResult = mrYes then
MsgBox('Continuing uninstall', mbInformation, MB_OK)
else
begin
MsgBox('Cancelled', mbInformation, MB_OK);
Abort;
end;
...
end;
I'm using InnoSetup 5.4.2 and in the docs are several Uninstall Event Functions including: procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
You should be able to create an input page within the [code] section.