【问题标题】:Create Object in Main Form (EXE) from DLL从 DLL 在主窗体 (EXE) 中创建对象
【发布时间】:2018-07-10 12:08:31
【问题描述】:

我正在尝试在 DLL 中创建一个 TButton 对象以在 EXE 主窗体中显示它。这是我的代码:

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.  

EXE:

  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。我检查了主exe 中的类名。ClassName 是TButton。我正在Lazarus IDE 下编译这两个项目对于 Windows x86_64。我也尝试使用 RTTI TPropertyEditor Grid。当我将其分配为:TIPropertyEditor1.TIObject:=FindControl(comps[0](Form1.Handle)) TIPropertyEditor1 就像正常的 TButton 一样。但我无法弄清楚为什么 'as TButton' 会导致 Invalid Type Cast.Is there我的问题有什么解决方案吗?

【问题讨论】:

  • 类型标识在模块间无法正常工作。使用为此目的设计的软件包。假设 Lazarus 有包支持。
  • Lazarus 有包支持,如果你有什么建议可以告诉我,我会很高兴
  • 肯定有文档
  • TIObject 可以感觉到它是 TButton,它可以毫无例外地处理它。所以这意味着类型标识可以跨模块工作。但我正在寻找关于为什么(作为 TButton)导致“无效类型转换”异常的答案以及如何解决它。
  • 我也尝试在 Delphi 10.2 Tokyo 下运行此代码,它什么也没做。没有在表单上创建任何按钮。

标签: dll lazarus hwnd delphi


【解决方案1】:

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

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

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

附: David 基本上是对的,Lazarus 的状态与 Delphi 大致相同,只是还没有工作包,也没有共享内存管理器概念来解决这个问题。

【讨论】:

    【解决方案2】:

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

    你应该从test 函数返回不是Handle 而是TButton 实例,HWND 和TButton 的区别。 Delphi 将 OS GUI API 封装在 TButton、TForm 和任何 TWinControl 实例中。在低级操作系统上,使用 HWND 作为对操作系统低级对象的引用。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-15
      • 2016-03-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多