技术开发 频道

浅议Visual Basic.NET中HOOK的应用

  等等,还有一个变化,就是SetWindowsHookEx的参数lpfn的类型变成了HOOKPROC,那……那是什么意思。噢,wait,我再补一句声明先:
Public Delegate Function HOOKPROC(ByVal nCode As Integer,_ ByVal wParam As Integer, ByVal lParam As Integer) As Integer
  看出来什么了吗?HOOKPROC其实就是一个函数声明,但是前面有一个Delegate(委托)是什么意思?为什么在vb.net中不能用integer表示lpfn的类型了呢?我们回头看一下vb6中调用API的句子:
hnextHookproc = SetWindowsHookEx(WH_KEYBOARD,_ AddressOf MyKBHFunc, App.hInstance, 0)
  Lpfn在这里被表示为AddressOf MyKBHFunc,即说明Hook发生作用时,调用的子程是MyKBHFunc。也就是说lpfn表示的是函数或过程的地址。在vb6中用long类型就可以记录下函数或过程的地址。
 
  在vb.net中,有了一点小变化喽,AddressOf 运算符创建的是一个指向指定的子程的子程委托。当指定的子程是一个实例方法时,子程委托同时引用实例和方法,以便当调用该子程委托时,调用指定实例的指定方法。AddressOf 运算符可以用作委托构造函数的操作数,或可以用在编译器能够确定委托类型的上下文中。
 
  所以,正是由于Addressof创建的不再只是简单的函数指针了,而是子程委托!打住先,什么是委托?(^?^)
 
  解释一下:事件是对象发送的消息,以发信号通知操作的发生。操作可能是由用户交互(例如鼠标单击)引起的,也可能是由某些其他的程序逻辑触发的。引发(触发)事件的对象叫做事件发送方。捕获事件并对其作出响应的对象叫做事件接收方。在事件通讯中,事件发送方类不知道哪个对象或方法将接收到(处理)它引发的事件。所需要的是在源和接收方之间存在一个媒介(或类似指针的机制)。.NET 框架定义了一个特殊的类型(Delegate),该类型提供函数指针的功能。看,这里提到了.net框架,所以C#等VS.net中的语言都可以有这个类型喽。
 
  委托就是可用于调用其他对象方法的对象。与其他的类不同,委托类具有一个签名,并且它只能对与其签名匹配的方法进行引用。这样,委托就等效于一个类型安全函数指针或一个回调。因为它们与其他编程语言中所使用的函数指针相似。但不同于函数指针,Visual Basic.NET 委托是基于 System.Delegate 类的引用类型,它可以引用共享方法无需特定即可调用的方法和实例方法。(具体内容请自已去查阅一下MSDN或等我的后续文章再说明)
 
  回过头来总结一下,也就是说,Addressof创建的是DelegateType(委托类型)。而不是简单的子程指针了,所以它的表示法就不是地址类型的long了,而是与调用的子程相一致的委托类型表示形式。因此,我定义了一个与MyKBHFunc声明同形的委托函数HOOKPROC来表示lpfn的类型。
 
  继续,我又接着声明了一个API:
Declare Function GetCurrentThreadId Lib "kernel32"_ Alias "GetCurrentThreadId" () As Integer
  
  函数说明:本函数是用于获取当前线程一个唯一的线程标识符。返回值:当前的线程标识符。
   2. 定义的常量是:
Public hnextHookproc As Long Public Const WH_KEYBOARD = 2 '这个是表明Hook的种类是键盘Hook Public Const PM_KEY_SPACE = &H20 '空格键
  
       或者,我在程序中对上面的第二句写法改变了一下:
Public Enum HookType  WH_KEYBOARD = 2 End Enum
  
   定义成了一个枚举。其实Hook的种类真的很多,比如有:WH_CALLWNDPROC、WH_CALLWNDPROCRET、WH_CBT 、WH_DEBUG、WH_GETMESSAGE等等。所以你不妨写一个枚举,以达到一劳永逸的目的。
 
    3. 代码段
Module Module1 Public frm1 As New Form1() ‘这个的作用,最后再说  Declare Function GetCurrentThreadId Lib "kernel32"_ Alias "GetCurrentThreadId" () As Integer  Declare Function SetWindowsHookEx Lib "user32" Alias _ "SetWindowsHookExA" (ByVal idHook As Integer, ByVal lpfn As HOOKPROC, _ ByVal hmod As Integer, ByVal dwThreadId As Integer) As Integer  Declare Function UnhookWindowsHookEx Lib "user32" _ (ByVal hHook As Integer) As Integer  Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Integer, _ ByVal ncode As Integer, ByVal wParam As Integer,_ ByVal lParam As Integer) As Integer Public Delegate Function HOOKPROC(ByVal nCode As Integer,_ ByVal wParam As Integer, ByVal lParam As Integer) As Integer  Public hnexthookproc As Integer  Public Const PM_KEY_SPACE = &H20  Public Enum HookType  WH_KEYBOARD = 2 End Enum Public Sub UnHook()  ‘解Hook  If hnexthookproc <> 0 Then   UnhookWindowsHookEx(hnexthookproc)   hnexthookproc = 0  End If End Sub Public Function SetHook() ‘设置Hook  If hnexthookproc <> 0 Then   Exit Function End If hnexthookproc = SetWindowsHookEx(HookType.WH_KEYBOARD,_ AddressOf MyKeyboardProc, 0, GetCurrentThreadId())
  
  我把第三个参数设为0(即NULL),表示的是此Hook的代码在此进程中。第四个参数用了一个API去取安装Hook子程相关联的线程的标识符。(参见前面的API声明)
End Function Public Function MyKeyboardProc(ByVal nCode As Integer,_ ByVal wParam As Integer, ByVal lParam As Integer) As Integer MyKeyboardProc = 0 If nCode < 0 Then  MyKeyboardProc = CallNextHookEx(hnexthookproc, nCode, wParam, lParam)  Exit Function End If If wParam = PM_KEY_SPACE Then  MyKeyboardProc = 1  '写入你自己的代码  frm1.textbox1.text=”HOOK成功!” End If End Function Sub main()  Application.Run(frm1) End Sub End Module
  同时请在:
 
   解决方案管理器-〉windowSAPplication1.sln -〉右点鼠标 -〉属性 -〉通用属性->常规->启动对象 -〉改为Module1
 
   4.在Form1中的代码:
Private Sub Form1_Load(ByVal sender As System.Object,_ ByVal e As System.EventArgs) Handles MyBase.Load Call SetHook() End Sub Private Sub Form1_Closing(ByVal sender As Object,_ ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing Call UnHook() End Sub
0
相关文章