为应用程序添加消息过滤器

前几天,在一QQ群上,有一网友提问:如何得到鼠标按下时,点中的是哪个控件。(不能在每个控件的事件中添加 OnMouseDown,因为这样太麻烦,而且控件可能是动态产生的)

当时我的第一反应是:这还不简单,直接重载 Form 的 WndProc 事件就行了

        const int WM_LBUTTONDOWN = 0x0201;
        
protected override void WndProc(ref Message m)
        {
            
if (m.Msg == WM_LBUTTONDOWN)
            {
                Console.WriteLine(Control.FromHandle(m.HWnd).Name);
            }
            
base.WndProc(ref m);
        }
实际运行才发现根本不是那么回事,当我在一个 TextBox 上按下鼠标时,Form的WndProc根本不会执行。
静下来好好想想,才发现自已错在对 WndProc 的理解上, Control.WndProc接收的消息仅仅是发送给该 Control 的,已经被操作系统过滤过的,所以当鼠标点在 TextBox 上时,Form 当然收不到 WM_LBUTTONDOWN 消息.

那假如要实现该功能,要怎么办呢,经查, 用Application.AddMessageFilter 方法可实现,具体代码为:
1.先定义一个消息过滤器
    /// <summary>
    
/// 自定义的消息过滤器,必须实现 IMessageFilter 接口
    
/// </summary>
    class myFilter : IMessageFilter
    {
        
const int WM_LBUTTONDOWN = 0x0201;
        
public bool PreFilterMessage(ref Message m)
        {
            
if (m.Msg == WM_LBUTTONDOWN)
            {
                Console.WriteLine(Control.FromHandle(m.HWnd).Name);
            }
            
return false;
        }
    }
2.在Form中添加该过滤器
        private void Form1_Load(object sender, EventArgs e)
        {
            
//为窗体添加消息过滤器
            Application.AddMessageFilter(new myFilter());
        }
经过这两步后,任何消息都会先发送到 myFilter 中, 用户可处理其中自已感兴趣的消息,OK!

注:msdn 上明确注明,AddMessageFilter 会让系统性能下降,估计其低层是用 SetWindowsHook之类的API.
posted @ 2007-06-15 09:49  在天空飞翔  阅读(802)  评论(0编辑  收藏  举报