【问题标题】:calling delphi procedure as method调用delphi过程作为方法
【发布时间】:2016-07-12 08:18:26
【问题描述】:

这是我编译好的简单代码,但会引发访问冲突。它进入 MD 程序,调试器显示一些 X 和 Y 值,但在退出程序后发生 AV。希望有人能帮忙。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Controls, Forms,  ExtCtrls;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    procedure FormCreate(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

    {$R *.dfm}

procedure MD(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  form1.caption:= inttostr(x)+ ' '+ inttostr(y);
end;

procedure TForm1.FormCreate(Sender: TObject);

function MakeMethod(data, code: pointer): TMethod;
begin
  result.Data:= data;
  result.Code:= code;
end;

begin
  panel1.OnMouseDown:= TMouseEvent(MakeMethod(nil, @MD));
end;

end.

谢谢

【问题讨论】:

  • 你对 AV 感到惊讶吗? - 你将 Nil 传递给 MakeMethod。
  • 如果我将指针指向某个字节数组,也会发生同样的情况。
  • @MartynA,你的cmets完全是误导,MD从不引用data指针,实际失败的原因是参数不匹配。
  • 如果你不想让MD 成为TForm1 的方法,你可以尝试我在这里描述的技术:stackoverflow.com/questions/11083336/…
  • @Uli Gerhardt - 是的,我知道该解决方案并且它工作正常。然而,类过程的解决方案引发了我不理解的 Lazarus 的编译问题(这是我的主要兴趣)。但是,这应该是针对其他线程的。

标签: delphi lazarus freepascal


【解决方案1】:

MD签名应该包含额外的隐藏参数;它解决了 AV 问题。

unit Unit1;

interface

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


type
  TForm1 = class(TForm)
    Panel1: TPanel;
    procedure FormCreate(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure MD(Instance, Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  form1.caption:= inttostr(x)+ ' '+ inttostr(y);
end;

procedure TForm1.FormCreate(Sender: TObject);

function MakeMethod(data, code: pointer): TMethod;
begin
  result.Data:= data;
  result.Code:= code;
end;

begin
  panel1.OnMouseDown:= TMouseEvent(MakeMethod(nil, @MD));
end;

end.

【讨论】:

  • 想解释一下为什么OnCreate 不是个好地方?我对此从来没有任何问题。 VCL/FMX 也将其作为Create 序列的步骤。
  • @FreeConsulting - 我的错,也适用于OnCreate。已编辑。
  • @Djole,它起作用了,因为并非所有TMouseEvent 参数都可以放入寄存器,因此使用堆栈。因此,当您不匹配签名时会导致堆栈未对齐。
  • This technique 在没有黑客的情况下基本相同。 :-)
  • 使用类方法无疑是更好的解决方案。
【解决方案2】:

尝试让 MD 成为表单类的成员。按以下方式编辑您的示例: 在类定义中:

type
TForm1 = class(TForm)
  Panel1: TPanel;
  procedure FormCreate(Sender: TObject);
  procedure MD(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
end;

稍后在您的代码中确保输入 MD 方法的所有者,如下所示:

procedure TForm1.MD(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

最后,当将此事件处理程序分配给您的组件时,您所要做的就是:

panel1.OnMouseDown:= MD;

我不知道您的意图是什么,但这就是您在运行时处理事件处理程序的方式。

【讨论】:

  • 我知道,但我故意尝试使用全局函数,而不是方法。这只是出于好奇。
  • 也许可以澄清你的意图。我根本不认为需要按照您的示例建议的方式做事。也许尝试使用事件处理程序以外的方法来使用您的方法。先尝试一些简单的方法,也许是不带参数的方法,然后自己尝试带参数的方法。
猜你喜欢
  • 2021-07-15
  • 1970-01-01
  • 1970-01-01
  • 2011-01-28
  • 1970-01-01
  • 2019-04-28
  • 2020-06-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多