WinForm中DefWndProc、WndProc与IMessageFilter的区别

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

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

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

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的定义如下:

[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得到窗口对应的控件对象,原型如下:

//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的输出窗口监视到的调试输出如下图所示:

希望本文所述分析对大家深入理解WinForm的消息处理机制有所帮助。

(0)

相关推荐

  • Python中的map、reduce和filter浅析

    1.先看看什么是 iterable 对象 以内置的max函数为例子,查看其doc: 复制代码 代码如下: >>> print max.__doc__max(iterable[, key=func]) -> valuemax(a, b, c, ...[, key=func]) -> value With a single iterable argument, return its largest item.With two or more arguments, return t

  • Python数组条件过滤filter函数使用示例

    使用filter函数,实现一个条件判断函数即可. 比如想过滤掉字符串数组中某个敏感词,示范代码如下: #filter out some unwanted tags def passed(item): try: return item != "techbrood" #can be more a complicated condition here except ValueError: return False org_words = [["this","is

  • servlet中session简介和使用例子

    HttpServletRequest有两个重载的getSession()方法,一个接受一个boolean的类型的值,另一个不带任何参数,getSession()方法和getSession(true)方法功能一样,就是如果对应的客户端已经产生过一个session,那么就会返回这个旧的session,否则,这个方法将会产生一个session ID并且和对应的客户端绑定在一起,而如果getSession(false)表示如果对应的客户端已经有对应的session,那么返回这个旧的session,否则不

  • 实例解读Ajax与servlet交互的方法

    本文以实例形式剖析了Ajax与servlet的交互,并且代码中有较为详细的注释,以帮助大家阅读理解.具体的实现方法如下: 1.JavaScript部分 var req; /*通过异步传输XMLHTTP发送参数到ajaxServlet,返回符合条件的XML文档*/ var url; function getResult() { var f=document.getElementById("form_pub"); var key=f.s.options[f.s.selectedIndex]

  • Servlet和Filter之间的区别与联系

    filter是一个可以复用的代码片段,可以用来转换HTTP请求.响应和头信息.Filter不像Servlet,它不能产生一个请求或者响应,它只是修改对某一资源的请求,或者修改从某一的响应. 最近使用插装的时候,改用cookie对计算机进行识别,加入了过滤,仔细研究了一下servlet和filter,区别主要是: 过滤器的生命周期一般都要经过下面三个阶段: servlet的特点是: 初始化 当容器第一次加载该过滤器时,init() 方法将被调用.该类在这个方法中包含了一个指向 Filter Con

  • java servlet过滤器使用示例

    Servlet过滤器简介      Servlet过滤器实际上就是一个标准的java类,这个类通过实现Filter接口获得过滤器的功能.它在jsp容器启动的时候通过web.xml配置文件被系统加载.Servlet过滤器在接收到用户请求的时候被调用,当服务器接收到用户的请求的时候,依次调用配置好的过滤器,完成后将执行请求所要求的servlet,而servlet执行后的响应,则先通过配置好的过滤器后再发送给用户. 过滤器的用途:1.用户认证和授权管理.2.统计web应用的访问量和访问命中率,生成访问

  • 利用JQuery和Servlet实现跨域提交请求示例分享

    原理:JavaScript的Ajax不可以跨域,但是可以通过向本地的一个Servlet发出请求,由Servlet完成跨域.再把远程的结构返回给客户端.这样Ajax就可以跨域了.在后面,再发一个PHP版本的,请大家关注啊.下面是代码 JS代码: 注意:在Post方式时,param1和param2为向远程发送的参数值,可以有多个. 复制代码 代码如下: //GET方式function reqeustCrossDomainProxyGet(){    var url = "http://www.bai

  • WinForm中DefWndProc、WndProc与IMessageFilter的区别

    一般来说,Winform的消息处理机制多数时候是通过事件处理程序进行的,但当没有对应的事件时通常的做法是声明DefWndProc或者WndProc或者IMessageFilter,经常在网上看见有文章将三者并列,那么它们有什么区别呢?本文对此做一简单分析如下: DefWndProc和WndProc都是继承自Control类中的虚方法,其原型如下: protected override void DefWndProc(ref Message m) { .... base.DefWndProc(m)

  • WinForm中KeyDown,KeyPress和KeyUp的顺序与区别解析

    WinForm中的键盘按键有KeyDown,KeyPress和KeyUp事件.那么它们的顺序以及区别在哪里呢?本文就此作出如下分析: 一.顺序: 根据MSDN所讲,三者的顺序是:KeyDown>KeyPress>KeyUp. 二.区别: KeyDown和KeyPress很接近,都是在按键按下时候先后发生.KeyUp是放掉某个键之后发生的事件. 三.KeyDown和KeyPress: KeyDown的事件中属性是KeyEventArgs,其中包含三个重要属性: 1)KeyCode(返回一个Key

  • WinForm中的几个实用技巧汇总

    本文汇总了几个WinForm中常见的实用技巧,对于C#程序开发有着很好的参考借鉴价值.具体分析如下: 一.屏蔽窗体右上角关闭按钮 1.重写OnClosing protected override void OnClosing(CancelEventArgs e) { if(this.Visible) { e.Cancel=true; // // WHATE TODO // } } 2.重写WndProc protected override void WndProc(ref Message m)

  • .Net WInform开发笔记(二)Winform程序运行结构图及TCP协议在Winform中的应用

    中午没事,把去年刚毕业那会画的几张图翻出来了,大概介绍Winform应用程序运行的过程,以及TCP协议在Winform中的应用.如果有Windows消息机制等基础,很好理解这两张图. (1)Winform应用程序运行结构图 (2)TCP通讯协议在Winform程序中的应用示意图 熟悉整个程序的来龙去脉,编程的时候就会很轻松,不会云里雾里. 另附公司招聘面试题一份,用了几次,发现效果不好,不知啥原因 1.简述接口.抽象类的区别. 2.简述重载(overload)与重写(override)的区别.

  • C# winform中窗口关闭按钮的隐藏与禁用详解

    首先说一句: 不存任何一种方式可以单独隐藏关闭按钮,隐藏的话会把所有最大化,最小化,帮助,关闭按钮都给隐藏掉. 第一种:禁用窗口上部的关闭按钮 方法一:在Form1的窗口程序中desigener设计器中重写如下方法:(将此部分粘贴到窗口程序中去就可以了) protected override void WndProc(ref Message m) { const int WM_SYSCOMMAND = 0x0112; const int SC_CLOSE = 0xF060; if (m.Msg

  • WinForm中Application.Idle方法详解

    Application.Idle()方法表示:当应用程序处于空闲状态时执行相应代码. 示例程序 1.界面设计:一个简单的Lable控件 2.代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threadin

  • oracle中存储函数与存储过程的区别介绍

    在oracle中,函数和存储过程是经常使用到的,他们的语法中有很多相似的地方,可是也有它们的不同之处,这段时间刚学完函数与存储过程,来给自己做一个总结: 一:存储过程:简单来说就是有名字的pl/sql块. 语法结构: create or replace 存储过程名(参数列表) is --定义变量 begin --pl/sql end; 案例: create or replace procedure add_(a int,b int) is c int; begin c:=a+b; dbms_ou

  • WinForm中如何预览Office文件

    本文为大家分享了WinForm预览Office文档的方法,供大家参考,具体内容如下 使用WinForm, WPF, Office组件 原理:使用Office COM组件将Word,Excel转换为XPS文档, 将WPF的DocumentViewer控件寄宿到WinForm中, 实现预览. 1. 新建WinForm项目 2. 新建WPF用户控件, 注意是WPF控件 3. 编辑WPF用户控件 <UserControl ... ...> <Grid> <DocumentViewer

  • js正则表达式中test,exec,match方法的区别说明

    js正则表达式中test,exec,match方法的区别说明 test test 返回 Boolean,查找对应的字符串中是否存在模式.var str = "1a1b1c";var reg = new RegExp("1.", "");alert(reg.test(str)); // true exec exec 查找并返回当前的匹配结果,并以数组的形式返回.var str = "1a1b1c";var reg = new R

  • Node.js 中exports 和 module.exports 的区别

    Node.js 中exports 和 module.exports 的区别 require 用来加载代码,而 exports 和 module.exports 则用来导出代码.但很多新手可能会迷惑于 exports 和 module.exports 的区别,为了更好的理解 exports 和 module.exports 的关系,我们先来巩固下 js 的基础.示例: test.js var a = {name: 1}; var b = a; console.log(a); console.log

随机推荐