Win32 Hooks

 
译文
Win32 钩子机制
在微软的 Windows 操作系统中,钩子( hook 是一种机制。该机制提供某个函数使各种事件(消息,鼠标动作,击键)到达应用程序之前被截获。在某些情况下,该机制提供的函数能够作用于各种事件,包括修改或丢弃它们。接收各种事件的函数称为过滤函数,它们依据截获的事件分类。例如,某一过滤函数可能只接收所有的键盘和鼠标事件。如果 Windows 要调用一个过滤函数, 该函数必须是安装—— 也就是附加——到某个 Windows 钩子里 (比如 ,一个键盘钩子 )。在一个钩子里附加一个或多个的过滤函数叫做设置钩子。假如一个钩子附加了一个以上的过滤函数, Windows 就为其维护一个过滤函数链。该链中元素的次序类似于堆栈结构,也就是,最近附加的函数位于链首,而最先附加的函数位于链尾。
当发生某个事件,该事件触发一个附加了一个或多个过滤函数的钩子时, Windows 调用其过滤函数链的第一个函数。这种动作称为钩子调用。例如,一个过滤函数附加在 CBT 钩子里,当发生了触发该钩子的事件,(例如,即将创建一个窗口),随即, Windows 通过调用过滤函数链的第一个函数来调用 CBT 钩子。
应用程序使用函数 SetWindowsHookEx UnhookWindowsHookEx 来维护和访问过滤函数。
钩子机制为基于 Windows 的应用程序提供强大的性能。它被用于:
处理或修改所有应用程序的对话框,消息框,滚动条,或者菜单的全部消息( WH_MSGFILTER )。
处理或修改所有系统对话框,消息框,滚动条,或者菜单的全部消息( WH_SYSMSGFILTER )。
当调用函数 GetMessage 或者 PeekMessage 时,处理或修改所有任何类型的系统消息 WH_GETMESSAGE )。
当调用函数 SendMessage 时,处理或修改所有任何类型的消息 WH_CALLWNDPROC
记录或反弹键盘或鼠标事件( WH_JOURNALRECORD, WH_JOURNALPLAYBACK )。
处理,修改,或者删除键盘事件( WH_KEYBOARD )。
处理,修改,或者丢弃鼠标事件( WH_MOUSE
响应特定的系统动作,使开发基于计算机的训练程序( CBT )成为可能 WH_CBT
防止调用其它的过滤器( WH_DEBUG
在应用程序中,钩子机制被用于:
支持菜单,对话框,以及消息框 F1 帮助键 WH_MSGFILTER
提供鼠标和击键记录以及反弹功能,这些功能往往涉及到各种宏。例如, Windows 宏记录器使用钩子机制来提供记录以及反弹泛函性 WH_JOURNALRECORD, WH_JOURNALPLAYBACK )。
监控各种消息,以确定发送到特定的窗口是哪类消息或者某个消息将产生何种动作( WH_GETMESSAGE , WH_CALLWNDPROC )。例如, Spy ,一个 Win32™ 环境下的 Windows NT™ 软件开发包( SDK )中的实用程序,使用钩子机制实现上面谈到的任务。在SDK中能够找到 Spy 的源码。
模拟鼠标或键盘输入( WH_JOURNALPLAYBACK )。钩子机制提供唯一可靠的方法来模拟这些行为。如果你试图以发送或寄送消息来模拟这些事件, Windows 内部不会更新鼠标或键盘的状态,这将导致非预期的行为。如果钩子用于反弹键盘或者鼠标事件,这些事件处理起来非常像真的键盘或鼠标事件。例如,微软 Excel 使用钩子机制实现其 SEND.KEYS 宏功能。
为运行于 Windows 环境下的应用程序提供 CBT 模式( WH_CBT )。 WH_CBT 钩子使得开发 CBT 应用程序变得更简单。
如何使用钩子:
使用钩子时,你必须了解:
如何使用 Windows 钩子函数从钩子的过滤函数链中添加或删除函数 。
附加的过滤函数将要执行什么功能。
哪种类型的钩子可用,它们能干什么,以及向过滤函数传递什么样的信息 (参数)。
Windows 钩子函数
基于 Windows 的应用程序使用函数 SetWindowsHookEx UnhookWindowsHookEx ,以及 CallNextHookEx 来管理钩子过滤函数链。在 3.1 版之前, Windows 使用函数 SetWindowsHook UnhookWindowsHook ,以及 DefHookProc 来实现钩子管理。 虽然这些函数也是在 Win32 下实现,但是它们的性能比新的( Ex )版本低。请把你的现有代码中的这些函数转换为新版本,并且在新代码中使用新函数。
下面是 SetWindowsHookEx UnhookWindowsHookEx 的描述。参考“调用过滤函数链中下一个函数”关于 CallNextHookEx 的讨论。
SetWindowsHookEx
SetWindowsHookEx 函数添加一个过滤函数到钩子中。它有四个参数:
一个整型代码,描述钩子的附加过滤函数,以及该函数的地址。这些代码在 WINUSER.H 中定义,在下文描述。
过滤函数的地址。过滤函数的输出必须包含它( 1 )在应用程序模块定义文件中的输出声明或( 2 )实时链接库( DLL )或者( 3 )使用适当的编译器标志。
包容过滤函数模块的实例句柄。在 Win32 (不像 Win16 )系统中,当安装特定线程钩子(看下文)时,该值为 NULL ,但并不都像文档说明的一定为 NULL 。当你安装某个系统范围或其它进程的子线程钩子时,必须在过滤函数出现之处使用 DLL 的实例句柄。
待设置钩子的线程标志( ID )。如果线程 ID 不为零,设置的过滤函数只能在特定线程上下文中调用。如果线程 ID 为零,设置的过滤函数就在系统范围内有效,能够被系统内任何线程的上下文中调用。应用程序或库能够使用函数 GetCurrentThreadId 来获取线程的句柄,以次钩住当前线程。
某些钩子只能在系统域内设置,一些只能在特定线程内设置,而其它的两者均可。如下表:
钩子
作用范围( Scope
WH_CALLWNDPROC
线程或系统
WH_CBT
线程或系统
WH_DEBUG
线程或系统
WH_GETMESSAGE
线程或系统
WH_JOURNALRECORD
仅限系统
WH_JOURNALPLAYBACK
仅限系统
WH_FOREGROUNDIDLE
线程或系统
WH_SHELL
线程或系统
WH_KEYBOARD
线程或系统
WH_MOUSE
线程或系统
WH_MSGFILTER
线程或系统
WH_SYSMSGFILTER
仅限系统
对于给出的钩子类型,首先调用线程钩子,然后是系统钩子。在某些前提下,使用线程钩子代替系统钩子是个好主意。对于线程钩子:不要使用高于系统范围的钩子,它不利于调用。
不要序列化钩子的所有事件。比方说,如果某个应用程序设置了一个系统范围内的键盘钩子,发往所有应用程序的键盘消息都会被该程序的过滤函数截获,极大的浪费系统的多输入队列功能性。如果它的过滤函数停止处理键盘事件,那么系统将会显式地停止用户,但用户不会真的被停止。用户往往能够使用 CTRL+ALT+DEL 组合键来注销或解决该问题,但他可能不喜欢文中的讨论。同样,用户可能没意识到能够依次利用注销 / 登陆操作来重置系统。
不要将过滤函数的实现打包到单独的 DLL 里(译者注:可能是指过滤函数的声明及定义打包到同一个 DLL )。在不同的应用程序中,所有系统范围内的钩子以及线程钩子必须驻于 DLL 中。
附加到不同进程的钩子不需要共享 DLL 中的数据。系统范围的过滤函数必须驻于 DLL 中,必须与其它进程共享所需的数据。由于数据共享不是 DLL 的缺省操作,所以必须小心实现系统范围的过滤函数。假如过滤函数错误地共享进程中的数据或者使用进程中的无效数据,那么将导致该进程崩溃。
函数 SetWindowsHookEx 返回一个指向已设置的钩子的句柄 (一个 HHOOK )。通过这个句柄,应用程序或者库在调用函数 UnhookWindowsHookEx 才能识别该钩子。如果钩子添加过滤函数失败,函数 SetWindowsHookEx 返回 NULL ,同时按照下面列出的值设置错误代码,指出函数失败的原因。
ERROR_INVALID_HOOK_FILTER: 钩子码无效。
ERROR_INVALID_FILTER_PROC: 过滤函数无效。
ERROR_HOOK_NEEDS_HMOD: 全局钩子的 hInstance 参数被设置为 NULL ,或设置钩子的线程不在应用程序中。
ERROR_GLOBAL_ONLY_HOOK: 系统专有的钩子被设置到线程中。
ERROR_INVALID_PARAMETER: 线程 ID 无效
ERROR_JOURNAL_HOOK_SET: 重复设置簿记类型的钩子。同一时间内,只能设置一个簿记记录或者簿记回放钩子。当屏幕保护程序运行时,假如某个应用程序试图设置簿记钩子,函数将设置该错误代码。
ERROR_MOD_NOT_FOUND: 全局钩子的 hInstance 参数不是库。(事实上, 该值仅仅意味着用户不能在它的模块列表中定位模块句柄。)
其它任意值:出于安全性不允许设置该钩子,或者系统内存溢出。
Windows 内部维护着过滤函数链(见下图),在该链中不依赖过滤函数而正确地存储下一个过滤函数的地址 Windows 3.1 之前版本就是这样做的)。因此, Windows 3.1 版本的钩子比以前版本更为强壮。另外,由于系统内部维护过滤函数链,使得性能极大地增强。
Windows 3.1 的过滤函数链
UnhookWindowsHookEx
调用函数 UnhookWindowsHookEx 从钩子的过滤函数链移除过滤函数。该函数接收 SetWindowsHookEx 返回的句柄作为参数,并返回一个值,指示钩子是否被删除。函数 UnhookWindowsHookEx 在这种情况下往往返回真。
过滤函数
过滤(钩子)函数是一种附加到钩子的函数。因为过滤函数是被 Windows 调用而不是应用程序,所以它们有时候类似回调函数一样被引用。为保持连贯性,本文使用过滤函数这一术语。
所有的过滤函数都必须包含以下形式:
LRESULT CALLBACK FilterFunc(nCode, wParam, lParam);
int nCode;
WORD wParam;
DWORD lParam;
所有的过滤函数都应该返回一个长整型数据( LONG )。 FilterFunc 是实际过滤函数名的占位符。
参数
过滤函数接收三个参数: ncode (钩子码), wParam ,以及 lParam 钩子码是一个整型的代码,它告知过滤函数应该知道的任何附加数据。例如,钩子码可能指出导致了钩子被调用的行为。
 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值