原文链接 -> 传送门
函数功能:
SetWindowsHookEx 函数用于安装应用程序定义的钩子处理程序到钩子链表中。你可以安装钩子处理程序监控系统某些类型事件。这些事件被关联到特定的线程或所有线程在同一桌面的调用线程。
API 函数原型:
注释:_In_ 说明该参数是输入的,_opt_ 说明该参数是可选的。
HHOOK WINAPI SetWindowsHookEx( _In_ int idHook, _In_ HOOKPROC lpfn, _In_ HINSTANCE hMod, _In_ DWORD dwThreadId );
参数解析:
|
参数 |
含义 |
||||||||||||||||||||||||||||||||
|
idHook |
指定被安装的钩子处理程序的类型,此参数可以是以下值之一:
|
||||||||||||||||||||||||||||||||
|
lpfn |
1. 指向相应的钩子处理过程 |
||||||||||||||||||||||||||||||||
|
hMod |
1. 指向一个动态链接库的句柄,该动态连接库包含了参数 lpfn 所指向的钩子处理过程 |
||||||||||||||||||||||||||||||||
|
dwThreadId |
1. 指向一个与线程相关钩子处理过程的线程标识符 |
返回值:
1. 如果函数调用成功,则返回值就是该钩子处理过程的句柄;
2. 如果函数执行失败,则返回值为 NULL。
获取有关错误的更多信息,请调用 GetLastError 函数。
备注:
1. SetWindowsHookEx 函数可以用来将一个 DLL 注入另一个进程。但是一个 32 位的 DLL 不能注入一个 64 位的进程中;一个 64 位的 DLL 不能注入一个 32 位的进程。如果一个应用程序需要在其他进程使用钩子,它要求一个 32 位的应用程序调用 SetWindowsHookEx 将一个 32 位的 DLL 注入 32 位的进程,一个 64 位的应用程序调用 SetWindowsHookEx 将一个 64 位的 DLL 注入 64 位的进程。32 位和 64 位的 dll 必须有不同的名称。
2. 因为钩子运行在应用程序的上下文中,他们必须匹配应用程序的“位数”。如果一个 32 位的应用程序在 64 位 Windows 系统安装全局钩子,该 32 位钩子被注入到每个 32 位进程(通常的安全边界启用)。在一个 64 位的进程中,那些线程仍然标记为"连接"。然而,因为 32 位的应用程序必须运行钩子代码,系统执行钩子过程在连接应用程序的上下文;具体来说,叫做 SetWindowsHookEx 的线程。这意味着连接应用程序必须继续抽取消息,这也可能阻止 64 位进程的正常功能。
3. 如果一个 64 位的应用程序在 64 位 Windows 系统安装全局钩子,该 64 位钩子注入每一个 64 位的进程,而所有 32 位进程使用一个回调以连接应用程序。
4. 为了在 64 位的 Windows 安装桌面上连接所有应用程序,安装一个 32 位全局钩子和一个 64 位全局钩子,从每个适当的流程,确保在连接应用程序抽取消息以避免阻塞正常功能。如果您已经有一个 32 位全局连接的应用程序,它不需要在每个应用程序的上下文中运行,您可以不创建一个 64 位的版本钩子。
5. 如果 hMod 参数是 NULL 可能发生错误,dwThreadId 参数为 0 或指定由另一个进程创建的线程标识符。
6. 调用 CallNextHookEx 函数链到下一个钩子程序是可选的,但强烈推荐您这样做;否则,其他应用程序安装的钩子将不会接收钩通知,可能表现不正确结果。您应该调用 CallNextHookEx 函数,除非您需要绝对防止其他应用程序被通知。
7. 在终止程序之前,应用程序必须调用 UnhookWindowsHookEx 函数释放与该钩子相关系统资源。
8. 钩子的范围取决于钩子类型。一些钩子仅可以设置在全局范围;一些钩子仅可以设置一个特定的线程,见下表:
|
钩子 |
范围 |
|
WH_CALLWNDPROC |
线程或全局 |
|
WH_CALLWNDPROCRET |
线程或全局 |
|
WH_CBT |
线程或全局 |
|
WH_DEBUG |
线程或全局 |
|
WH_FOREGROUNDIDLE |
线程或全局 |
|
WH_GETMESSAGE |
线程或全局 |
|
WH_JOURNALPLAYBACK |
仅全局 |
|
WH_JOURNALRECORD |
仅全局 |
|
WH_KEYBOARD |
线程或全局 |
|
WH_KEYBOARD_LL |
仅全局 |
|
WH_MOUSE |
线程或全局 |
|
WH_MOUSE_LL |
仅全局 |
|
WH_MSGFILTER |
线程或全局 |
|
WH_SHELL |
线程或全局 |
|
WH_SYSMSGFILTER |
仅全局 |
9. 对于指定的钩子类型,线程钩子首先被调用,然后是全局钩子。安装钩子线程而不是处理钩子线程可以在线程中调用 WH_MOUSE , WH_KEYBOARD , WH_JOURNAL * ,WH_SHELL ,低优先级钩子。对于这些钩子,如果在钩子链中 32 位钩子在 64 位钩子的前面,那么 32 位和 64 位钩子被调用是可能的。
10. 全局钩子共享资,在同一桌面安装一个钩子影响到所有应用程序调用线程。所有的全局钩子函数必须在库中。全局钩子应该限于专用应用程序或应用程序调试期间作为发展援助。当库不再需要钩子时,应该移除钩子过程。
11. Windows 商店应用程序开发如果 dwThreadId 是零,因为 Windows 商店应用程序进程和安装 Windows 运行时代理进程那么窗口钩 dll 没有加载进进程内,除非他们通过 UIAccess 进程(辅助工具)安装。为下列的钩子传递通知到这些钩子的安装程序线程:
· WH_JOURNALPLAYBACK
· WH_JOURNALRECORD
· WH_KEYBOARD
· WH_KEYBOARD_LL
· WH_MOUSE
· WH_MOUSE_LL
12. 这种行为类似于钩子 DLL 目标应用程序进程不匹配,例如,当钩子 DLL 是 32 位和应用过程是 64 位。
需求:
|
Minimum supported client |
Windows 2000 专业版 [仅桌面应用程序] |
|
Minimum supported server |
Windows 2000 服务器版 [仅桌面应用程序] |
|
Header |
Winuser.h (包含于 Windows.h) |
|
Library |
User32.lib |
|
DLL |
User32.dll |
|
Unicode and ANSI names |
SetWindowsHookExW (Unicode) 和 SetWindowsHookExA (ANSI) |




