WinForm中DefWndProc、WndProc与IMessageFilter的区别
一般来说,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的区别的更多相关文章
- DefWndProc/WndProc/IMessageFilter的区别
谈到Winform的消息处理,多数时候是通过事件处理程序进行的,但当没有对应的事件时通常的做法是声明DefWndProc或者WndProc或者IMessageFilter,经常在网上看见有文章将三者并 ...
- C# Winform中WndProc 函数作用
http://blog.csdn.net/xochenlin/article/details/4328954 C# Winform中WndProc 函数作用: 主要用在拦截并处理系统消息和自定义消息 ...
- WinForm中Dispose()和Close()的区别
WinForm中Dispose()和Close()的区别 Close()会自动调用Dispose()方法,但是如果窗体是模态的,则不会调用 所以ShowDialog的时候,要用Dispose(),Sh ...
- 在Winform中播放视频等【DotNet,C#】
在项目中遇到过这样的问题,就是如何在Winform中播放视频.当时考察了几种方式,第一种是直接使用Windows Media Player组件,这种最简单:第二种是利用DirectX直接在窗体或者控件 ...
- WPF中Timer与DispatcherTimer类的区别
前几天在WPF中写了一个轨迹回放的功能,我想稍微做过类似项目的,都晓得采用一个时间控件或者时间对象作为调度器,我在这么做的时候,出现了问题,于是将程序中的Timer换成了DispatchTimer,然 ...
- 关于FastReport在winform中的使用(包含FastReport.net的安装步骤链接)
一.FastReport的简介 FastReport是功能齐全的报表控件,使开发者可以快速并高效地为·NET/VCL/COM/ActiveX应用程序添加报表支持. 二.FastReport的安装(推荐 ...
- C#在WinForm中重写ProgressBar控件(带%的显示)
废话少说,直接上码: namespace csPublish { [ToolboxItem(true)] class textProgressBar : System.Windows.Forms.Pr ...
- 在winform中,禁止combobox随着鼠标一起滑动!
在winform中,如果form上或者是控件上有一个combobox控件,当你选择这个控件,当你鼠标移动其他地方,滑动鼠标时,这时combobox的选择值就会随之鼠标一起变化,如果你不想让comboB ...
- 在Winform中屏蔽UnityWebPlayer的右键以及自带Logo解决方案整理
根据项目的需要,对已经完成的Unity三维模型以及游戏要使用Winform进行包装,也就是使用Winform做一层外壳.因此在展示Unity的时候使用到了UnityWebPlayer这个插件,对于此插 ...
随机推荐
- python 字符串,数组,元祖操作基础巩固。
由于上个星期有点忙,没时间来抽空记一些有用的东西.丢了比较久的python很多忘记的小操作我也会重新捡起来 以前最容易搞混的 str.split() #操作会生成一个数组对象.example:'lap ...
- 通过用 .NET 生成自定义窗体设计器来定制应用程序
通过用 .NET 生成自定义窗体设计器来定制应用程序 https://www.microsoft.com/china/MSDN/library/netFramework/netframework/Cu ...
- 数据结构(C语言版)---第三章栈和队列 3.4.2 队列的链式表示和实现(循环队列)
这个是循环队列的实现,至于串及数组这两章,等有空再看,下面将学习树. 源码如下: #include <stdio.h> #include <stdlib.h> #define ...
- CSS圆角,输入框提示信息,JS查找同级元素
input { /*设置边框*/ border:1px solid #95B8E7; border-radius: 5px; /*设置圆角,IE不兼容*/ height:18px } placehol ...
- LDS,LES,LFS,LGS,LSS指令
LDS,LES,LFS,LGS,LSS其指令格式都是 LDS reg16,mem32 其意义是同时给一个段寄存器和一个16位通用寄存器同时赋值 具体如下:reg16=mem32的低字, ...
- GC: CMS垃圾回收器一(英文版)
Memory Management in the Java HotSpot™ Virtual Machine Concurrent Mark-Sweep (CMS) Collector For man ...
- 【CSDN博客之星】2013年CSDN博客之星正在评选,希望大家支持,非常感谢!
首先在此感谢 MoreWindows 秒杀多线程面试题系列让我成长和学习,同时也借鉴了很多优秀观点和示例! 请各位读者可以支持MoreWindows,让更优秀的文章陪伴我们! 各位读者好, 本人博客自 ...
- C# try catch finally 执行
try { //dosomething eg: int a = 1; int b = 2; int c = a + b; if(c>2) { return; } } catch(Exceptio ...
- Javascript实现笛卡儿积算法
在根据商品属性计算SKU时,通常会对商品不同选项的不同属性进行笛卡儿积运算. 这是在NodeJs里的实现版本,目前用在生产环境. function cartesian(elements) { if ( ...
- tab栏切换的特殊效果(类似网易的登陆栏效果)
代码显示效果如上图所示: 需求说明: 在实际需求中,会遇到这样的情况:不仅是要展示选项卡的内容,而且还有可能在选项卡中需求顾客填写相关内容,而这些内容是顾客如果想了解更深层次的,就会继续填写右边的内容 ...