自定义 Inno Setup 卸载页面(非 MsgBox)

8
我需要在安装过程中向用户询问密码,然后将其用作安装后运行的命令的一部分。我使用自定义页面来完成这个操作,效果很好。
我还需要在卸载过程中询问同样的问题,这是卸载后运行的命令的一部分。
我已经查看了帮助文件,但似乎没有可供我在CreateInputQuery函数中使用的卸载的PageID。我不介意在卸载的开始、中间或结束时显示页面,只要能够显示即可。
我不想在卸载中使用MsgBox,因为我想要标准页面的外观和感觉。
您有什么建议可以帮助我实现这个目标吗?
5个回答

13
你可以修改卸载表单,使其像安装表单一样运作(包括页面和下一步/返回按钮)。 在 InitializeUninstallProgressForm 中:
  • 创建新的页面并将它们插入到UninstallProgressForm.InnerNotebook(或.OuterNotebook)中。
  • 实现“下一步”和“返回”按钮。
  • 你也可以让“取消”按钮起作用。
  • 使用UninstallProgressForm.ShowModal运行表单的模态循环。
  • 只有在模态循环退出后,才恢复表单的原始布局,并让卸载继续进行。
[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;

第一页

第二页

卸载


另请参阅如何在Inno Setup卸载程序中创建OuterNotebook/welcome页面?


6
幸运的是,Inno Setup 提供了足够的能力来构建自己的表单,因此您可以在另一个模态表单上模仿卸载表单的任何页面。 以下是我成功创建的内容。该表单从 UninstallForm 中获取尺寸,包含一个 TNewNotebook 控件和用于跳转页面和取消对话框的按钮。

demo

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;

使用方式如下:

// 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;

有趣的想法!不过,如果您可以通过这种方式拦截卸载过程,那么嵌入一个TPanel是否比将另一个表单放在UninstallProgressForm上方更好呢?使用此代码,您难道不是拥有两个单独的(可移动的)表单吗? - TLama
@TLama 确实,那是我尝试的第一件事,但不幸的是那样行不通。卸载程序代码只是在显示 UninstallForm 后无条件地继续执行,而不考虑我们的任何操作。因此,目前似乎唯一干预卸载过程的方法是模态窗体 :( - Fr0sT

2

我也在使用这个版本。抱歉,我应该在最初的问题中提到这一点。因此,我不是在我的InitializeWizard过程中定义对话框(以及它在页面序列中的位置),而是手动使用CreateCustomForm进行编码。我认为CodeClasses.iss示例可以帮助解决问题。感谢您的建议 - 我会尝试一下... - eyoopmeduck

2

Inno目前不支持在卸载过程中使用向导页面。您需要使用表单替代。


你实际上可以在卸载表单中实现页面。请查看我的回答:https://dev59.com/p1vUa4cB1Zd3GeqPrkL3#42550055 - Martin Prikryl

0

如果您只需要一个页面,我们可以简化Martin Prikryl的答案。

它仍然是相同的过程,但所有步骤都在InitializeUninstallProgressForm中实现:

  • 创建卸载按钮。
  • 创建新页面并将其插入到UninstallProgressForm.InnerNotebook(或.OuterNotebook)中。
  • 向页面添加控件。
  • 您还可以使“取消”按钮起作用。
  • 使用UninstallProgressForm.ShowModal运行表单的模态循环。
  • 仅在模态循环退出后,恢复表单的原始布局并让卸载继续。
[Code]

procedure InitializeUninstallProgressForm();
var
  UninstallPage: TNewNotebookPage;
  UninstallButton: TNewButton;

  OriginalPageNameLabel: string;
  OriginalPageDescriptionLabel: string;
  OriginalCancelButtonEnabled: Boolean;
  OriginalCancelButtonModalResult: Integer;

  ctrl: TWinControl;
begin
  if not UninstallSilent then
  begin
    { Create Uninstall button }
    ctrl := UninstallProgressForm.CancelButton;
    UninstallButton := TNewButton.Create(UninstallProgressForm)
    UninstallButton.Parent := UninstallProgressForm;
    UninstallButton.Left := ctrl.Left - ctrl.Width - ScaleX(10);
    UninstallButton.Top := ctrl.Top;
    UninstallButton.Width := ctrl.Width;
    UninstallButton.Height := ctrl.Height;
    UninstallButton.TabOrder := ctrl.TabOrder;
    UninstallButton.Caption := 'Uninstall';
    { Make the "Uninstall" button break the ShowModal loop }
    UninstallButton.ModalResult := mrOK;    
    UninstallProgressForm.CancelButton.TabOrder := UninstallButton.TabOrder + 1;

    { Create the page and make it active }
    UninstallPage := TNewNotebookPage.Create(UninstallProgressForm);
    UninstallPage.Notebook := UninstallProgressForm.InnerNotebook;
    UninstallPage.Parent := UninstallProgressForm.InnerNotebook;
    UninstallPage.Align := alClient;
  
    UninstallProgressForm.InnerNotebook.ActivePage := UninstallPage;

    { Create and add a controls to the page }
    ctrl := UninstallProgressForm.StatusLabel;
    with TNewStaticText.Create(UninstallProgressForm) do
    begin
      Parent := UninstallPage;
      Top := ctrl.Top;
      Left := ctrl.Left;
      Width := ctrl.Width;
      Height := ctrl.Height;
      AutoSize := False;
      ShowAccelChar := False;
      Caption := 'Press Next to proceeed with uninstallation.';
    end;    

    { Save state }
    OriginalPageNameLabel := UninstallProgressForm.PageNameLabel.Caption;
    OriginalPageDescriptionLabel := UninstallProgressForm.PageDescriptionLabel.Caption;
    OriginalCancelButtonEnabled := UninstallProgressForm.CancelButton.Enabled;
    OriginalCancelButtonModalResult := UninstallProgressForm.CancelButton.ModalResult;

    { Run our wizard pages } 
    UninstallProgressForm.PageNameLabel.Caption := 'First uninstall wizard page';
    UninstallProgressForm.PageDescriptionLabel.Caption := 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';    
    UninstallProgressForm.CancelButton.Enabled := True;    
    UninstallProgressForm.CancelButton.ModalResult := mrCancel;

    { Show the form }
    if UninstallProgressForm.ShowModal = mrCancel then Abort;

    { Restore the standard page layout }
    UninstallButton.Visible := False;

    UninstallProgressForm.PageNameLabel.Caption := OriginalPageNameLabel;
    UninstallProgressForm.PageDescriptionLabel.Caption := OriginalPageDescriptionLabel;
    UninstallProgressForm.CancelButton.Enabled := OriginalCancelButtonEnabled;
    UninstallProgressForm.CancelButton.ModalResult := OriginalCancelButtonModalResult;

    UninstallProgressForm.InnerNotebook.ActivePage := UninstallProgressForm.InstallingPage;
  end;
end;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接