我正在尝试在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。在Windows x86_64的Lazarus IDE下编译这两个项目。我还尝试使用RTTI TPropertyEditor Grid。当我像这样分配它时:TIPropertyEditor1.TIObject:=FindControl(comps[0](Form1.Handle))
TIPropertyEditor1像正常情况一样像TButton。但是我不知道为什么为什么要像TButton '导致类型转换类型无效。我的问题有解决方案吗?
答案 0 :(得分:3)
程序包(如BPL程序包)在中继中使用,但尚未运行。 Designtime组件被编译到IDE二进制文件中(它还具有Lazarus更快启动的优点)
除了那些使用普通.so / dll的用户,除了身份问题之外,DLL和主程序都具有RTL及其状态的完整副本,其中包括内存管理器,VMT,RTTI,本地化等。托管类型或其中一个模块分配而另一个模块取消分配的任何情况在这种情况下都是危险的。 AS案例使用的类类型信息在每个模块中也是重复的。
另请参见http://wiki.freepascal.org/packages。
P.s。 David基本上是正确的,并且Lazarus的状态与Delphi的状态大致相同,只是没有可用的软件包,也没有共享的内存管理器概念来解决此问题。
答案 1 :(得分:-1)
将对Form实例的引用发送到按钮创建调用是正确的决定,因为只有死了,它将调用所有子组件的析构函数。
您应该从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;