从 DLL 以主窗体 (EXE) 创建对象

Create Object in Main Form (EXE) from DLL

我正在尝试在 DLL 中创建一个 TButton 对象以在 EXE Main 中显示它 Form.Here 是我的代码:

DLL:

library dlltest1;

{$mode objfpc}{$H+}

uses
  Classes,sysutils,Forms,Interfaces,StdCtrls,Windows,Dialogs
  { you can add units after this };
function test(hand:TForm):HWND;

var
  a:TButton;
begin
  a:=TButton.Create(hand);
  a.Show;
  a.Caption:='a';
  result:=a.Handle;
end;

exports test;
begin
end.  

执行文件:

  procedure test(hand:HWND);  external 'dlltest1.dll';
type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    TIPropertyGrid1: TTIPropertyGrid;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private

  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }
  type TComp=function(Hand:HWND):HWND;
var
  comps:array of TComp;

procedure TForm1.FormCreate(Sender: TObject);
begin
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  a:HWND;
begin
SetLength(comps,1);
a:=LoadLibrary('dlltest1.dll');
comps[0]:=TComp(GetProcAddress(a,'test'));
(FindControl(comps[0](Form1.Handle)) as TButton).Caption:='A'; 
end;

它使用命令 comps[0](Form1.Handle) 成功创建了按钮,但是当我尝试执行此 (FindControl(comps[0](Form1.Handle)) as TButton).Caption:='A'; 时,它显示 INVALID TYPE CAST。我检查了 main [=] 中的 class 名称26=] 是 TButton.I 正在为 Windows IDE 编译 Lazarus IDE 下的两个项目 x86_64.I 还尝试使用 RTTI TPropertyEditor Grid.When 我将其分配为:TIPropertyEditor1.TIObject:=FindControl(comps[0](Form1.Handle)) TIPropertyEditor1 就像 TButton 一样 normal.But 我不明白为什么 'as TButton ' 导致无效类型 Cast.Is 我的问题有什么解决方案吗?

包(如 BPL 包)在主干中工作,但尚未运行。设计时组件被编译成 IDE 二进制文件(它也具有 Lazarus 启动速度更快等优点)

如果不使用正常的.so/dlls,除了身份问题,DLL 和主程序都有 RTL 及其状态的完整副本,其中包括内存管理器、VMT、RTTI、本地化等等等等。在这种情况下,使用托管类型或一个模块分配而另一个模块解除分配的任何场景都是危险的。 AS 案例使用类类型信息,每个模块也是重复的。

另请参阅 http://wiki.freepascal.org/packages 以获取简短的论文。

P.s。 David 大部分是正确的,Lazarus 的状态与 Delphi 大致相同,除了还没有可用的包,也没有共享内存管理器概念来解决这个问题。

将对 Form 实例的引用发送到按钮创建调用是正确的决定,因为只有 forn 死了它才会调用所有子组件的析构函数。

你应该return 来自test 函数而不是 Handle 而是 TButton 实例,HWND 和 TButton 之间的区别。 Delphi 在 TButton、TForm 和任何 TWinControl 实例中包装 OS GUI API。在低级别 OS 使用 HWND 作为对 OS 低级别对象的引用。

您不必担心内存泄漏,因为您将 Form 实例发送到 TButton.Create 构造函数。

function test(Owner: TForm): TButton;
begin
  Result := TButton.Create(Owner);
  Result.Show;
  Result.Caption:='a';
end;