DefWndProc/WndProc/IMessageFilter的区别
談到Winform的消息處理,多數(shù)時(shí)候是通過(guò)事件處理程序進(jìn)行的,但當(dāng)沒(méi)有對(duì)應(yīng)的事件時(shí)通常的做法是聲明DefWndProc或者WndProc或者IMessageFilter,經(jīng)常在網(wǎng)上看見(jiàn)有文章將三者并列,那么它們有什么區(qū)別呢?
DefWndProc和WndProc都是繼承自Control類中的虛方法,原型如下:
1: protected override void DefWndProc(ref Message m) 2: { 3: .... 4: base.DefWndProc(m); 5: } 6: ? 7: protected override void WndProc(ref Message m); 8: { 9: ..... 10: base.WndProc(m); 11: }所有的有用戶界面的控件都繼承自Control,這種方式需要?jiǎng)?chuàng)建對(duì)應(yīng)控件的派生類,不能統(tǒng)一對(duì)各個(gè)窗口的消息進(jìn)行攔截處理,因?yàn)閺母旧险f(shuō)這兩者都是Windows的窗口過(guò)程,只有收到針對(duì)本窗口自身的消息。
通過(guò)復(fù)習(xí)Windows的消息處理機(jī)制,對(duì)這三者的關(guān)系可以有更好的理解。應(yīng)用程序的消息來(lái)自于系統(tǒng)消息隊(duì)列,被應(yīng)用程序的主程序中的消息循環(huán)所處理。這個(gè)消息循環(huán)從應(yīng)用程序的消息隊(duì)列中取出消息,進(jìn)行預(yù)處理,然后派發(fā)到消息對(duì)應(yīng)的窗口過(guò)程,窗口過(guò)程在被調(diào)用后根據(jù)消息的類型進(jìn)行相應(yīng)的處理,有些可以由Windows默認(rèn)處理的消息就調(diào)用Windows的DefWindowProc。
這里的WndProc就是對(duì)應(yīng)控件窗口的窗口過(guò)程,而DefWndProc會(huì)被WndProc調(diào)用,處理那些WndProc中未處理的消息(包括WndProc未吞掉的),因此DefWndProc收到的消息會(huì)比WndProc少。
IMessageFilter的調(diào)用發(fā)生在應(yīng)用程序的消息循環(huán)中,是消息預(yù)處理的一部分,所以它收到的消息是更全的(除了直接發(fā)送到窗口過(guò)程不進(jìn)入消息隊(duì)列的那些消息)。使用方式如下:
1: public class MessageFilter : IMessageFilter 2: { 3: public bool PreFilterMessage(ref Message msg) 4: { 5: //識(shí)別消息并處理 6: //return true;//吞掉消息,不派發(fā) 7: return false;//進(jìn)入下一步派發(fā)到對(duì)應(yīng)窗口過(guò)程 8: } 9: } 10: ? 11: //在應(yīng)用程序消息循環(huán)中加入消息過(guò)濾器 12: MessageFilter f = new MessageFilter(this.lbMsg); 13: Application.AddMessageFilter(f); 14: ?三者都有一個(gè)共同的參數(shù)類型Message,它封裝了Windows消息。同時(shí)還包括一個(gè)很方便的ToString方法,可以將Message對(duì)象轉(zhuǎn)換成包括消息名稱(WM_XXX)在內(nèi)的字符串,通過(guò)Reflector可以看到實(shí)現(xiàn)是通過(guò)一個(gè)內(nèi)部類MessageDecoder,使用一個(gè)很長(zhǎng)的switch語(yǔ)句將消息ID轉(zhuǎn)換成消息名稱。
Message的定義如下:
1: [StructLayout(LayoutKind.Sequential), SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] 2: public struct Message 3: { 4: private IntPtr hWnd; 5: private int msg; 6: private IntPtr wparam; 7: private IntPtr lparam; 8: private IntPtr result; 9: public IntPtr HWnd { get; set; } 10: public int Msg { get; set; } 11: public IntPtr WParam { get; set; } 12: public IntPtr LParam { get; set; } 13: public IntPtr Result { get; set; } 14: public object GetLParam(Type cls); 15: public static Message Create(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam); 16: public override bool Equals(object o); 17: public static bool operator !=(Message a, Message b); 18: public static bool operator ==(Message a, Message b); 19: public override int GetHashCode(); 20: public override string ToString(); 21: } 22: ?其中hWnd是消息對(duì)應(yīng)的窗口句柄,根據(jù)上面的分析可以知道在窗口過(guò)程(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);通過(guò)這種方式可以監(jiān)測(cè)各消息的信息來(lái)自哪個(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)試輸出: P.S.腦子里一直想著好像還有種定義消息處理過(guò)程的方式,而且是可以直接指定處理哪個(gè)消息,好像使用的關(guān)鍵字是“message”。。。 在MSDN上搜索N久后反應(yīng)過(guò)來(lái),哦,好象是Delphi中的方法;-) 原文地址:http://ymail2000.spaces.live.com/?_c11_BlogPart_BlogPart=blogview&_c=BlogPart&partqs=cat%3dWinform轉(zhuǎn)載于:https://www.cnblogs.com/08shiyan/archive/2012/01/06/2313864.html
總結(jié)
以上是生活随笔為你收集整理的DefWndProc/WndProc/IMessageFilter的区别的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 大别山区域医疗中心暨市中心医院(二期)项
- 下一篇: 中金汇财是什么