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

时间:2009-06-22 10:45:53

标签: delphi

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

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

var
  EditorFrameWindow: Function: HWnd Of Object = Nil;

在表单激活中,我有:

procedure TEditForm.FormActivate(Sender: TObject);
begin
  EditorFrameWindow := GetFrameWindow;
end;

在表格停用时我得到了:

procedure TEditForm.FormDeactivate(Sender: TObject);
begin
  if EditorFrameWindow = GetFrameWindow then
    EditorFrameWindow := nil;
end;

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

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

2 个答案:

答案 0 :(得分:14)

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

每次机会工作?

修改

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

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

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

答案 1 :(得分:9)

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

if @EditorWindowMethod = @TEditForm.GetFrameWindow then
  EditorWindowMethod := nil;

它检查EditorWindowMethod变量中的代码指针是否与GetFrameWindowTEditForm方法的起始地址匹配。它不会检查EditorWindowMethod中的对象引用是否与Self相同。如果您想使对象引用也相同,那么您需要使用TMethod记录将方法指针拆分为其组成部分,Mghie's answer演示。 (你可能想要比较对象引用,因为它听起来像你有多个编辑表单。它们都有相同的GetFrameWindow代码指针,但它们有不同的对象引用。)< / p>

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

您应该考虑摆脱对激活和停用通知的依赖。相反,只需检查表单是否在GetFrameWindow内有效。