窗体代码
Option Explicit
Private Sub chkDisable_Click()
If chkDisable = vbChecked Then
'钩子的安装与释放:
'使用API函数SetWindowsHookEx()把一个应用程序定义的钩子子程安装到钩子链表中。SetWindowsHookEx函数总是在Hook链的开头安装Hook子程。
'当指定类型的Hook监视的事件发生时,系统就调用与这个Hook关联的Hook链的开头的Hook子程。每一个Hook链中的Hook子程都决定是否把这个事件传递到下一个Hook子程。
'Hook子程传递事件到下一个Hook子程需要调用CallNextHookEx函数。
'HHOOK SetWindowsHookEx(
' int idHook, // 钩子的类型,即它处理的消息类型
' HOOKPROC lpfn, // 钩子子程的地址指针。如果dwThreadId参数为0
' // 或是一个由别的进程创建的线程的标识,
' // lpfn必须指向DLL中的钩子子程。
' // 除此以外,lpfn可以指向当前进程的一段钩子子程代码。
' // 钩子函数的入口地址,当钩子钩到任何消息后便调用这个函数。
' HINSTANCE hMod, // 应用程序实例的句柄。标识包含lpfn所指的子程的
'DLL?
' // 如果dwThreadId 标识当前进程创建的一个线程,
' // 而且子程代码位于当前进程,hMod必须为NULL。
' // 可以很简单的设定其为本应用程序的实例句柄。
' DWORD dwThreadId // 与安装的钩子子程相关联的线程的标识符。
' // 如果为0,钩子子程与所有的线程关联,即为全局钩子。
' );
'
' 函数成功则返回钩子子程的句柄,失败返回NULL。
' 以上所说的钩子子程与线程相关联是指在一钩子链表中发给该线程的消息同时发送给钩子子程,且被钩子子程先处理。
' idHook值为它处理的消息类型;lpfn值为钩子子程序的地址指针。如果dwThreadId参数为0或是一个由别的进程创建的线程的标识,
' lpfn必须指向DLL中的钩子子程。除此以外,lpfn可以指向当前进程的一段钩子子程代码。hMod值为应用程序的句柄,
' 标识包含lpfn所指的子程的DLL。如果dwThreadId标识当前进程创建的一个线程,而且子程代码位于当前进程,hMod必须为0。
' dwThreadId值为与安装的钩子子程相关联的线程的标识符,如果为0,钩子子程与所有的线程关联。钩子安装成功则返回钩子子程的句柄,失败返回0。
'当在 Visual Basic 开发环境中使用工程进行工作时,App.hInstance 属性返回 Visual Basic 实例的实例句柄。
hhkLowLevelKybd = SetWindowsHookEx(WH_KEYBOARD_LL, AddressOf LowLevelKeyboardProc, App.hInstance, 0) '加载钩子
Else
UnhookWindowsHookEx hhkLowLevelKybd
hhkLowLevelKybd = 0
End If
End Sub
Private Sub chkDisableAll_Click()
If chkDisableAll = vbChecked Then
hhkLowLevelKybd = SetWindowsHookEx(WH_KEYBOARD_LL, AddressOf LowLevelKeyboardProc, App.hInstance, 0) '加载钩子
Text1.SetFocus
Else
UnhookWindowsHookEx hhkLowLevelKybd
hhkLowLevelKybd = 0
End If
End Sub
Private Sub Command1_Click()
Unload Me
End Sub
Private Sub Form_Unload(Cancel As Integer)
If hhkLowLevelKybd <> 0 Then UnhookWindowsHookEx hhkLowLevelKybd '卸载钩子
End Sub
模块代码
Option Explicit
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal nCode As Long, ByVal wParam As Long, lParam As Any) As Long
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
Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
Private Const HC_ACTION = 0
Private Const WM_KEYDOWN = &H100
Private Const WM_KEYUP = &H101
Private Const WM_SYSKEYDOWN = &H104
Private Const WM_SYSKEYUP = &H105
Private Const VK_TAB = &H9
Private Const VK_CONTROL = &H11
Private Const VK_ESCAPE = &H1B
Public Const WH_KEYBOARD_LL = 13
Private Const LLKHF_ALTDOWN = &H20
Private Type KBDLLHOOKSTRUCT '这个是低级键盘钩子的索引值
vkCode As Long '虚拟码 (and &HFF)
scanCode As Long '扫描码
flags As Long '键按下:128 抬起:0
time As Long 'Window运行时间
dwExtraInfo As Long
End Type
Dim KBDLLHOOKSTRUCT As KBDLLHOOKSTRUCT
Public hhkLowLevelKybd As Long '安装的钩子句柄
Public Function LowLevelKeyboardProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Dim fEatKeystroke As Boolean
If (nCode = HC_ACTION) Then 'nCode值为HC_ACTION时表示WParam和LParam参数包涵了按键消息
'按下键会产生WM_KEYDOWN或WM_SYSKEYDOWN消息,然后会被放置在当前键盘聚焦的窗口所在线程的消息队列中。同样释放按键也会产生消息,这个消息将会是WM_KEYUP或者WM_SYSKEYUP。
'系统中系统按键与非系统按键是截然不同的,系统按键产生系统按键消息:WM_SYSKEYDOWN、WM_SYSKEYUP,而非系统按键产生非系统按键消息:WM_KEYDOWN与WM_KEYUP。
If Form1.chkDisableAll.Value = 1 Then LowLevelKeyboardProc = 1: Exit Function '吃掉消息
If wParam = WM_KEYDOWN Or wParam = WM_SYSKEYDOWN Or wParam = WM_KEYUP Or wParam = WM_SYSKEYUP Then
'CopyMemory的历史非常特殊,它的真名并非叫CopyMemory。看看CopyMemory的声明,它是定义在Kernel32.dll中的RtlMoveMemory这个API,
'32位C函数库中的memcpy就是这个API的封装,如MSDN文档中所言,它的功能是将从Source指针所指处开始的长度为Length的内存拷贝到Destination所指的内存处。
'它不会管我们的程序有没有读写该内存所应有的权限,一但它想读写被系统所保护的内存时,
'VOID CopyMemory(
' PVOID Destination, // pointer to address of copy destination
' CONST VOID *Source, // pointer to address of block to copy
' DWORD Length // size, in bytes, of block to copy
');
'Parameters
'Destination
'Pointer to the starting address of the copied block's destination.
'Source
'Pointer to the starting address of the block of memory to copy.
'Length
'Specifies the size, in bytes, of the block of memory to copy.
CopyMemory KBDLLHOOKSTRUCT, ByVal lParam, Len(KBDLLHOOKSTRUCT)
fEatKeystroke = _
((KBDLLHOOKSTRUCT.vkCode = VK_TAB) And ((KBDLLHOOKSTRUCT.flags And LLKHF_ALTDOWN) <> 0)) Or _
((KBDLLHOOKSTRUCT.vkCode = VK_ESCAPE) And ((KBDLLHOOKSTRUCT.flags And LLKHF_ALTDOWN) <> 0)) Or _
((KBDLLHOOKSTRUCT.flags And LLKHF_ALTDOWN) <> 0) Or _
((KBDLLHOOKSTRUCT.vkCode = VK_ESCAPE) And (GetKeyState(VK_CONTROL) <> 0)) Or _
((KBDLLHOOKSTRUCT.vkCode = 91) Or (KBDLLHOOKSTRUCT.vkCode = 92) Or (KBDLLHOOKSTRUCT.vkCode = 93))
'TAB+ALT
'Esc+ALT
'Alt+Any(Alt+F4)
'Esc+Ctrl
'左右Win 和徽标键
End If
End If
If fEatKeystroke Then
LowLevelKeyboardProc = 1 '吃掉消息
Else
LowLevelKeyboardProc = CallNextHookEx(hhkLowLevelKybd, nCode, wParam, ByVal lParam) '如果消息要被处理,则传0或安装的钩子句柄
End If
End Function