首先来说说windows 消息Hook,这个消息Hook就是我们常用的通过SetWindowsHookEx来设置一个Hook,这个函数通过将这个Hook插入到Hook链的最前端,而发送给我们已经Hook了的窗口的消息首先会被我们的Hook函数截获,也就是我们优先于窗体捕获到消息。
Windows Message Hook 可以实现全局Hook和局部Hook。局部Hook是在自身进程中创建一个Hook,可以用来捕获自身进程中的消息;而全局Hook是可以捕获操作系统下所有的指定的消息,需要借助于DLL来实现。全局钩子必须要使用DLL,DLl存放了钩子函数的代码。在操作系统中安装了全局钩子后,只要进程收到可以发出钩子的消息后,全局钩子的DLl文件会被操作系统自动或强行地加载到该进程中。可以发现设置消息钩子也是一种导入DLl的方法。
一.钩子函数:
其实钩子函数也就3个:
(1)设置钩子:SetWindowsHookEx
(2)释放钩子:UnhookWindowsHookEx
(3)继续钩子:CallNextHookEx
在线程级的钩子中经常用到 GetCurrentThreadID 函数来获取当前线程的 ID
1. SetWindowsHookEx
HHOOK SetWindowsHookEx(
int idHook, // hook type(钩子类型,即它处理的消息类型)
HOOKPROC lpfn, // hook procedure(回调函数的地址)
HINSTANCE hMod, // handle to application instance(实例句柄,标识包含lpfn所指的子程的DLL)
DWORD dwThreadId // thread identifier(线程ID)
);
第一个参数为钩子的类型,钩子的类型一共还有14种,表示在什么时机调用钩子。下面会介绍。
第二个参数为钩子的子程,实际上就是一个回调函数的地址,当相应的事件发生时系统就会调用这个回调函数。
第三个参数为这个钩子绑定的进程的实例句柄,即包含回调函数的DLL的实例句柄,如果dwThreadId 标识当前进程创建的一个线程,而且子程代码位于当前进程,hMod必须为NULL。 可以很简单的设定其为本应用程序的实例句柄。
第四个参数为线程的ID,若为全局钩子这个参数设置为0,若是线程钩子可以使用GetCurrentThreadId来获得当前线程的ID
返回值:若调用成功,返回的是这个钩子过程的句柄;否则返回NULL
2.UnhookWindowsHookEx
钩子在使用完之后需要用UnhookWindowsHookEx()卸载,否则会造成麻烦。释放钩子比较简单,[1]()只有一个参数。函数原型如下:
UnhookWindowsHookEx( HHOOK hhk );
函数成功返回TRUE,否则返回FALSE。
3.CallNextHookEx
在钩子子程中调用得到控制权的钩子函数在完成对消息的处理后,如果想要该消息继续传递,那么它必须调用另外一个 SDK中的API函数CallNextHookEx来传递它,以执行钩子链表所指的下一个钩子子程。这个函数成功时返回钩子链中下一个钩子过程的返回值, 返回值的类型依赖于钩子的类型。
LRESULT CallNextHookEx
(
HHOOK hhk;
int nCode;
WPARAM wParam;
LPARAM lParam;
);
hhk为当前钩子的句柄,由SetWindowsHookEx()函数返回。
NCode为传给钩子过程的事件代码。
wParam和lParam 分别是传给钩子子程的wParam值,其具体含义与钩子类型有关。
钩子函数也可以通过直接返回TRUE来丢弃该消息,并阻止该消息的传递。否则的话,其他安装了钩子的应用程序将不会接收到钩子的通知而且还有可能产生不正确的结果。