这篇文章主要介绍了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的输出窗口监视到的调试输出如下图所示:

WinForm中DefWndProc、WndProc与IMessageFilter的区别的更多相关文章

  1. DefWndProc/WndProc/IMessageFilter的区别

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

  2. C# Winform中WndProc 函数作用

    http://blog.csdn.net/xochenlin/article/details/4328954 C# Winform中WndProc 函数作用: 主要用在拦截并处理系统消息和自定义消息 ...

  3. WinForm中Dispose()和Close()的区别

    WinForm中Dispose()和Close()的区别 Close()会自动调用Dispose()方法,但是如果窗体是模态的,则不会调用 所以ShowDialog的时候,要用Dispose(),Sh ...

  4. 在Winform中播放视频等【DotNet,C#】

    在项目中遇到过这样的问题,就是如何在Winform中播放视频.当时考察了几种方式,第一种是直接使用Windows Media Player组件,这种最简单:第二种是利用DirectX直接在窗体或者控件 ...

  5. WPF中Timer与DispatcherTimer类的区别

    前几天在WPF中写了一个轨迹回放的功能,我想稍微做过类似项目的,都晓得采用一个时间控件或者时间对象作为调度器,我在这么做的时候,出现了问题,于是将程序中的Timer换成了DispatchTimer,然 ...

  6. 关于FastReport在winform中的使用(包含FastReport.net的安装步骤链接)

    一.FastReport的简介 FastReport是功能齐全的报表控件,使开发者可以快速并高效地为·NET/VCL/COM/ActiveX应用程序添加报表支持. 二.FastReport的安装(推荐 ...

  7. C#在WinForm中重写ProgressBar控件(带%的显示)

    废话少说,直接上码: namespace csPublish { [ToolboxItem(true)] class textProgressBar : System.Windows.Forms.Pr ...

  8. 在winform中,禁止combobox随着鼠标一起滑动!

    在winform中,如果form上或者是控件上有一个combobox控件,当你选择这个控件,当你鼠标移动其他地方,滑动鼠标时,这时combobox的选择值就会随之鼠标一起变化,如果你不想让comboB ...

  9. 在Winform中屏蔽UnityWebPlayer的右键以及自带Logo解决方案整理

    根据项目的需要,对已经完成的Unity三维模型以及游戏要使用Winform进行包装,也就是使用Winform做一层外壳.因此在展示Unity的时候使用到了UnityWebPlayer这个插件,对于此插 ...

随机推荐

  1. 了解shell

    1. shell 脚本文件第一行:    #!/bin/sh 或 #!/bin/bash "#!"  又称为纪数,在执行bash脚本的时候,内核会根据它来确定该用哪个程序来解释脚本 ...

  2. 第三百五十八天 how can I 坚持

    万事要有度,不要话唠,也不能不说,把握好分寸,今天貌似又说多了. 加了天班,理了个发,还有老爸明天来北京. 还有同学聚会没去,还有金龙让去吃鱼,没去. 还有.小米视频通话还行,能远程控制桌面, 还有, ...

  3. 转】Linux下安装Tomcat服务器和部署Web应用

    原博文出自于: http://www.cnblogs.com/xdp-gacl/p/4097608.html 感谢! 一.上传Tomcat服务器

  4. Encapsulating Data

    [Encapsulating Data] The synthesized methods follow specific naming conventions: The method used to ...

  5. jQuery Callback 函数

    @(编程) Callback 函数在当前动画 100% 完成之后执行. jQuery 动画的问题 许多 jQuery 函数涉及动画.这些函数也许会将 speed 或 duration 作为可选参数. ...

  6. VPN 隧道协议PPTP、L2TP、IPSec和SSLVPN的区别

    最近软矿频繁地介绍了各种VPN,有免费的PacketiX.NET和Hotspot Shield,有付费的Astrill VPN,iVPN和PureVPN.在介绍这些VPN的时候,常常会说到PPTP.L ...

  7. MySQL重置密码(OSX)

    1.停止MySQL的服务 sudo /Library/StartupItems/MySQLCOM/MySQLCOM stop   2.cd /usr/local/mysql/bin ./mysqld_ ...

  8. 高分辨率 2x图像: -webkit-min-device-pixel-ratio 的常见值对照

    -webkit-min-device-pixel-ratio的常见值对照 原文地址:http://zhangyaochun.iteye.com/blog/1816582 前言: 本文来自于对 http ...

  9. MFC 构建、消亡 顺序 (一)--单文档 (SDI)

    MFC 构建.消亡 顺序 (一)--单文档 (SDI) by:http://www.cnblogs.com/vranger/ (一)SDI 生成顺序 (二)打开文档-“Open” (三)新建文档-“N ...

  10. VPS之openVPN的安装配置

    原文地址:http://www.blogjava.net/dongbule/archive/2010/11/01/336714.html 上次写的<VPS的购买和使用>中提到了openVP ...