
C ++键盘钩
Windows系统是建立在事件驱动机制上的,整个系统是通过消息传递来实现的. 挂钩是Windows系统中非常重要的系统界面. 它可以拦截和处理发送到其他应用程序的消息,以完成普通应用程序难以完成的功能. 挂钩可以监视系统或进程中的各种事件消息,拦截和处理发送到目标窗口的消息. 这样,我们可以在系统中安装自定义钩子,监视系统中特定事件的发生,并完成特定功能,例如拦截键盘和鼠标输入,屏幕单词获取,日志监视等. 可以看出,使用钩子可以实现许多特殊和有用的功能. 因此,高级程序员有必要掌握钩子的编程方法.
挂钩类型
按事件分类,常见的类型如下:
键盘挂钩和低级键盘挂钩可以监视各种键盘消息;鼠标钩和低级鼠标钩可以监视各种鼠标消息; Shell挂钩可以监视各种Shell事件消息,例如启动和关闭应用程序;日志挂钩可以记录从系统消息队列中检索到的各种事件消息;窗口过程挂钩监视从系统消息队列发送到目标窗口的所有消息.
此外,还有一些特定的事件挂钩供我们使用,而不是全部列出.
以下介绍了常用的Hook类型:
1. WH_CALLWNDPROC和WH_CALLWNDPROCRET钩子
WH_CALLWNDPROC和WH_CALLWNDPROCRET挂钩允许您监视发送到窗口过程的消息. 在将消息发送到接收窗口过程之前,系统调用WH_CALLWNDPROC Hook子例程,并在窗口过程处理该消息之后调用WH_CALLWNDPROCRET Hook子例程. WH_CALLWNDPROCRET Hook将指针传递给CWPRETSTRUCT结构,然后将其传递给Hook子例程. CWPRETSTRUCT结构包含处理消息的窗口过程的返回值,以及与此消息关联的消息参数.
2. WH_CBT挂钩
在发生以下事件之前,系统将调用WH_CBT Hook子例程. 这些事件包括:
激活,创建,销毁,最小化,最大化,移动,更改大小和其他窗口事件;完成系统命令;从系统消息队列中移动鼠标和键盘事件;设置输入焦点事件;同步系统消息队列事件.
挂钩过程的返回值确定系统是允许还是阻止这些操作之一.
3. WH_DEBUG挂钩
在系统调用与系统中其他Hook关联的Hook子例程之前,系统将调用WH_DEBUG Hook子例程. 您可以使用此挂钩来决定是否允许系统调用与其他挂钩相关联的挂钩子例程.
4. WH_FOREGROUNDIDLE钩子
当应用程序的前台线程空闲时,可以使用WH_FOREGROUNDIDLE Hook来执行低优先级任务. 当应用程序的前台线程大致变为空闲时,系统将调用WH_FOREGROUNDIDLE Hook子例程.
5. WH_GETMESSAGE挂钩

应用程序使用WH_GETMESSAGE Hook监视从GetMessage或PeekMessage函数返回的消息. 您可以使用WH_GETMESSAGE Hook监视鼠标和键盘输入以及其他发送到消息队列的消息.
6. WH_JOURNALPLAYBACK挂钩
WH_JOURNALPLAYBACK挂钩使应用程序可以将消息插入系统消息队列. 您可以使用此挂钩重播使用WH_JOURNALRECORD挂钩记录的连续鼠标和键盘事件. 只要已安装WH_JOURNALPLAYBACK挂钩,正常的鼠标和键盘事件均无效. WH_JOURNALPLAYBACK Hook是全局Hook,不能像特定于线程的Hook一样使用. WH_JOURNALPLAYBACK Hook返回一个超时值,该值告诉系统在处理来自播放Hook的当前消息之前要等待多长时间(以毫秒为单位). 这使Hook可以控制实时事件的回放. WH_JOURNALPLAYBACK是系统范围的本地钩子,它们不会被注入任何笔触地址空间(估计按钮向导是使用此钩子创建的. )
7. WH_JOURNALRECORD钩子
WH_JOURNALRECORD挂钩用于监视和记录输入事件. 通常,您可以使用此挂钩来记录连续的鼠标和键盘事件,然后使用WH_JOURNALPLAYBACK挂钩来播放它们. WH_JOURNALRECORD Hook是全局Hook,不能像特定于线程的Hook一样使用. WH_JOURNALRECORD是系统范围内的本地钩子,它们不会被注入任何笔画地址空间.
8. WH_KEYBOARD钩子
在应用程序中,WH_KEYBOARD挂钩用于监视由GetMessage或PeekMessage函数返回的WM_KEYDOWN和WM_KEYUP消息. 您可以使用此挂钩来监视输入到消息队列中的键盘消息.
9. WH_KEYBOARD_LL钩子
WH_KEYBOARD_LL挂钩监视输入到线程消息队列中的键盘消息.
10. WH_MOUSE挂钩
WH_MOUSE Hook监视从GetMessage或PeekMessage函数返回的鼠标消息. 使用此挂钩可以监视输入到消息队列中的鼠标消息.
11. WH_MOUSE_LL挂钩
WH_MOUSE_LL Hook监视输入到线程消息队列中的鼠标消息.
12. WH_MSGFILTER和WH_SYSMSGFILTER钩子
WH_MSGFILTER和WH_SYSMSGFILTER挂钩允许我们监视菜单,滚动条,消息框,对话框消息,并发现用户使用ALT + TAB或ALT + ESC组合键来切换窗口. WH_MSGFILTER Hook只能监视由安装了hook子例程的应用程序创建的传递到菜单,滚动条,消息框的消息以及传递给对话框的消息. WH_SYSMSGFILTER挂钩监视所有应用程序消息. WH_MSGFILTER和WH_SYSMSGFILTER挂钩允许我们在模式循环期间过滤消息,这等效于在主消息循环中过滤消息. WH_MSGFILTER挂钩可以通过调用CallMsgFilter函数直接调用. 通过使用此功能,应用程序可以在模式循环期间使用与主消息循环中相同的代码来过滤消息.
13. WH_SHELL钩子
Shell应用程序可以使用WH_SHELL Hook接收重要的通知. 激活Shell应用程序以及创建或破坏顶层窗口时,系统将调用WH_SHELL Hook子例程.
WH_SHELL中有5种情况:

只要生成,激活或销毁了顶层的无主窗口;当任务栏需要重绘按钮时;当系统需要显示有关任务栏的程序的最小化形式时;当前键盘的布局状态更改时;当用户按Ctrl + Esc执行任务管理器(或同一级别的程序)时.
按照惯例,shell应用程序不接收WH_SHELL消息. 因此,在应用程序可以收到WH_SHELL消息之前,应用程序必须调用SystemParametersInfo函数进行注册.
以上是13种常用的钩子类型!
线程挂钩和系统挂钩线程挂钩监视指定线程的事件消息. 系统挂钩监视系统中所有线程的事件消息. 由于系统挂钩会影响系统中的所有应用程序,因此挂钩功能必须放置在单独的动态链接库(DLL)中. 这是系统挂钩和线程挂钩之间的最大区别.
一些要点需要解释:
如果针对同一事件(例如鼠标消息)同时安装了线程挂钩和系统挂钩,则系统将首先自动调用线程挂钩,然后再自动调用系统挂钩. 可以为同一事件消息安装多个挂钩进程,并且这些挂钩进程形成一个挂钩链. 当前挂钩处理结束后,挂钩信息应传递给下一个挂钩函数. 并且最近安装的钩子位于链的开头,而最早安装的钩子位于链的末尾,也就是说,后来添加的钩子首先获得控制权. 挂钩(尤其是系统挂钩)会消耗消息处理时间并降低系统性能. 仅在必要时安装挂钩,并在使用后及时卸载它们. 编写钩子程序
编写钩子程序的步骤分为三个步骤: 定义钩子函数,安装钩子和卸载钩子.
1. 定义挂钩函数
hook函数是一个特殊的回调函数. 在由挂钩监视的特定事件发生之后,系统将调用挂钩函数进行处理. 不同事件的钩子函数形式不同. 下面的示例使用鼠标钩子函数演示钩子函数的原型:
LALL回调HookProc(int nCode,WPARAM wParam,LPARAM lParam)
参数wParam和lParam包含已挂起的消息的信息,例如鼠标位置,状态,键盘键等. nCode包含有关消息本身的信息,例如是否从消息队列中将其删除.
我们首先在hook函数中实现自定义函数,然后调用函数CallNextHookEx. 挂钩信息将传递到挂钩链中的下一个挂钩函数. CallNextHookEx的原型. 如下:
LRESULT CallNextHookEx(HHOOK hhk,int nCode,WPARAM wParam,LPARAM lParam)
参数hhk是钩子句柄. 参数nCode,参数wParam和参数lParam是挂钩函数.
当然,您也可以通过直接返回TRUE来丢弃消息,这将阻止消息的传递.
2. 安装钩
程序初始化后,调用函数SetWindowsHookEx安装挂钩. 函数原型为:
HHOOK SetWindowsHookEx(int idHook,HOOKPROC lpfn,INSTANCE hMod,DWORD dwThreadId)

参数idHook表示钩子类型,它与钩子函数类型一一对应. 例如,WH_KEYBOARD表示已安装键盘挂钩,WH_MOUSE表示已安装鼠标挂钩,依此类推. 参数Lpfn是挂钩函数的地址. 参数HMod是挂钩函数所在实例的句柄. 对于线程挂钩,此参数为NULL;对于线程挂钩,此参数为NULL. 对于系统挂钩,此参数是挂钩函数所在的DLL句柄. 参数dwThreadId指定由挂钩监视的线程的线程号. 对于全局挂钩,此参数为NULL. 参数SetWindowsHookEx返回已安装钩子的句柄.
3. 卸载钩子
当不再使用挂钩时,必须及时将其卸载. 只需调用BOOL UnhookWindowsHookEx(HHOOK hhk)函数即可.
值得注意的是,线程钩子和系统钩子的钩子函数的位置是完全不同的. 线程挂钩通常位于当前线程或从当前线程派生的线程中,并且系统挂钩必须放置在独立的动态链接库中,这在实现时比较麻烦.
线程钩子的编程示例
根据上面介绍的方法,实现线程级鼠标钩子. 挂钩跟踪当前窗口中鼠标移动的位置更改信息. 并输出到窗口.
1. 在VC ++ 6.0中使用MFC APPWizard(EXE)生成不使用文档/视图结构的单个文档应用程序鼠标钩. 打开childview.cpp文件并添加全局变量:
HHOOK hHook; //鼠标钩柄
CPoint点; //鼠标位置信息
CChildView * pView; //鼠标钩子功能使用的输出窗口指针
在CChildView :: OnPaint()中添加以下代码:
CPaintDC dc(this);
char str [256];
sprintf(str,“ x =%d,y =%d”,point.x,point.y); //构造一个字符串
dc.TextOut(0,0,str); //显示字符串
2. 全局鼠标挂钩功能在childview.cpp文件中定义.
LALL回调MouseProc(int nCode,WPARAM wParam,LPARAM lParam)
{//鼠标移动消息

if(wParam == WM_MOUSEMOVE || wParam == WM_NCMOUSEMOVE)
{
point =(((MOUSEHOOKSTRUCT *)lParam)-> pt; //获取鼠标信息
pView-> Invalidate(); //重新绘制窗口
}
返回CallNextHookEx(hHook,nCode,wParam,lParam); //传输钩子信息
}
3. 将钩子安装在CChildView类的构造函数中.
CChildView :: CChildView()
{
pView = this; //获取输出窗口指针
hHook = SetWindowsHookEx(WH_MOUSE,MouseProc,0,GetCurrentThreadId());
}
(4)卸载CChildView类的析构函数中的钩子.
CChildView ::〜CChildView()
{
if(hHook)
UnhookWindowsHookEx(hHook);
}
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/bofangqi/article-302986-1.html
在别的地方我可以让着你
这种东西还用酿吗