WinForm中DefWndProc、WndProc與IMessageFilter的區(qū)別
一般來說,Winform的消息處理機(jī)制多數(shù)時(shí)候是通過事件處理程序進(jìn)行的,但當(dāng)沒有對(duì)應(yīng)的事件時(shí)通常的做法是聲明DefWndProc或者WndProc或者IMessageFilter,經(jīng)常在網(wǎng)上看見有文章將三者并列,那么它們有什么區(qū)別呢?本文對(duì)此做一簡(jiǎn)單分析如下:
DefWndProc和WndProc都是繼承自Control類中的虛方法,其原型如下:
protected override void DefWndProc(ref Message m) { .... base.DefWndProc(m); } protected override void WndProc(ref Message m); { ..... base.WndProc(m); }
所有的有用戶界面的控件都繼承自Control,這種方式需要?jiǎng)?chuàng)建對(duì)應(yīng)控件的派生類,不能統(tǒng)一對(duì)各個(gè)窗口的消息進(jìn)行攔截處理,因?yàn)閺母旧险f這兩者都是Windows的窗口過程,只有收到針對(duì)本窗口自身的消息。
通過復(fù)習(xí)Windows的消息處理機(jī)制,對(duì)這三者的關(guān)系可以有更好的理解。應(yīng)用程序的消息來自于系統(tǒng)消息隊(duì)列,被應(yīng)用程序的主程序中的消息循環(huán)所處理。這個(gè)消息循環(huán)從應(yīng)用程序的消息隊(duì)列中取出消息,進(jìn)行預(yù)處理,然后派發(fā)到消息對(duì)應(yīng)的窗口過程,窗口過程在被調(diào)用后根據(jù)消息的類型進(jìn)行相應(yīng)的處理,有些可以由Windows默認(rèn)處理的消息就調(diào)用Windows的DefWindowProc。
這里的WndProc就是對(duì)應(yīng)控件窗口的窗口過程,而DefWndProc會(huì)被WndProc調(diào)用,處理那些WndProc中未處理的消息(包括WndProc未吞掉的),因此DefWndProc收到的消息會(huì)比WndProc少。
IMessageFilter的調(diào)用發(fā)生在應(yīng)用程序的消息循環(huán)中,是消息預(yù)處理的一部分,所以它收到的消息是更全的(除了直接發(fā)送到窗口過程不進(jìn)入消息隊(duì)列的那些消息)。使用方式如下:
public class MessageFilter : IMessageFilter { public bool PreFilterMessage(ref Message msg) { //識(shí)別消息并處理 //return true;//吞掉消息,不派發(fā) return false;//進(jìn)入下一步派發(fā)到對(duì)應(yīng)窗口過程 } } //在應(yīng)用程序消息循環(huán)中加入消息過濾器 MessageFilter f = new MessageFilter(this.lbMsg); Application.AddMessageFilter(f);
三者都有一個(gè)共同的參數(shù)類型Message,它封裝了Windows消息。同時(shí)還包括一個(gè)很方便的ToString方法,可以將Message對(duì)象轉(zhuǎn)換成包括消息名稱(WM_XXX)在內(nèi)的字符串,通過Reflector可以看到實(shí)現(xiàn)是通過一個(gè)內(nèi)部類MessageDecoder,使用一個(gè)很長(zhǎng)的switch語句將消息ID轉(zhuǎn)換成消息名稱。
Message的定義如下:
[StructLayout(LayoutKind.Sequential), SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] public struct Message { private IntPtr hWnd; private int msg; private IntPtr wparam; private IntPtr lparam; private IntPtr result; public IntPtr HWnd { get; set; } public int Msg { get; set; } public IntPtr WParam { get; set; } public IntPtr LParam { get; set; } public IntPtr Result { get; set; } public object GetLParam(Type cls); public static Message Create(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam); public override bool Equals(object o); public static bool operator !=(Message a, Message b); public static bool operator ==(Message a, Message b); public override int GetHashCode(); public override string ToString(); }
其中hWnd是消息對(duì)應(yīng)的窗口句柄,根據(jù)上面的分析可以知道在窗口過程(DefWndProc,WndProc)中收到的窗口句柄都是該窗口的句柄,而在PreFilterMessage中收到的消息的窗口句柄則根據(jù)觸發(fā)消息的窗口不同而不同。
在PreFilterMessage中收到消息時(shí),可以使用Control.FromHandle得到窗口對(duì)應(yīng)的控件對(duì)象,原型如下:
//Declaring Type: System.Windows.Forms.Control //Assembly: System.Windows.Forms, Version=2.0.0.0 public static Control FromHandle(IntPtr handle);通過這種方式可以監(jiān)測(cè)各消息的信息來自哪個(gè)控件。 public bool PreFilterMessage(ref Message msg) { Control c = Control.FromHandle(msg.HWnd); if (c == null) System.Diagnostics.Debug.WriteLine("Filter:NULL" +"-" + msg.ToString()); else System.Diagnostics.Debug.WriteLine("Filter:" +c.Name+"-"+ msg.ToString()); return false; }
從Visual Studio的輸出窗口監(jiān)視到的調(diào)試輸出如下圖所示:
希望本文所述分析對(duì)大家深入理解WinForm的消息處理機(jī)制有所幫助。
相關(guān)文章
使用遞歸實(shí)現(xiàn)數(shù)組求和示例分享
這篇文章主要介紹了使用遞歸實(shí)現(xiàn)數(shù)組求和示例,思路是給定一個(gè)含有n個(gè)元素的整型數(shù)組a,求a中所有元素的和,需要的朋友可以參考下2014-03-03C#逐行分元素讀取記事本數(shù)據(jù)并寫入數(shù)據(jù)庫的方法
這篇文章主要介紹了C#逐行分元素讀取記事本數(shù)據(jù)并寫入數(shù)據(jù)庫的方法,通過StreamReader類里的ReadLine()方法實(shí)現(xiàn)逐行讀取的功能,是非常實(shí)用的技巧,需要的朋友可以參考下2014-12-12WPF利用TabControl控件實(shí)現(xiàn)拖拽排序功能
在UI交互中,拖拽操作是一種非常簡(jiǎn)單友好的交互,這篇文章主要為大家介紹了WPF如何利用TabControl控件實(shí)現(xiàn)拖拽排序功能,需要的小伙伴可以參考一下2023-10-10Unity UGUI的GridLayoutGroup網(wǎng)格布局組件使用詳解
這篇文章主要介紹了Unity UGUI的GridLayoutGroup網(wǎng)格布局組件使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07C# 時(shí)間與時(shí)間戳互轉(zhuǎn)的方法(13位)
這篇文章主要介紹了C# 時(shí)間與時(shí)間戳互轉(zhuǎn)的方法(13位),詳細(xì)的介紹了常出現(xiàn)的幾種時(shí)間方式及其時(shí)間與時(shí)間戳互轉(zhuǎn)的方法,非常具有實(shí)用價(jià)值,希望此文章對(duì)各位有所幫助2018-10-10C#命令行參數(shù)解析庫System.CommandLine使用
System.CommandLine是一個(gè)基于.Net Standard 2.0的命令行參數(shù)解析庫,該項(xiàng)目還是屬于beta狀態(tài),期待以后的正式版本,文章通過示例代碼給大家介紹了System.CommandLine使用講解,感興趣的朋友一起看看吧2021-06-06C#使用iTextSharp將PDF轉(zhuǎn)成文本的方法
這篇文章主要介紹了C#使用iTextSharp將PDF轉(zhuǎn)成文本的方法,涉及C#操作pdf文件的相關(guān)技巧,需要的朋友可以參考下2015-05-05C# JSON格式化轉(zhuǎn)換輔助類 ConvertJson
本文介紹使用C#原生代碼實(shí)現(xiàn) JSON格式化以及各種類型轉(zhuǎn)化JSON的輔助類,幫助開發(fā)人員快速開發(fā)。2016-04-04C#實(shí)現(xiàn)餐飲管理系統(tǒng)完整版
這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)餐飲管理系統(tǒng)的完整版,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01C#中Winform 實(shí)現(xiàn)Ajax效果自定義按鈕
這篇文章主要介紹了C#中Winform 實(shí)現(xiàn)Ajax效果自定義按鈕的相關(guān)資料,需要的朋友可以參考下2017-12-12