CallNextHookEx 的第一个参数,在 MSDN 中介绍,应该是你自己设置的钩子的句柄。不过,我们也经常听到这样的说法,说那个参数其实没有用,直接传入 NULL 也可以。
老汉一直是后一种说法的认可者,原因很简单,我有好多代码就是这么写的,而且从来没有出现过问题,直到昨天。问题出在 Windows 95 上,在我设置了 WH_CBT 类型的钩子之后,MFC 的同类型的钩子函数工作就不正常了。调试了很长时间才意识到这个问题有可能是我将 NULL 传递为 CallNextHookEx 的第一个参数造成的,改正后果然正常了。不过,这个问题从来没有在 Windows NT 系列的操作系统上出现过。其实,如果你稍微深入地探查一下 Windows NT 系列的系统内部,就会发现那个参数确实没有用。
最后形成的结论是不完整的,而且也有可能不正确,仅供参考:
1、在 Windows NT 系列的操作系统上,CallNextHookEx 的第一个参数可以传递 NULL,而且工作正常。
2、在 Windows 95 系列的操作系统上,CallNextHookEx 的第一个参数在钩子的类型为 WH_GETMESSAGE/WH_CALLWNDPROC 时可以传递 NULL,而且工作正常(这一点有一个非常有力的佐证,即微软 SDK 中的 SPY 示例程序,该程序同时设置了这两种类型的钩子,并在调用 CallNextHookEx 时将第一个参数传递为 NULL,在两个系列的系统上运行均正常);在钩子的类型为 WH_CBT 时不可以传递 NULL,否则工作不正常;其他类型的钩子没有测试,但是,个人认为,由于 WH_CALLWNDPROCRET 类型的钩子与 WH_CALLWNDPROC 类型的钩子具有一定的相似性,也应该可以传递 NULL。
不过上述对 SPY 的例举有一点没有考虑,就是该程序设置的是一个全局钩子,而我测试的时候设置的是线程局部钩子。
顺便说一句,微软在设计钩子的回调例程的原型时,没有按照惯例保留出供用户使用的数据参数,是一大失败。