如何将包含指向函数的指针的变量的值与函数地址进行比较?
我正在维护一些代码,它在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并创建一个异常。
我应该怎么做才能阻止这种情况发生? (框架已更改为选项卡式系统,因此操作可能已更改。)
答案 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
变量中的代码指针是否与GetFrameWindow
中TEditForm
方法的起始地址匹配。它不会检查EditorWindowMethod
中的对象引用是否与Self
相同。如果您想使对象引用也相同,那么您需要使用TMethod
记录将方法指针拆分为其组成部分,Mghie's answer演示。 (你可能做想要比较对象引用,因为它听起来像你有多个编辑表单。它们都有相同的GetFrameWindow
代码指针,但它们有不同的对象引用。)< / p>
代码中@
的原因是告诉编译器您要引用方法指针。没有它,编译器将尝试调用方法指针,这就是让你陷入困境的原因。第一次停用窗口时,您调用 EditorWindowMethod
并将生成的窗口句柄与调用 GetFrameWindow
的返回值进行比较。当然,它们匹配,因此您取消分配EditorWindowMethod
。下次停用表单时,您尝试再次调用EditorWindowMethod
,但它是一个空指针。
您应该考虑摆脱对激活和停用通知的依赖。相反,只需检查表单是否在GetFrameWindow
内有效。