Window SubClassing之另類運用(之一)
所謂Window SubClassing,中文通常譯為窗口子類化,簡單說來就是截獲並處理窗口過程的技術。可能很多程序員都已經了解這項技術,並且或多或少在自己的程序中使用過它。在微軟的MFC類庫中就大量使用了Window SubClassing方法,以至於有人說“MFC is about Subclassing”。即使你沒有用過,至少你也應該聽說過它。所謂另類,有不循常理、不拘一格的意思。我在這裡將要描述都可以說是一些“旁門左道”的應用,不過或許能夠讓你有耳目一新的感覺。
我的第一個應用是所謂“延時自動關閉的對話框”。Windows中用來顯示信息的MessageBox函數非常簡單方便,但是它有一個致命的缺陷,就是除非用戶按下某個按鈕,否則整個程序的執行都會掛起。這對於無人值守的自動化程序來說是無論如何都不能接受的。如果是在比較依賴於時序的應用程序中(例如多線程程序或者基於定時器的應用),MessageBox還可能嚴重干擾整個程序的執行流程。為了解決這個問題,自己定義一個新的、能夠自動關閉的對話框當然是最直觀的做法,但是我發現這也是應用SubClass的一個好地方,因為我們並不需要在UI上花什麼功夫,唯一需要做的就是為對話框增加一條WM_TIMER的消息和對應的處理程序就行了。
想法雖然簡單,實現起來卻有一點小小的麻煩。首先指出一點:要實現SubClass,唯一的充分必要條件是我們需要獲得某個特定窗口的句柄。就是這個簡單的要求,對於MessageBox來說卻很棘手,因為它是一個模態對話框,窗口在調用MessageBox之後才建立,而在MessageBox返回的時候就已經撤銷了。我們如何獲得這個窗口呢?
這裡的關鍵在於,在調用MessageBox的同時,系統將把應用程序的主線程掛起,在MessageBox返回後才把控制權交還,所以我們沒有獲得這個窗口的機會。既然知道了症結所在,解決方案也就來了:主線程雖然掛起了,但是我可以使用子線程,看你能奈我何?
方法已經找到,接下來的實現可以說是勢如破竹了。首先,聲明必須的類型和變量:
type
TWindowProc = function(AWnd:HWND; uMsg:UINT; wp:WPARAM; lp:LPARAM) : LongInt; stdcall;
var
OldProc : TWindowProc = nil;
既然是SubClass,我們免不了要自己寫一個窗口過程。唯一需要處理的就是WM_TIMER 消息,在收到這個消息的時候關閉對話框即可:
function NewProc(AWnd:HWND; uMsg:UINT; wp:WPARAM; lp:LPARAM):LongInt;stdcall;
begin
Result := 0;
case uMsg of
WM_TIMER:
begin
KillTimer(AWnd, 1);
PostMessage(AWnd, WM_COMMAND, IDCANCEL, 0);
end;
end;
if As