如何将DLL中的表单嵌入到Inno Setup向导页面中?

3

我已经在 Delphi 的 DLL 中构建了一些 VCL 表单,这些表单将在 Inno Setup 安装过程中显示。然而,如果我能够将这些表单嵌入到 Inno Setup 向导中,那将更加简洁。

我该怎么做呢?

1个回答

5
您可以创建一个导出函数来完成库中的所有操作。这个函数的最小要求是一个参数,用于将您的表单嵌入到 Inno Setup 控件的句柄中。嵌入所需的边界可以通过库端的 Windows API 函数调用获得。
下面是 Delphi 部分,显示了 DLL 项目中带有表单的单位:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Grids;

type
  TEmbeddedForm = class(TForm)
    StringGrid1: TStringGrid;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  end;

procedure CreateEmbeddedForm(ParentWnd: HWND); stdcall;

implementation

{$R *.dfm}

{ TEmbeddedForm }

procedure TEmbeddedForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

{ CreateEmbeddedForm }

procedure CreateEmbeddedForm(ParentWnd: HWND); stdcall;
var
  R: TRect;
  Form: TEmbeddedForm;
begin
  Form := TEmbeddedForm.Create(nil);
  Form.ParentWindow := ParentWnd;
  Form.BorderStyle := bsNone;
  GetWindowRect(ParentWnd, R);
  Form.BoundsRect := R;
  Form.Show;
end;

exports
  CreateEmbeddedForm;

end.

这里是Inno Setup脚本:

[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program

[Files]
Source: "MyDLL.dll"; Flags: dontcopy

[Code]
procedure CreateEmbeddedForm(ParentWnd: HWND);
  external 'CreateEmbeddedForm@files:MyDLL.dll stdcall';

procedure InitializeWizard;
var
  CustomPage: TWizardPage;
begin
  CustomPage := CreateCustomPage(wpWelcome, 'Caption', 'Description');
  CreateEmbeddedForm(CustomPage.Surface.Handle);
end;

请注意,Inno Setup还支持COM Automation,所以上述方法并不是将对象嵌入向导表单的唯一选项。但是,它是最简单的方法。

还有一个提示可能对您有用。如果您需要从库中执行某个Inno Setup脚本代码,可以在Inno Setup端创建回调函数,并在DLL端传递和执行它。


PS:我有意忽略了GetWindowRect函数调用的结果(但你不应该这样做),因为如果那个调用失败了,你会在哪里放置表单呢?从你的DLL抛出异常是无用的,因为你不会得到它的对象以供Inno Setup使用。虽然如果您为导出函数添加一个边界参数,或者例如使用现有的SetLastError机制,并使用29位(通过在IS中调用DllGetLastError)至少报告IS端找到父级边界失败,您可以修复此弱点。这是我留给你决定的事情。 - TLama
P.P.S. 我强烈建议使用第一种选项,因为将边界参数添加到函数中可以使您获得更好的灵活性。 - TLama
2
@Sertac,例如这样。从通常的实现角度来看,这是相当棘手的,因为Inno Setup中定义的每个过程实际上都是一个隐藏对象的方法。当我尝试进行回调时,我花了一些时间才意识到这一点。然后我记起来脚本中的所有事件方法(即使是你自己定义的)都是无对象过程,因此必须有一个隐藏的对象将它们全部包装成方法。 - TLama
1
很有趣,谢谢。如果我需要的话,我一定会问一个适当的问题。 :) - Sertac Akyuz
1
谢谢,很棒能知道 Stack Overflow 上有一个 Inno Setup 专家 :-) - Jerry Dodge
显示剩余2条评论

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