谈到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的输出窗口监视到的调试输出:
P.S.脑子里一直想着好像还有种定义消息处理过程的方式,而且是可以直接指定处理哪个消息,好像使用的关键字是“message”。。。
在MSDN上搜索N久后反应过来,哦,好象是Delphi中的方法;-)
原文地址:http://ymail2000.spaces.live.com/?_c11_BlogPart_BlogPart=blogview&_c=BlogPart&partqs=cat%3dWinform

DefWndProc/WndProc/IMessageFilter的区别的更多相关文章

  1. WinForm中DefWndProc、WndProc与IMessageFilter的区别

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

  2. WndProc和hook区别

    1)WndProc函数作用:主要在程序中拦截并处理系统消息和自定义消息 比如:windows程序会产生很多消息,比如你单击鼠标,移动窗口都会产生消息.这个函数就是默认的消息处理函数.你可以重载这个函数 ...

  3. 结合windows消息系统理解C#中WndProc函数和DefWndProc函数

    Windows消息系统由3部分组成:     1.消息队列.Windows应用程序的消息是由Windows统一在一个消息队列中管理的.     2.消息循环.应用程序从Windows消息队列中获得自己 ...

  4. C# 重写WndProc 拦截 发送 系统消息 + windows消息常量值

    接收拦截+发送消息 对于处理所有消息.net 提供了wndproc进行重写 WndProc(ref Message m)protected override void WndProc(ref Mess ...

  5. C# 重写WndProc

    重写WndProc方法来处理 Windows 消息 处理 Windows 消息. 在开发winForm时,常常要处理Windows消息,可以重写WndProc来实现.常见代码如下: using Sys ...

  6. What exactly is the difference between WndProc and DefaultWndProc?

    Control.DefWndProc Sends the specified message to the default window procedure. 参数说明:m:The Windows M ...

  7. c#委托与事件、消息、WndProc用法(转)

    c#委托与事件 心得 c#用委托来实现事件通知机制.委托相当与c++函数指针.整个过程涉及一个呼叫者,一个被呼叫者,还有就是这个委托. - 实现步骤有以下几步: 1. 申明委托, 2.定义呼叫者和调用 ...

  8. 【C++】DDX_Control、SubclassWindow和SubclassDlgItem的区别

    在自绘窗口的时候,子类化是MFC最常用的窗体技术之一.什么是子类化?窗口子类化就是创建一个新的窗口函数代替原来的窗口函数. Subclass(子类化)是MFC中最常用的窗体技术之一.子类化完成两个工作 ...

  9. (转)KeyDown、KeyUp、KeyPress区别

    Windows窗体通过引发键盘事件来处理键盘输入以响应Windows消息,大多数Windows窗体应用程序都通过处理键盘事件来以独占方式处理键盘输入. 1.按键的类型 Windows窗体将键盘输入标 ...

随机推荐

  1. Linux ARM kernel Makefile and Kconfig

    kernel build:顶层Makefile:-->1. include build/main.mk    -->2. include build/kernel.mk         k ...

  2. BZOJ 1821 部落划分

    kruskal.第k-1大的边. 其实prim会更快. #include<iostream> #include<cstdio> #include<cstring> ...

  3. PHP中括号“{}”的3个作用

    1,将多个独立语句合并为一个复合语句,例如“if .... else ....”中推荐如此使用. 2,在变量的间接引用中进行定界,避免歧义.例如“${$my_var[8]}”与“${$my_var}[ ...

  4. 【英语】Bingo口语笔记(49) - 春节请客吃饭的表达

  5. 批量生成sqlldr文件,高速卸载数据

    SQL*Loader 是用于将外部数据进行批量高速加载的数据库的最高效工具,可用于将多种平面格式文件加载到Oracle数据库.SQL*Loader支持传统路径模式以及直接路径这两种加载模式.关于SQL ...

  6. C# Math.Round中国式的四舍五入法

    double dou = 1.255; //这种是错误的 double dou_result = Math.Round(dou, 2); //结果: 1.25 dou_result = Math.Ro ...

  7. 用 Javascript 获取页面大小、窗口大小和滚动条位置

    页面大小.窗口大小和滚动条位置这三个数值在不同的浏览器例如 Firefox 和 IE 中有着不同的实现.即使在同一种浏览器例如 IE 中,不同版本也有不同的实现. 本文给出两个能兼容目前所有浏览器的 ...

  8. EL表达式(胖先生版)

    EL表达式没有指定范围,从最小范围开始 <% pageContext.setAttribute("shxt", "java web"); request. ...

  9. 说说shell脚本中的export 和 source,bash

    小弟刚刚接触linux,对linux上的很多东西都比较陌生,所以写一写博客,当做自己工作的总结和技术的积累吧,也是鞭策自己不断努力的去学习. 今天之所以起这个标题,把export,source ,ba ...

  10. Android Application 深入分析

    http://blog.csdn.net/rain_butterfly/article/details/37598939