一般來說,Winform的消息處理機制多數時候是通過事件處理程式進行的,但當沒有對應的事件時通常的做法是聲明DefWndProc或者WndProc或者IMessageFilter,經常在網上看見有文章将三者并列,那麼它們有什麼差別呢?本文對此做一簡單分析如下:
DefWndProc和WndProc都是繼承自Control類中的虛方法,其原型如下:
1 2 3 4 5 6 7 8 9 10 11 | |
所有的有使用者界面的控件都繼承自Control,這種方式需要建立對應控件的派生類,不能統一對各個視窗的消息進行攔截處理,因為從根本上說這兩者都是Windows的視窗過程,隻有收到針對本視窗自身的消息。
通過複習Windows的消息處理機制,對這三者的關系可以有更好的了解。應用程式的消息來自于系統消息隊列,被應用程式的主程式中的消息循環所處理。這個消息循環從應用程式的消息隊列中取出消息,進行預處理,然後派發到消息對應的視窗過程,視窗過程在被調用後根據消息的類型進行相應的處理,有些可以由Windows預設處理的消息就調用Windows的DefWindowProc。
這裡的WndProc就是對應控件視窗的視窗過程,而DefWndProc會被WndProc調用,處理那些WndProc中未處理的消息(包括WndProc未吞掉的),是以DefWndProc收到的消息會比WndProc少。
IMessageFilter的調用發生在應用程式的消息循環中,是消息預處理的一部分,是以它收到的消息是更全的(除了直接發送到視窗過程不進入消息隊列的那些消息)。使用方式如下:
12 13 | |
三者都有一個共同的參數類型Message,它封裝了Windows消息。同時還包括一個很友善的ToString方法,可以将Message對象轉換成包括消息名稱(WM_XXX)在内的字元串,通過Reflector可以看到實作是通過一個内部類MessageDecoder,使用一個很長的switch語句将消息ID轉換成消息名稱。
Message的定義如下:
14 15 16 17 18 19 20 21 22 | |
其中hWnd是消息對應的視窗句柄,根據上面的分析可以知道在視窗過程(DefWndProc,WndProc)中收到的視窗句柄都是該視窗的句柄,而在PreFilterMessage中收到的消息的視窗句柄則根據觸發消息的視窗不同而不同。
在PreFilterMessage中收到消息時,可以使用Control.FromHandle得到視窗對應的控件對象,原型如下:
|
從Visual Studio的輸出視窗監視到的調試輸出如下圖所示: