VB 消息钩子 详细解释
今天来学习VB的钩子:
本来是因为要做一个小软件,其中要实现的一部分是用鼠标来定位一个座标,那么也就是说本身窗体的焦点可能会离开,就不能使用form的mousedown事件了,那么,使用钩子是可以实现的。基本想法就是,用钩子获取鼠标点击消息,然后将光标所在的座标记录下来,钩子分为线程钩子和系统钩子。线程钩子只能钩取本线程的消息,而系统钩子能勾取系统中所有的消息。VB能实现的只是线程钩子。而且就算是线程钩子好像对鼠标的操作也不会成功!!
学习总是由问题引起的,可能这个问题很简单,但是我努力的去找答案一定会有收获对吗?呵呵。。
第一步:建立钩子。在我的理解,其实就是使用一个API函数,将一个回调函数的地址加入一个钩子队列中,当然可能这个队列只有一个钩子。那么当发生硬件中断或者软中断的时候,操作系统对这个消息处理的时候,就会照顾到这个钩子,选择一个应用程序的函数来处理它。vb 的钩子函数是放在一个模块中的,而且在申明的时候都是用public,即在moulde中,呵呵,不知道有没有写错。好了要想建立钩子,用的是
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
这个API 函数。很简单看看这个括号里的几个参数的意义:
Public Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA"
(ByVal idHook As Long, hook的ID了,我猜滴。(要安装的钩子类型,简单点就是你要拦截的消息类 型,是键盘呢?还是鼠标……如是键盘钩子则为:WH_KEYBOARD或者直接写常数代表的值)
ByVal lpfn As Long, 这表示一个地址: 注意:如果dwThreadId参数为0或是一个由别的进程创建的线程的标识,lpfn必须指向DLL中的钩子子程,即表示这是一个系统钩子。VB中属于线程钩子所以用
Adressof 钩子子程序名 这样的方式来呼叫
ByVal hmod As Long, 代表.DLL的hInstance,如果是Local Hook,该值可以是Null(VB中可传0进去),而如果是Remote Hook,则可以使用GetModuleHandle(".dll名称")来传入,也就是说我们在VB中它应置为0
ByVal dwThreadId As Long dwThreadId值为与安装的钩子子程相关联的线程的标识符,如果为0,钩子子程与所有的线程关联,在VB中我们置为App.ThreadId
第二步:写钩子函数,就是说当钩子钩到消息时,要运行的函数
Public Function MyKBHook(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
If nCode >= 0 Then
MsgBox "你按下了键"
End If
End Function
这个函数谁也看得懂,函数名自已起,我想用它来做键盘钩子,只要在前边的建立钩子的时候,将其中的
hook的ID赋予WH_KEYBOARD这个常量,同时把这里的函数名给lpfn就可以让这个钩子函数,变成键盘钩子函数了。
参数介绍如下:
nCode:这个参数按照钩子不同产生不同的值。
wParam,lParam 包含了拦截到的消息内容,同样它也与Hook的种类和nCode的值不同而不同。比如在键盘钩子(KeyBoard)中,wParam则是按键返回码。
第三步认识其它两个API函数:
(1)CallNextHookEx 呼叫下个钩子,将消息传递个下个钩子程序
声明:Public Declare Function CallNextHookEx Lib "user32.dll" (ByVal hHook As Long, ByVal nCode As Long, ByVal wParam As
Long, lparam As Any) As Long
参数说明:
hHook,SetWindowsHookEx的传回值
nCode,wParam,lparam只是它的三个参数而已,具体的作用并不明显。使用的时候可以直接填写这个三个形参。
为什么要有这个CallNextHookEx函数呢,其实道理很简单,我们来假设一下,如果在系统中,有两个程序:程序A与程序B,首先A安装了一个键盘钩子,他写了钩子函数,做好了一切,等着有人按下键盘他就可响应了。而这时B匆匆赶来。他也安装了一个键盘钩子,系统自然为他们排好队,很不幸的后来的B被排到了A的前边,也就是当键盘按下时,启动了B的钩子。当他处理完的钩子函数后,拍拍屁股走人了,而A只能望穿秋水了。。要想解决这样的问题,那么就需要大家一起来努力。怎么努力呢,也就是说,所有钩子函数都在后面加一个CallNextHookEx来呼叫下一个在等待这个消息的同类型钩子,当然除非,你想要让这个消息不再传递给别人,那就不用CallNextHookEx了。。。
(2)UnHookWindowsHookEx:释放一个钩子
声明:Private Declare Function UnhookWindowsHookEx Lib "user32.dll" (ByVal hHook As Long) As Long
参数说明:
hHook,欲释放的那个钩子名
释放了钩子后,系统的资源并不一定就成功释放完毕了,这个时候在用
set 钩子=nothing 可以完全释放系统资源了。
钩子像一个全程摄像机一样,它当然很占资源了,所以在不需要的时候,一定要除去。。
第四步,写一个最简单的钩子
(1)打开VB 新建一个窗休,添加一个公共模块写入
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
Public Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
Public Const WH_KEYBOARD = 2
public hHook
Public Function MyKBHook(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
If nCode >= 0 Then
MsgBox "你按下了键"
End If
End Function
(2)找开窗口代码窗口写入:
Private Sub Form_Load()
hHook = SetWindowsHookEx(WH_KEYBOARD, AddressOf MyKBHook, 0, App.ThreadID)
End Sub
Private Sub Form_Unload(Cancel As Integer)
UnhookWindowsHookEx hHook
End Sub
这个简单的钩子在退出时一定要使用窗体的右上角的叉号关闭,而不能使用VB的调试停止关闭,不然钩子仍然在噢。而且其中的Function MyKBHook可以看出是一个有返回值的函数,我们可以对把它改成:
Public Function MyKBHook(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
If nCode >= 0 Then
MsgBox "你按下了键"
if wParam=115 And(lParam And&H20000000)<>0 Then
if(lParam And &HC000000)=0 Then '是否进行ALT+F4操作
MsgBox "你按下了ALT+F4"
MyKBHook=1
exit function '退出,表明不再运行下面的CallNextHookEx函数即吃掉了消息,也称屏蔽了
else
MyKBHook=0
End If
End If
Call CallNextHookEx(hHook,nCode,wParam,lParam)
End Function
这样就比较严谨一点了,多了一个返回值,我们可以根据这个返回值来判断是否被处理,以何方式处理。同时还有CallNextHookEx,把消息传给了下个钩子。
写到这里,只能实现键盘的钩子,现将接受鼠标钩子的示例列下。
(1)模块中输入:
Public Const WM_MOUSEMOVE = &H200
Public Const WM_LBUTTONDOWN = &H201
Public Const WM_LBUTTONUP = &H202
Public Const WM_LBUTTONDBLCLK = &H203
Public Const WM_RBUTTONDOWN = &H204
Public Const WM_RBUTTONUP = &H205
Public Const WM_RBUTTONDBLCLK = &H206
Public Const WM_MBUTTONDOWN = &H207
Public Const WM_MBUTTONUP = &H208
Public Const WM_MBUTTONDBLCLK = &H209
Public Const WM_MOUSEACTIVATE = &H21
Public Const WM_MOUSEFIRST = &H200
Public Const WM_MOUSELAST = &H209
Public Const WM_MOUSEWHEEL = &H20A '以上是鼠标的各个值
Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal nCode As Long, ByVal wParam As Long, lparam As Any) As Long
Public Function HookProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lparam As Long) As Long
If nCode < 0 Then
HookProc = CallNextHookEx(hHook, nCode, wParam, lparam)
Exit Function
End If
If wParam = WM_RBUTTONDOWN Then
MsgBox "aa"
End If
End Function
(2)窗体中输入:
Private 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
Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
Private Const WH_MOUSE_LL As Long = 14
Private Sub Form_Load()
hHook = SetWindowsHookEx(WH_MOUSE_LL, AddressOf HookProc, App.hInstance, 0)
End Sub
Private Sub Form_Unload(Cancel As Integer)
Call UnhookWindowsHookEx(hHook)
End Sub
本例在鼠标右键单击时会弹出msg a
注:本文引用了一些网的流行的看法。
posted on 2011-11-12 00:40 wanghj_dz 阅读(1074) 评论(0) 编辑 收藏 举报