欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

WinForm中DefWndProc、WndProc与IMessageFilter的区别

程序员文章站 2023-12-21 09:26:16
一般来说,winform的消息处理机制多数时候是通过事件处理程序进行的,但当没有对应的事件时通常的做法是声明defwndproc或者wndproc或者imessagefil...

一般来说,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中DefWndProc、WndProc与IMessageFilter的区别

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

上一篇:

下一篇: