zoukankan      html  css  js  c++  java
  • WinForm中DefWndProc、WndProc与IMessageFilter的区别

    这篇文章主要介绍了WinForm中DefWndProc、WndProc与IMessageFilter的区别,较为详细的分析了WinForm的消息处理机制,需要的朋友可以参考下
     
     

    一般来说,Winform的消息处理机制多数时候是通过事件处理程序进行的,但当没有对应的事件时通常的做法是声明DefWndProc或者WndProc或者IMessageFilter,经常在网上看见有文章将三者并列,那么它们有什么区别呢?本文对此做一简单分析如下:

    DefWndProc和WndProc都是继承自Control类中的虚方法,其原型如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    protected override void DefWndProc(ref Message m)
    {
     ....
       base.DefWndProc(m);
    }
       
    protected override void WndProc(ref Message m);
    {
     .....
       base.WndProc(m);
    }

    所有的有用户界面的控件都继承自Control,这种方式需要创建对应控件的派生类,不能统一对各个窗口的消息进行拦截处理,因为从根本上说这两者都是Windows的窗口过程,只有收到针对本窗口自身的消息。

    通过复习Windows的消息处理机制,对这三者的关系可以有更好的理解。应用程序的消息来自于系统消息队列,被应用程序的主程序中的消息循环所处理。这个消息循环从应用程序的消息队列中取出消息,进行预处理,然后派发到消息对应的窗口过程,窗口过程在被调用后根据消息的类型进行相应的处理,有些可以由Windows默认处理的消息就调用Windows的DefWindowProc。

    这里的WndProc就是对应控件窗口的窗口过程,而DefWndProc会被WndProc调用,处理那些WndProc中未处理的消息(包括WndProc未吞掉的),因此DefWndProc收到的消息会比WndProc少。

    IMessageFilter的调用发生在应用程序的消息循环中,是消息预处理的一部分,所以它收到的消息是更全的(除了直接发送到窗口过程不进入消息队列的那些消息)。使用方式如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class MessageFilter : IMessageFilter
    {
     public bool PreFilterMessage(ref Message msg)
     {
       //识别消息并处理
      //return true;//吞掉消息,不派发
       return false;//进入下一步派发到对应窗口过程
     }
    }
       
    //在应用程序消息循环中加入消息过滤器
    MessageFilter f = new MessageFilter(this.lbMsg);
    Application.AddMessageFilter(f);

    三者都有一个共同的参数类型Message,它封装了Windows消息。同时还包括一个很方便的ToString方法,可以将Message对象转换成包括消息名称(WM_XXX)在内的字符串,通过Reflector可以看到实现是通过一个内部类MessageDecoder,使用一个很长的switch语句将消息ID转换成消息名称。

    Message的定义如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    [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是消息对应的窗口句柄,根据上面的分析可以知道在窗口过程(DefWndProc,WndProc)中收到的窗口句柄都是该窗口的句柄,而在PreFilterMessage中收到的消息的窗口句柄则根据触发消息的窗口不同而不同。

    在PreFilterMessage中收到消息时,可以使用Control.FromHandle得到窗口对应的控件对象,原型如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //Declaring Type: System.Windows.Forms.Control //Assembly: System.Windows.Forms, Version=2.0.0.0 public static Control FromHandle(IntPtr handle);通过这种方式可以监测各消息的信息来自哪个控件。
    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的输出窗口监视到的调试输出如下图所示:

  • 相关阅读:
    27 Spring Cloud Feign整合Hystrix实现容错处理
    26 Spring Cloud使用Hystrix实现容错处理
    25 Spring Cloud Hystrix缓存与合并请求
    24 Spring Cloud Hystrix资源隔离策略(线程、信号量)
    23 Spring Cloud Hystrix(熔断器)介绍及使用
    22 Spring Cloud Feign的自定义配置及使用
    21 Spring Cloud使用Feign调用服务接口
    20 Spring Cloud Ribbon配置详解
    19 Spring Cloud Ribbon自定义负载均衡策略
    18 Spring Cloud Ribbon负载均衡策略介绍
  • 原文地址:https://www.cnblogs.com/rinack/p/4260083.html
Copyright © 2011-2022 走看看