基本知识
HOOK是Windows消息处理机制的平台。应用程序可以通过设置钩子来监视指定窗口的特定消息。消息到达后,将在目标窗口对其进行处理之前对其进行处理。监视的窗口可以由其他进程创建。
有关特定的深入知识,请参阅本文Windows Hook Hook技术的全面摘要
根据钩子拦截消息的范围,可以分为
相关接口功能简介:
HHOOK SetWindowsHookEx(
int idHook, //钩子类型,如 WH_MOUSE_LL, WH_MOUSE
HOOKPROC lpfn, //拦截回调函数
HINSTANCE hmod, // dll句柄
DWORD dwThreadId // 线程Id,当为0时表示全局钩子
);
此功能用于安装挂钩。若要拦截来自其他线程的消息,则必须由dll中的回调函数来触发全局挂钩。处理不当会导致系统崩溃。不建议新手使用。推荐使用螺纹钩。
在这种需求下,我们将重点放在鼠标钩上。鼠标钩有两种类型:
在当前情况下,我们可以使用WM_MOUSE挂钩。请注意,WM_MOUSE_LL挂钩只能应用于全局挂钩类型。如果要监视特定线程,则在注入阶段将提示1429错误。该挂钩程序只能对整个错误消息进行设置。
LRESULT CALLBACK MouseProc(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
此函数定义了鼠标挂钩回调函数的接口,

LRESULT CallNextHookEx(
HHOOK hhk,
int nCode,
WPARAM wParam,
LPARAM lParam
);
此函数用于将挂钩信息传递到当前挂钩链中的下一个挂钩。
BOOL UnhookWindowsHookEx(
HHOOK hhk
);
此功能用于卸载该钩子。
总体设计
此功能的总体设计如下:

此功能的关键业务逻辑有两点:
注册鼠标钩
注册WM_MOUSE鼠标挂钩类型就足够了,这里需要注意的一点是,官方文档中WM_MOUSE类型消息的回调函数原型是:
LRESULT CALLBACK MouseProc(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);

wParam表示鼠标消息标识符,例如WM_MOUSEWHEEL,WM_MOUSEMOVE等。
lParam表示鼠标指针消息回调结构类型MOUSEHOOKSTRUCT,结构声明如下:
typedef struct tagMOUSEHOOKSTRUCT {
POINT pt;
HWND hwnd;
UINT wHitTestCode;
ULONG_PTR dwExtraInfo;
} MOUSEHOOKSTRUCT, *LPMOUSEHOOKSTRUCT, *PMOUSEHOOKSTRUCT;
根据上述结构,我们关心的是pt(基于屏幕坐标系的当前鼠标的位置坐标),并且鼠标滚轮需要滚动一定距离。搜索后,我们发现此参数有两个位置:
typedef struct tagMSLLHOOKSTRUCT {
POINT pt;
DWORD mouseData;
DWORD flags;
DWORD time;
ULONG_PTR dwExtraInfo;
} MSLLHOOKSTRUCT, *LPMSLLHOOKSTRUCT, *PMSLLHOOKSTRUCT;
截获鼠标滚轮消息时,mouseData的高字节表示鼠标滚轮距离。但是,低级挂钩需要全局挂钩,因此不适合使用。
This is an extension of the MOUSEHOOKSTRUCT structure that includes information
about wheel movement or the use of the X button.
typedef struct tagMOUSEHOOKSTRUCTEX {
DWORD mouseData;
} MOUSEHOOKSTRUCTEX, *LPMOUSEHOOKSTRUCTEX, *PMOUSEHOOKSTRUCTEX;
显然,此结构是在普通消息结构上扩展的,扩展的mouseData字段正是我们所需要的。
在拦截滚轮消息后传输消息
基于以上分析,我们现在要做的是将钩形滚轮消息转换为普通滚轮消息。
根据MSDN文档,钩轮消息的wParam是鼠标消息标识符,例如WM_MOUSE_WHEEL。钩轮消息的lParam转换如下:

MOUSEHOOKSTRUCTEX const &eventInfo = *(MOUSEHOOKSTRUCTEX*)lParam;
// eventInfo.mouseData <-- 鼠标滚轮距离
// eventInfo.pt <-- 鼠标当前坐标
可以通过GET_WHEEL_DELTA_WPARAM宏从mouseData成员中提取滚轮的滚动距离。除了正常滚轮消息WM_MOUSEWHEEL的wParam中滚轮的滚动距离之外,低字节还包括虚拟键消息。挂钩消息不包括在内,因此虚拟密钥消息也已完成。此步骤需要GetAsyncKeyState函数。
最后一步是根据鼠标的当前坐标获取当前位置所在的窗口的句柄。 Windows提供了WindowFromPoint函数来实现此功能。
到目前为止,已经介绍了基于钩子的非活动窗口实现对鼠标滚动的响应的要点。
演示参考链接
重新加载预处理消息的实现方案
在Internet上找到另一种方法。有关详细信息,请参见对鼠标滚轮的无效窗口响应
核心思想是在PreTranslateMessage中拦截当前应用程序接收到的鼠标滚轮消息,并将其直接发送到当前鼠标悬停位置下的窗口以进行处理。此解决方案非常简单,但是当它可能引起问题时,鼠标消息将发送到由非当前线程创建的窗口。可能有问题,需要更多测试。
摘要
以上两种实现思路仅供参考。
经验:在这个世界上,如果只有一种方法可以做一件事情,那会不会很无聊。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/bofangqi/article-377809-1.html
只要他不像那样耍赖坐滩
从哪里开始
更有利于我们