c#中的消息处理函数和vc中的消息处理函数区别

从vc入门编程的,相信大家都很熟悉PreTranslateMessage和WindowProc两个函数,前者是预处理windows发给控件的消息,后者是处理剩余的控件消息。对于PreTranslateMessage函数,一般来说,我们是这样处理控件消息的:


BOOL test::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->hwnd==GetSafeHwnd())
{

if(pMsg->message==WM_MOUSEMOVE)
{m_tooltip.RelayEvent(pMsg);}
}
 return CDialog::PreTranslateMessage(pMsg);
}
}

分为两层,先判断该消息是属于那个控件窗口的,再判断这个消息的类型。

对于windowproc函数,我们通常是这样处理控件消息的:
LRESULT test::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
if(message==WM_SYSCOMMAND)
if(wParam==SC_RESTORE)
wParam=SC_MAXIMIZE;

 return CDialog::WindowProc(message, wParam, lParam);
}
这个函数对控件消息的处理方法是先把消息发给当前控件,如果不处理,则发给其父窗口,如果其父窗口也不处理,则发给当前程序处理。

而在c#中,消息处理函数有所改变。对于PreProcessMessage函数:
我们必须在需要预处理消息的控件中重载这个函数,而不能仅在父窗口重载这个函数。
  public override bool PreProcessMessage(ref Message msg)
  { 
  
   if(msg.Msg==0x101)
   {
  
   
    MessageBox.Show(msg.HWnd.ToString());
   }
   

   return base.PreProcessMessage(ref msg);
  
  }
可以看到,此函数第一步不再需要判断此消息是属于那个控件的,每个控件(包括父窗口本身),它只处理属于自己的消息,不再沿用vc中的消息机制,在某个消息发送到一个类前,允许其它类试着处理它。

 对于WndProc(跟vc中的windowproc名字稍有改变)函数来说:


 protected override void WndProc(ref Message msg)
        {
          
   if(msg.Msg==0x101)
   {
  
   
    MessageBox.Show(msg.HWnd.ToString());
   }
   
            base.WndProc(ref msg);
        }

和vc中的windowproc没有什么形式上的变化,只不过实质上,c#已不再采用消息发送顺序的机制,只要当前控件没有相应消息处理入口,则消息被丢弃。


   如果我们在c#里面想再实现在listbox控件中,点右键弹出菜单,就不能再用
BOOL test::PreTranslateMessage(MSG* pMsg)
{
 if(pMsg->hwnd==GetDlgItem(IDC_listbox1)->GetSafeHwnd())
 {
switch(pMsg->message)
 {

  case WM_LBUTTONUP:
……

  }
 } 
}
那怎么办呢
其实c#中,不再和vc那样只提供少数几种事件,c#中丰富的事件,已经不再经常需要程序员特制某种事件的消息处理函数,只要在listbox控件的mousedown响应函数中,区分出左右键,然后根据情况弹出不同的菜单即可!

    但比如你要自定义一个编辑框,可是想拦截某些特定的键(如delete),这时,c#丰富的事件,就不再有用了,必须要我们先自定义一个从textbox继承下来编辑框控件,然后在其preprocessmessage函数中预处理它!

public override bool PreProcessMessage(ref Message msg)
  { 
  Keys keyCode=(Keys)(int)msg.WParam &Keys.KeyCode;
   if(msg.Msg==0x101&&keyCode==Keys.Delete)
   {
  
  ……
   }
   

   return base.PreProcessMessage(ref msg);
  
  }

剩余几点,我现在还没搞清楚:
PreProcessMessage函数能处理的消息很有限:
WM_KEYUP,WM_KEYDOWN之类的消息可以处理,可是WM_CLOSE,WM_LBUTTONDOWN等消息无法处理。但wndproc函数却可以处理它们! 

/*****************************************************************

Net平台在消息处理上的编程和Windows C++有很大的不同,Net对消息处理更加面向对象,但对于截获某些Window消息的处理并不让人很适应, 这里根据我们遇到的一些需求写了点东西供大家参考.

  有这样一个需求, 一个文本框, 用户要求只能输入数字, 不可以输入字符, 但又不愿意在保存的时候提醒, 而是直接让字符输不进来.

这时我们就要截获字符输入消息, 避免让它显示在文本框里, 看下面的代码:

public class MyTextBox:TextBox
 {
  private const int WM_CHAR=0x0102;  //定义在WinUser.h中, 位于这个目录:.../Vc7/PlatformSDK/Include

  public override bool PreProcessMessage(ref Message msg)
  {
   if(msg.Msg==WM_CHAR)  
   {
    Keys keyCode=(Keys)(int)msg.WParam & Keys.KeyCode; 
    if(keyCode<Keys.D0 || keyCode>Keys.D9)
     if(keyCode!=Keys.Back && keyCode!=Keys.Delete)
           return true;  // 这行代码可以截住输入, 从而避免显示
   }  

   return base.PreProcessMessage (ref msg);
  }

}

这里讲两个方法:PreProcessMessage 和 WndProc. 它们都是Control的虚方法, 可以被覆盖从而为我所用. 这两个方法只对于本控件有效, 与别的控件, 无论是子控件还是父控件.统统无关. Net里的消息如果当前控件不处理它, 它就被丢弃, 不会传给父控件. 它不再沿用VC的消息机制, 这点要记住.

PreProcessMessage:  Preprocesses input messages within the message loop before they are dispatched.

WndProc: Processes Windows messages.

我们可以看到, 这两个方法的分工不同, 前一个是处理那些输入消息,比如键盘上的输入键. 后一个是处理单纯的消息, 比如鼠标点击,激活等.

这里一个例子是截获双击事件:

private const int WM_LBUTTONDBLCLK=0x0203;

protected override void WndProc(ref Message m)
  {
   if(m.Msg==WM_LBUTTONDBLCLK)
   {
    System.Diagnostics.Debug.WriteLine("wndproc");
    return;
   }
   base.WndProc(ref m);
  }

在这里, 处理完事件后, 用return来截获, 如果不加return这句代码, 消息将会继续得到处理, 如果你又定义了一个双击的事件处理方法后, 这个方法将被触发:

private void textBox1_DoubleClick(object sender, System.EventArgs e)
  {
   System.Diagnostics.Debug.WriteLine("double click");
  }

Net 里的每个控件都定义了十分丰富的消息事件, 一般情况下都可以满足你的需求, 所以WndProc重写并不普遍.这一切由你来权衡, 有的人想把所有的消息处理放到一起, 用这种方式也未尝不可.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值