其实无论在子线程还是主线程中,设置的钩子都是一样的。但是,如果只是像在主线程中那样调用完SetWindowsHookEx函数就以为没事了,那你有可能什么也钩不到。如果你设置的是鼠标钩子,你还会看到鼠标反应迟顿。这是为什么呢?
前些日子我就遇到过这事,在网上搜了半天也没找到解决方案。无奈,自己仔细研究,找到原因了,非常简单,与大家分享。
答案就是,调用完SetWindowsHookEx后,子线程中要启动消息泵,不能Sleep在那里,也不能因为等待事件而阻塞在任何地方。把下面的代码加到你的子线程中,你的钩子就可以起作用了:
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
这是为什么呢?事实上这和Windows的消息驱动机制有关。Windows中几乎所有的线程、进程间通信都是使用“消息”来实现的。使用消息通知而不是直接调用你提供的函数代码,可以起到线程的隔离和保护作用,防止线程执行不安全的代码。
但这样一来,如果你不接收消息,你就不会得到任何消息。Windows事实上是把消息放到线程的消息队列中,然后线程自己使用GetMessage函数取出来,再使用DispatchMessage分发到各个响应函数中执行。如果你设置了钩子(HOOK)那么GetMessage会先调用那些钩子函数。当然不只是GetMessage, PeekMessage也可以。如果你没调用这两个函数,不只是钩不到消息,说不定你的线程连个消息队列都还没建立呢!
这也解释了鼠标反应迟顿问题。系统把消息给你的线程之后,就等你的线程中的响应结果。可是你没理会它,那它只好在每个消息后都等一会儿。这样就反应迟顿了。
那后来为什么又好了呢?估计是你的消息队列占满了,系统一看这小子太懒了,索性就不把消息给你了,也就不用等了。这样鼠标就又正常了。
更多内容可以看我的上一篇文章:谁在调用那些回调函数。
为了让更多人能搜到答案,我多写几个关键字:钩子,线程,子线程,HOOK,SetWindowsHook, SetWindowsHookEx,钩不到,不起作用,没作用,没用。
作者:苏林