钩子函数被调用的过程:
当进程A一个线程准备向一个窗口发送一个消息,系统检查该线程是否被安装了钩子,如果该线程被安装了钩子且该消息与钩子要截获的消息类型一致,此消息将被截获。系统检查该钩子的钩子函数所在的DLL是否已经被映射进程A的地址空间中。如果尚未映射,系统会强制将该DLL映射到进程A的地址空间。然后获得钩子函数在进程A的虚拟地址,并调用钩子函数。我们可以在钩子函数内定义我们对该消息处理的过程。
注意:当系统把钩子函数所在的DLL映射到某个进程地址空间时,会映射整个DLL,而不仅仅是钩子函数,这也就说我们可以使用该DLL中的所有导出函数。
3:hmod参数是钩子函数所在dll的实例句柄,也是该dll在进程内的虚拟地址。如果钩子函数在当前进程中,此参数应被指定为NULL.
4:dwThreadid指定要被安装钩子的线程的ID号。如果被设为0,就会为系统内的所有GUI线程安装钩子。
5:钩子函数
钩子被安装后,如果有相应的消息发生,Windows将调用钩子函数。以下为钩子函数的原型:
LRESULT CALLBACK HookProc(int nCode,WPARAM wParam,LPARAM lParam) { //处理消息的代码。 return CallNextHookEx(hHook,nCode,wParam,lParam); } |
HookProc为钩子函数的名称。
nCode指定是否必须处理该消息。如果它为HC_ACTION,那么钩子函数就必须处理该消息。如果小于0,钩子函数就必须将该消息传递给CallNextHookEx,不对该消息进行处理,并返回CallNextHookEx的返回值。
CallNextHookEx用于把消息传递到钩子链中下一个钩子函数。
wParam和lParam的值依赖于具体的钩子类型。请参考MSDN。
卸载钩子。
BOOL UnhookWindowsHookEx(HHOOK hhk);
hhk为要卸载的钩子句柄。
下面将要实现一个例子,实现对键盘按键的监控。一旦有键盘被按下,就在主程序窗口显示一条信息指示哪一个键被按下。
程序外观: