有没有办法为 Windows 窗体中的特定按钮挂钩鼠标事件

Posted

技术标签:

【中文标题】有没有办法为 Windows 窗体中的特定按钮挂钩鼠标事件【英文标题】:Is there a way to hook mouse events for a specific button in a windows form 【发布时间】:2011-10-14 00:17:12 【问题描述】:

我想从特定窗口内的特定按钮挂钩 WM_MOUSEDOWN 和 WM_MOUSEUP 事件。我在想 SetWindowsHookEx 会钩住我想要的消息。 FindWindowEx 将帮助我找到要从中捕获这些事件的窗口句柄。

我只是不知道如何让它给我来自特定窗口句柄的事件。或者如何确定消息应该发送到哪个句柄。

其他有这方面经验的人,我将不胜感激

编辑

也可以选择 C# 中的 Spy++ 工具的代码或 ManagedSpy 的工作副本或类似的东西。我想学习导航窗口句柄层次结构并从中挂钩窗口事件。

【问题讨论】:

您使用 WH_MOUSE,我仍在使用它,但据我了解,您无法使用 WH_MOUSE_LL 获取本地信息(您要查找的 hwnd)。根据我现在的理解,唯一的方法是创建一个 .dll 文件。 【参考方案1】:

您不能让SetWindowsHookEx 只为您提供来自单个窗口句柄的事件,但您可以自己过滤它。如果您使用WH_CALLWNDPROCWH_CALLWNDPROCRET(您需要使用它们来获取您感兴趣的鼠标消息),则CallWndProc 和CallWndRetProc 的lParam 值是一个包含窗口句柄的结构处理消息的控件。

因此,在您的SetWindowsHookEx 回调中,您只需检查该消息是否适用于您正在过滤的窗口。

例如:

static HWND s_hWndButton;
.....
SetWindowsHookEx(WH_CALLWNDPROC, ButtonHookProc, ....);
.....
LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam) 
    if (nCode >= 0) 
        CWPSTRUCT* cp = (CWPSTRUCT*)lParam;
        if (cp->hWnd == s_hWndButton) 
            if (cp->Msg == WM_MOUSEUP || cp->Msg == WM_MOUSEDOWN) 
                // Your logic goes here
            
        
    

    Return CallNextHookEx(NULL, nCode, wParam, lParam);

几乎相同的逻辑适用于WH_CALLWNDPROCRET

【讨论】:

lparam 总是 CWPSTRUCT 吗? 仅适用于 WH_CALLWNDPROC 挂钩,是的。 WH_CALLWNDPROCRET 挂钩使用 CWPRETSTRUCT 代替。【参考方案2】:

SetWindowsHookEx 可用于挂钩特定线程或所有线程。您不能钩住特定的手柄。您可以获取 windows 窗体应用程序的特定线程或所有线程并挂钩它们,但这并不能解决您的问题,这只是性能考虑。

MouseProc 的回调中,您可以使用wParam 过滤事件WM_LBUTTONDOWNWM_LBUTTONUP

您可以从lParam获取此鼠标事件所指向的窗口的句柄

MOUSEHOOKSTRUCT * pMouseHookStruct = (MOUSEHOOKSTRUCT *) lParam;
HWMD hWnd = pMouseHookStruct->hwnd;

hwnd你可以得到窗口的所有细节,你可以检查它是否是同一个窗体窗口。

如果您只想要特定按钮的鼠标事件,您可以从鼠标点击点获取 UI 对象详细信息并相应地过滤事件(使用 UIAutomation

CoCreateInstance(__uuidof(CUIAutomation), NULL, CLSCTX_INPROC_SERVER, __uuidof(IUIAutomation), (void**)&pAutomation);

pAutomation->ElementFromPoint(*pPoint, &pIUIAutomationElement);

您可以从IUIAutomationElement 获取button namerect coordinateshot keys

【讨论】:

所以现在你的每个答案都有竞争结构......这些结构相同吗? @VolureDarkAngel:这是两种不同的方法,一种是使用 WH_MOUSE 钩子捕获所有鼠标事件,另一种是捕获所有进入窗口的 Windows 消息事件 你知道获得更多关于低级挂钩的信息的好地方吗?最佳实践和方法之类的?

以上是关于有没有办法为 Windows 窗体中的特定按钮挂钩鼠标事件的主要内容,如果未能解决你的问题,请参考以下文章

在 C#/Windows 窗体中检测应用程序启动时的 shift 键

在表单中移动对象[重复]

如何对 SVN 中的特定文件夹使用预提交挂钩(Windows 批处理文件)?

如何在 Windows 窗体 C# 中单击按钮通过 DataGridView 更新数据库中的布尔字段

使用功能组件/挂钩从 React 中的数组中删除特定项目

如何获取特定类型(按钮/文本框)的Windows窗体表单的所有子控件?