zoukankan      html  css  js  c++  java
  • DefWndProc/WndProc/IMessageFilter的区别

    谈到Winform的消息处理,多数时候是通过事件处理程序进行的,但当没有对应的事件时通常的做法是声明DefWndProc或者WndProc或者IMessageFilter,经常在网上看见有文章将三者并列,那么它们有什么区别呢?

    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,这种方式需要创建对应控件的派生类,不能统一对各个窗口的消息进行拦截处理,因为从根本上说这两者都是Windows的窗口过程,只有收到针对本窗口自身的消息。

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

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

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

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

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

    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是消息对应的窗口句柄,根据上面的分析可以知道在窗口过程(DefWndProc,WndProc)中收到的窗口句柄都是该窗口的句柄,而在PreFilterMessage中收到的消息的窗口句柄则根据触发消息的窗口不同而不同。

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

    //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的输出窗口监视到的调试输出:
    tmp180
    P.S.脑子里一直想着好像还有种定义消息处理过程的方式,而且是可以直接指定处理哪个消息,好像使用的关键字是“message”。。。
    在MSDN上搜索N久后反应过来,哦,好象是Delphi中的方法;-)
    原文地址:http://ymail2000.spaces.live.com/?_c11_BlogPart_BlogPart=blogview&_c=BlogPart&partqs=cat%3dWinform
  • 相关阅读:
    【Distributed】缓存技术
    【Redis】基本数据类型
    【Redis】安装、开启以及关闭
    【Ehcache】基础知识学习
    VS2012 改C# 模版
    C# Windows Services 启动和结束其它进程
    .net Console.ReadLine无效
    VS2012在解决方案资源管理器显示解决方案名称
    Mysql 数据库中9大对象
    C# 开发 Windows 服务 使用Log4net 组件 不能生成日志文件
  • 原文地址:https://www.cnblogs.com/zhaoxinshanwei/p/4027536.html
Copyright © 2011-2022 走看看