钩子函数解析

本文通过VB演示如何创建一个键盘低级钩子,详细解释了钩子函数的工作原理和实现过程,包括设置和卸载钩子、拦截键盘事件以及处理特定键的屏蔽。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

打开VB新建一个项目,然后创建一个窗体和一个模块,此程序已调试过,但是要注意的是在写钩子函数的过程,请在每次RUN之前进行保存,这些API程序超越了VB的编译环境,因为VB环境和这些API函数同属系统级,因此它无法管理这些API,一旦出现问题,整个VB环境会在毫无预知的情况下造成全线崩溃的局面。

窗体中的代码:窗体中的程序:
Option Explicit
Private Const WH_KEYBOARD_LL = 13&
 
Private Sub cmdExit_Click()
End
End Sub
Public Sub HookKeyboard()
KeyboardHandle = SetWindowsHookEx(WH_KEYBOARD_LL, AddressOf KeyboardCallback, _
App.hInstance, 0&)
'WH_KEYBOARD_LL:拦截类型
'AddressOf KeyboardCallback:挂接函数链的首地址
'App.hInstance:程序本身的句柄
'0,表示全局拦截,意思就是拦截所有窗口下的键盘输入
End Sub

Private Sub Form_KeyPress(KeyAscii As Integer)
If KeyAscii = 9 Then
 MsgBox "你按下了TAB键!", vbOKOnly + vbInformation, "提示"
End If
If KeyAscii = 13 Then
 MsgBox "你按下了ENTER键!", vbOKOnly + vbInformation, "提示"
End If
If KeyAscii = 97 Then
 MsgBox "你按下了a键!", vbOKOnly + vbInformation, "提示"
End If
If KeyAscii = 65 Then
 MsgBox "你按下了A键!", vbOKOnly + vbInformation, "提示"
End If
End Sub
Private Sub Form_Load()
Call HookKeyboard
End Sub
Private Sub Form_Unload(Cancel As Integer)
Call UnhookKeyboard
End Sub

模块中的代码:
Option Explicit
'通知Windows进行钩子操作并定义钩子函数
Public Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" _
(ByVal idHook As Long, ByVal lpfn As Long, _
ByVal hmod As Long, ByVal dwThreadId As Long) As Long
'idHook:拦截类型     lpfn:挂接函数链的首地址指针
'hmod:创建钩子函数实体的句柄,即程序本身的句柄
'dwThreadId:为监控代码,0表示全局监控,dwThreadId用于线程钩子VB中可以设置为App.ThreadID。

Public Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
'释放钩子
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, _
pSource As Any, ByVal cb As Long)
'将内存里的某一块数据pSource拷贝到另一个地址pDest,cb表示拷贝内容的字节大小

Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, _
ByVal nCode As Long, ByVal wParam As Long, _
ByVal lParam As Long) As Long
'挂钩函数拦截了某条消息后,由CallNextHookEx决定是否将这些消息送还给Windows系统

Private Type KBDLLHOOKSTRUCT  '键盘钩子的结构体
vkCode As Long    '虚拟键码
scanCode As Long   '扫描码
flags As Long       '功能键状态
time As Long
dwExtraInfo As Long
End Type

Public KeyboardHandle As Long   '键盘钩子函数句柄
Private Const HC_ACTION = 0
Private Const LLKHF_EXTENDED = &H1
Private Const LLKHF_INJECTED = &H10
Private Const LLKHF_ALTDOWN = &H20
Private Const LLKHF_UP = &H80
Public Const VK_A = &H41
Public Const VK_ENTER = &HD
Public Const VK_TAB = &H9
Public Const VK_CONTROL = &H11
Public Const VK_ESCAPE = &H1B
Public Const VK_DELETE = &H2E

'钩子函数的核心
Public Function KeyboardCallback(ByVal Code As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
'Code 表示拦截层次,之前我们已经说过,如果Code为0,则拦截所有窗口的键盘输入
'wParam 表示是何种Windows消息
'lParam表示某条Windows消息的具体内容的指针,它实际指向存储那个内容的内存地址

Static Hookstruct As KBDLLHOOKSTRUCT  '定义一个局部静态结构体实例
If (Code = HC_ACTION) Then   '鉴别Windows的消息来源
Call CopyMemory(Hookstruct, ByVal lParam, Len(Hookstruct))
If (IsHooked(Hookstruct)) Then   '过滤消息
KeyboardCallback = 1
Exit Function
End If
End If
KeyboardCallback = CallNextHookEx(KeyboardHandle, Code, wParam, lParam)
'将消息释放,用CallNextHookEx交还给系统
End Function
Public Function IsHooked(ByRef Hookstruct As KBDLLHOOKSTRUCT) As Boolean
'If (KeyboardHook Is Nothing) Then
If KeyboardHandle = 0 Then
IsHooked = False
Exit Function
End If
'有时候CopyMemory也会发生意想不到的事情,所以,当KeyboardHook = Nothing (无值)的情况下,退出,略过该函数,以防不可预知的错误。
If (Hookstruct.vkCode = VK_TAB) And _
CBool(Hookstruct.flags And _
LLKHF_ALTDOWN) Then      '屏蔽ALT+TAB键组合
IsHooked = True
Exit Function
End If
'以上拦截了Alt+Tab的键盘组合,并将IsHooked返回True(就是1),表示本次按键确实符合了过滤原则,应该吞吃掉。
If (Hookstruct.vkCode = VK_ENTER) Then   '屏蔽ENTER键
IsHooked = True
Exit Function
End If
If (Hookstruct.vkCode = VK_A) Then   '屏蔽A和a键
IsHooked = True
Exit Function
End If
End Function

Public Sub UnhookKeyboard()   '释放钩子函数
'If (Hooked) Then
Call UnhookWindowsHookEx(KeyboardHandle)
'End If
End Sub
 

三:程序的设计: I:设置钩子 设置钩子是通过SetWindowsHookEx ()的API函数. 原形: HHOOK SetWindowsHookEx(int idHook,HOOKPROC lpfn,HINSTANCE hMod,DWORD dwThreadId) idhook:装入钩子的类型. lpfn: 钩子进程的入口地址 hMod: 应用程序的事件句柄 dwThreadId: 装入钩子的线程标示 参数: idHook: 这个参数可以是以下值: WH_CALLWNDPROC、WH_CALLWNDPROCRET、WH_CBT、WH_DEBUG、WH_FOREGROUNDIDLE、WH_GETMESSAGE、WH_JOURNALPLAYBACK、WH_JOURNALRECORD、WH_KEYBOARD、 WH_KEYBOARD_LL、WH_MOUSE、WH_MOUSE_LL、WH_MSGFILTER、WH_SHELL、WH_SYSMSGFILTER。 对于这些参数,我不想一一加以解释,因为MSDN中有关于他们的详细注解。我只挑选其中的几个加以中文说明。 WH_KEYBOARD:一旦有键盘敲打消息(键盘的按下、键盘的弹起),在这个消息被放在应用程序的消息队列前,WINDOWS将会调用你的钩子函数钩子函数可以 改变和丢弃键盘敲打消息。 WH_MOUSE:每个鼠标消息在被放在应用程序的消息队列前,WINDOWS将会调用你的钩子函数钩子函数可以改变和丢弃鼠标消息。 WH_GETMESSAGE:每次当你的应用程序调用一个GetMessage()或者一个PeekMessage()为了去从应用程序的消息队列中要求一个消息时,WINDOWS都会调用你的钩子函数。 而钩子函数可以改变和丢弃这个消息。 II:释放钩子 钩子的释放使用的是UnhookWindowsHookEx()函数 原形:BOOL UnhookWindowsHookEx( HHOOK hhk ) UnhookWindowsHookEx()函数将释放的是钩子链中函数SetWindowsHookEx所装入的钩子进程。 hhk: 将要释放的钩子进程的句柄。 III:钩子进程 钩子进程使用函数HookProc;其实HookProc仅仅只是应用程序定义的符号。比如你可以写成KeyBoardHook.但是参数是不变的。Win32 API提供了诸如:CallWndProc、 GetMsgProc、DebugProc、CBTProc、MouseProc、KeyboardProc、MessageProc等函数,对于他们的详细讲解,可以看MSDN我在此只讲解一下KeyBoardHook的含义。 原形:LRESULT CALLBACK KeyBoardHook (int nCode, WPARAM wParam, LPARAM lParam) 说明:钩子进程是一些依附在一个钩子上的一些函数,因此钩子进程只被WINDOWS调用而不被应用程序调用,他们有时就需要作为一个回调函数(CALLBACK)。 参数说明: nCode:钩子代码,钩子进程使用钩子代码去决定是否执行。而钩子代码的值是依靠钩子的种类来定的。每种钩子种类都有他们自己一系列特性的代码。比如对于WH_KEYBOARD钩子代码的参数有:HC_ACTION,HC_NOREMOVE。HC_ACTION的意义:参数wParam 和lParam 包含了键盘敲打消息的信息,HC_NOREMOVE的意义:参数wParam 和lParam包含了 键盘敲打消息的信息,并且,键盘敲打消息一直没有从消息队列中删除。(应用程序调用PeekMessage函数,并且设置PM_NOREMOVE标志)。也就是说当nCode等于HC_ACTION时, 钩子进程必须处理消息。而为HC_NOREMOVE时,钩子进程必须传递消息给CallNextHookEx函数,而不能做进一步的处理,而且必须有CallNextHookEx函数的返回值。 wParam:键盘敲打所产生的键盘消息,键盘按键的虚拟代码。 lParam:包含了消息细节。 注意:如果钩子进程中nCode小于零,钩子进程必须返回(return) CallNextHookEx(nCode,wParam,lParam);而钩子进程中的nCode大于零,但是钩子进程并不处理消息, 作者推荐你调用CallNextHookEx并且返回该函数的返回值。否则,如果另一个应用程序也装入WH_KEYBOARD 钩子,那么该钩子将不接受钩子通知并且返回一个不正确的值。 如果钩子进程处理了消息,它可能返回一个非零值去阻止系统传递该信息到其它剩下的钩子或者windows进程。所以最好在钩子进程的最后都返回CallNextHookEx的返回
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值