从类引用创建的表单中执行方法(Delphi)

Posted

技术标签:

【中文标题】从类引用创建的表单中执行方法(Delphi)【英文标题】:Execute a method from a form created by class reference (Delphi) 【发布时间】:2010-06-07 18:02:16 【问题描述】:

我有一个表单 (form2),我实现了以下 PUBLIC 方法:

function ShowInterface(i:integer):boolean;

此表单位于将被动态加载的包中。现在我想实例化这个表单(form2)并执行上面的方法。

重要提示:我无法在 form1 中引用 form2 的单位。

我尝试了这段代码,但它从未找到“ShowInterface”指针(返回 nil)。

procedure TfrmForm1.Button1Click(Sender: TObject);
var
  PackageModule: HModule;
  AClass: TPersistentClass;
  ShowInterface: function (i:integer):boolean;
  frm: TCustomForm;
begin
  PackageModule := LoadPackage('form2.bpl');
  if PackageModule <> 0 then
  begin
    AClass := GetClass('TfrmForm2');
    if AClass <> nil then // <<-- FINE!! IT FINDS OUT 'TfrmForm2' in 'form2.bpl')
    begin
      frm := TComponentClass(AClass).Create(Self) as TCustomForm;
      ShowInterface := frm.MethodAddress('ShowInterface'); // <<-- HERE!! ALLWAYS RETURNS "NIL"
      if @ShowInterface <> nil then
        ShowInterface(1);
      // but if I call frm.Show, it works fine. frm is "loaded"!!!

      frm.Free;
    end;
    DoUnloadPackage(PackageModule);
  end;
end;

提前致谢。

【问题讨论】:

【参考方案1】:

MethodAddress 仅适用于 已发布 方法。将其移至 已发布 部分,它应该可以工作。

或者,如果您有 Delphi 2010,扩展的 RTTI 提供了一种按名称查找 public 方法的方法。 (或其他可见性级别,如果您将其更改为默认值。)

【讨论】:

好的。现在它起作用了。 (我对代码做了一些更改,因为它引发了 AV。请参阅下面的更正代码)。【参考方案2】:

正如 Mason 和 TOndrej 所说,我必须将方法放在已发布的部分。 (谢谢!)

但是,需要一些修复:

procedure TfrmForm1.Button1Click(Sender: TObject);
type
  TShowInterface = function(i:integer):boolean of object;
var
  PackageModule: HModule;
  AClass: TPersistentClass;
  Routine: TMethod;
  ShowInterface : TShowInterface;
  frm: TCustomForm;
begin
  PackageModule := LoadPackage('form2.bpl');
  if PackageModule <> 0 then
  begin
    AClass := GetClass('TfrmForm2');
    if AClass <> nil then
    begin
      frm := TComponentClass(AClass).Create(Self) as TCustomForm;
      Routine.Data := Pointer(frm);
      Routine.Code := frm.MethodAddress('ShowInterface');
      if Assigned(Routine.Code) then
      begin
        ShowInterface := TShowInterface(Routine);
        ShowInterface(1); // showinterface executes a "ShowModal", so we can "free" form after this.
      end;
      frm.Free;
    end;
    DoUnloadPackage(PackageModule);
  end;
end;

【讨论】:

+1 用于在接受 Mason 的回答的同时发布更正的代码。【参考方案3】:

在 D2007 和一些更早的版本中,仅适用于 published 方法或扩展 RTTI:$METHODINFO ON。我还没用过D2010;它似乎有一个新的RTTI系统,已经扩展了很多。

【讨论】:

以上是关于从类引用创建的表单中执行方法(Delphi)的主要内容,如果未能解决你的问题,请参考以下文章

在DELPHI中如何在dbgrid 显示查询数据

逃逸分析(Escape Analysis)

逃逸分析(Escape Analysis)

从 Delphi 中的类引用变量访问类常量

如何从类变量中引用静态方法[重复]

当我引用其他表时,如何保存在 Access 2003 中的表单中创建的数据?