在Delphi中比较指向函数值的指针

mj2*_*008 5 delphi

如何将包含函数指针的变量的与函数地址进行比较?

我正在维护一些代码,它在Delphi 2007中失败了.声明是:

var
  EditorFrameWindow: Function: HWnd Of Object = Nil;
Run Code Online (Sandbox Code Playgroud)

在表单激活中,我有:

procedure TEditForm.FormActivate(Sender: TObject);
begin
  EditorFrameWindow := GetFrameWindow;
end;
Run Code Online (Sandbox Code Playgroud)

在表格停用我有:

procedure TEditForm.FormDeactivate(Sender: TObject);
begin
  if EditorFrameWindow = GetFrameWindow then
    EditorFrameWindow := nil;
end;
Run Code Online (Sandbox Code Playgroud)

所以正在发生的事情是表单被停用了两次,并且因为没有其他任何东西被激活而失败.调用FormDeactivate,它匹配,并且EditorFrameWindow全局设置为(nil,nil)(根据调试器).然后再次调用它,并调用存储在变量中的函数,但当然没有存储的函数,因此它跳过nil并创建一个异常.

我应该怎么做才能阻止这种情况发生?(框架已更改为选项卡式系统,因此操作可能已更改.)

mgh*_*hie 14

procedure TEditForm.FormDeactivate(Sender: TObject);
begin
  if Assigned(EditorFrameWindow) and (EditorFrameWindow = GetFrameWindow) then
    EditorFrameWindow := nil;
end;
Run Code Online (Sandbox Code Playgroud)

每次机会工作?

编辑:

您不比较函数地址,比较这些函数的结果.因此,即使上面的固定代码不再导致异常,它仍然可能无法完成您想要的操作.另一个返回相同结果的函数也会重置事件处理程序.

要真正检查变量是否设置为特定的事件处理程序,您需要比较TMethod记录中的两个元素.就像是:

procedure TEditForm.FormDeactivate(Sender: TObject);
begin
  if (TMethod(EditorFrameWindow).Code = @TForm1.GetFrameWindow)
    and (TMethod(EditorFrameWindow).Data = Self)
  then
    EditorFrameWindow := nil;
end;
Run Code Online (Sandbox Code Playgroud)


Rob*_*edy 9

您可能有两种方法来比较方法指针.方法指针由两个指针组成,一个代码指针和一个对象指针.Delphi比较方法指针的本地方法只比较代码指针,它看起来像这样:

if @EditorWindowMethod = @TEditForm.GetFrameWindow then
  EditorWindowMethod := nil;
Run Code Online (Sandbox Code Playgroud)

它检查在该代码指针是否EditorWindowMethod可变的的起始地址匹配GetFrameWindow在方法TEditForm.它不检查是否对象引用EditorWindowMethod是一样的Self.如果你想使对象引用也是相同的,那么你需要将方法指针拆分为TMethod记录的组成部分,Mghie的答案就是这样.(而且你可能想比较的对象引用,因为它听起来像您有多个编辑表单.它们都具有相同的GetFrameWindow代码指针,但它们有不同的对象引用.)

@代码中的原因是告诉编译器您要引用方法指针.没有它,编译器将尝试调用方法指针,这就是让你陷入困境的原因.第一次停用窗口时,您调用 EditorWindowMethod并将生成的窗口句柄与调用 的返回值进行比较GetFrameWindow.当然,他们匹配,所以你没有分配EditorWindowMethod.下次停用表单时,您尝试EditorWindowMethod再次调用,但它是一个空指针.

您应该考虑摆脱对激活和停用通知的依赖.相反,只需检查表单内部是否处于活动状态GetFrameWindow.

  • +1这是一个混乱的问题(遗留代码的问题)之一变得有价值,因为答案是如此有用的. (3认同)