2009-06-22 51 views
5

如何比較變量的,該變量包含指向具有函數地址的函數的指針?在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 global被設置爲(nil,nil)(根據調試器)。然後再次調用它,並調用存儲在變量中的函數,但當然沒有存儲的函數,所以它跳過零並創建一個異常。

我該怎麼做才能阻止這種情況的發生? (該框架已更改爲一個標籤式的系統,因此操作可能改變。)

+1

聽起來像錯誤是在你沒有顯示的GetFrameWindow裏面。 – 2009-06-22 11:15:11

+0

對於初學者來說 - 爲什麼不總是將EditorFrameWindow設置爲FormDeactivate中的零? – gabr 2009-06-22 13:14:36

+0

實際上只包含「Result:= Handle」。 – mj2008 2009-06-22 13:23:11

回答

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; 
+0

請注意,儘管這樣做可行,但我不喜歡代碼,因此會重新設計它。 – mghie 2009-06-22 10:55:49

+0

@mghie,是的,它可能不是理想的,但正如維護你不完全理解的代碼的情況一樣,有時候你不希望觸及它超過需要! – mj2008 2009-06-22 13:25:38

8

有兩種方法可能需要比較方法指針。方法指針由兩個指針,一個代碼指針和一個對象指針組成。德爾福的原生比較方法指針的方式相比只有代碼指針,而且它看起來像這樣:

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

它檢查在EditorWindowMethod變量的代碼指針是否在TEditFormGetFrameWindow方法的起始地址相匹配。它不檢查對象參考EditorWindowMethod是否與Self相同。如果你想讓對象引用也是相同的,那麼你需要將方法指針拆分成TMethod記錄,這個記錄Mghie's answer演示了這個記錄。 (你可能要比較的對象引用,因爲它聽起來像您有多個編輯表單。它們都具有相同的GetFrameWindow代碼的指針,但它們有不同的對象引用。)

的原因@在代碼是告訴編譯器你想引用方法指針。沒有它,編譯器會嘗試調用方法指針,這就是讓你陷入困境的原因。窗口第一次被停用時,您將稱爲EditorWindowMethod,並將結果窗口句柄與從返回的值進行比較,呼叫GetFrameWindow。當然,它們相匹配,所以您可以取消指定EditorWindowMethod。下一次表單被停用時,您試圖再次撥打EditorWindowMethod,但它是空指針。

您應該考慮擺脫對激活和停用通知的依賴。相反,只需檢查表單在GetFrameWindow內是否處於活動狀態。

+3

+1這是一個棘手的問題(與遺留代碼有關的問題),因爲答案內容豐富而變得有價值。 – Argalatyr 2009-06-22 13:41:58