zoukankan      html  css  js  c++  java
  • VB指针操作和消息钩子

    二、VB怎么用指针
     
        要想弄明白VB怎么使用指针,就必须要弄明白两件事,第一,如何取得数组的指针,第二,如何将指针所指向的数组取出来。
     
        A、在讲解这两个问题之前,我们需要了解几个问题:
     
        1、VB的数组与C++的数组的区别
        有可能,大家现在认为VB的数组和C++的数组没有任何区别,都是内存中的一段地址而已,其实不然。
        C++中是真的数组,真的是一段地址,而且,当你的指针访问超出了数组的范围,也没人理你,只是很容易导致系统崩溃而已。
        而VB数组其实是一个结构体,在这个结构体中包含了关于这个数组的描述信息,其结构类似如下:
     
    Private Type VB数组
       数组维数
       数组大小
       真实的数组
    End Type
     
         2、Copymemory系统函数
         这个函数有点像Java中的ArrayCopy函数,就是将两段内存空间进行复制操作。它的声明是这样的:
    Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
     
      函数原型
      VOID CopyMemory(
      PVOID Destination,
      CONST VOID *Source,
      DWORD Length
      );
     
            第一个参数:目的地址指针
            第二个参数:源地址指针
            第三个参数:复制的大小
     
            请注意,在CopyMemory的VB声明中,传递的源与目的是Any类型,也就是说可以是任何类型的变量。
     
        B、如何用指针
     
        1、如何取得数组的指针
     
        请看如下程序:
        pOutputArray As Long
        outputArray() As Byte
        ReDim outputArray(100) As Byte
        pOutputArray = VarPtr(outputArray(0))
     
        说明:
        我们声明了一个Byte数组outputArray,用VarPtr函数,取出数组的指针赋给了Long型变量pOutputArray。
     
        2、如何将指针所指向的数组取出来
     
        请看如下程序:
        CopyMemory ByVal pOutputArray, ByVal pData, UBound(outputArray)
     
        说明:
        pData是一个内存块的指针,通过这句话的执行,我们得到了pData指向的内存区域中的数据到pOutputArray数组中。
     
    三、高级应用:取得函数的指针
     
        有时候,系统函数库调用中会要求有回调函数,而将回调函数以参数进行传递时,并不能传入回调函数名,而是需要将回调函数的地址传参,这时候,我们就需要得到回调函数的地址。
        在这里我只给出例子代码,有兴趣的朋友可以去研究。
     
    Public Sub RegisterWinProc(ByVal hwnd As Long)
        '传入hWnd是本窗口的句柄
        'GetWindowLong从指定窗口的结构中取得信息
        prevWndProc = GetWindowLong(hwnd, GWL_WNDPROC)
        'SetWindowLong在窗口结构中为指定的窗口设置信息
        SetWindowLong hwnd, GWL_WNDPROC, AddressOf WndProc
        DesthWnd = hwnd
    End Sub
        VB一直被认为是一个可以通过简单的方法,完成Windows界面应用程序的一个语言。对Windows系统方面的编程似乎首先想到的绝对不是VB,而大部分程序员想到的一定是VC。我们今天就介绍一种用VB截获Windows全局消息的方法。
       
        一、Windows全局消息介绍
        我不喜欢用非常晦涩的语言来介绍一个简单的事物,因此,我想在本篇文章中就用通俗的语言来解释这个概念吧。
        什么是Windows全局消息呢?
        例如:鼠标在自定义的窗口中移动的位置,我们可以通过这个Form中的相关方法获取,然而,如果鼠标并没有在自己的Form中移动又该怎么获得其位置呢?
        再例如:键盘的敲击动作,在别的地方敲击键盘,并没有在自己的Form中敲击键盘,怎么才能获得按键的具体键值呢?
        对单片机有了解的朋友都知道,鼠标和键盘的操作都是利用的是“中断”触发事件来完成的,那么当系统“中断”的时候,就会发出消息给操作系统,而这些消息就是Windows全局消息。
     
        二、钩子简介
        钩子是通过英文Hook翻译过来的,所谓的钩子就是在Windows全局消息传递到操作系统之前进行截获,经过处理后再传递给操作系统或者其他钩子的程序。
        想想看,钩子听起来像什么程序?
        对没错,黑客程序,木马程序,都是通过钩子的方法获取鼠标键盘的相应操作信息,还获取密码或其他有用信息的。
        但是,钩子其本身并不是病毒,而是提供给我们程序员一种获取操作系统动作的一个方法,这个方法有时候非常有用,可以非常方便的开发针对操作系统的优质程序。
     
        三、消息种类
     
        1、WH_CALLWNDPROC和WH_CALLWNDPROCRET
        这两种消息是发送到窗口过程的消息,系统在消息发送到接收窗口过程之前调用WH_CALLWNDPROC,并且在窗口过程处理完消息之后调用WH_CALLWNDPRO 。
     
        2、WH_CBT   
        它是激活,建立,销毁,最小化,最大化,移动,改变尺寸等窗口事件;
        完成系统指令;来自系统消息队列中的移动鼠标,键盘事件;
        设置输入焦点事件;同步系统消息队列事件。
     
        3、WH_KEYBOARD
        WM_KEYDOWN     监视     WM_KEYUP
     
        4、WH_KEYBOARD_LL
        监视输入到线程消息队列中的键盘消息
     
        5、WH_MOUSE
        监视输入到消息队列中的鼠标消息
     
        6、WH_MOUSE_LL
        监视输入到线程消息队列中的鼠标消息

        四、钩子类型
       
        1)    线程钩子:监视指定线程的事件消息。    
        2)    系统钩子:监视系统中的所有线程的事件消息。
     
        VB只能设定线程钩子,因为系统钩子会影响系统中所有的应用程序,所以钩子函数必须放在独立的动态链接库(DLL)中才能做到。
     
       五、VB建立钩子的方法步骤
     
       步骤1:挂钩
     
       挂钩是第一步,目的是1,告诉操作系统我要监听什么消息,2是告诉操作系统得到消息后调用什么回调函数。
     
       挂钩的方法:
       例如:
       Private Const WH_MOUSE_LL As Long = 14
       Private hHook As Long
       ......
       hHook = SetWindowsHookEx(WH_MOUSE_LL, AddressOf HookProc, App.hInstance, 0)
     
       第一个参数:告诉操作系统,我要挂的是一个鼠标监听钩子。
       第二个参数:告诉操作系统,我的回调函数是HookProc,AddressOf的作用是得到HookProc这个函数的地址。
     
       步骤二:回调函数的编写
     
       Public Function HookProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lparam As Long) As Long
        Dim typMHS As MSLLHOOKSTRUCT, pt As POINTAPI
        If wParam = WM_MOUSEMOVE Then
            Call CopyMemory(typMHS, ByVal lparam, LenB(typMHS))
            pt = typMHS.pt
            'If PtInRect(hRT, pt.x, pt.y) <> 0 Then
            '    HookProc = 1 '取消原本要完成的動作
            'Else
                Form1.Caption = "mouse Cursor at " + CStr(pt.x) + "," + CStr(pt.y)
                HookProc = 0 '令待完成的動作繼續完成
            'End If
        End If
       
        If wParam = WM_LBUTTONDOWN Then
           Debug.Print "l"
        End If
       
        If wParam = WM_RBUTTONDOWN Then
           Debug.Print "r"
        End If
       
        'If nCode < 0 Then
           HookProc = CallNextHookEx(hHook, nCode, wParam, lparam)
        '   Exit Function
        'End If
       
    End Function
     
        注意一:回调函数的格式
        Public Function HookProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lparam As Long) As Long
         nCode:钩子的句柄
         wParam,lParam:包含了拦截到的消息内容,同样它也与Hook的种类和nCode的值不同而不同。比如在键盘钩子(KeyBoard)中,wParam则是按键返回码。如果是鼠标事件,那么包含的鼠标的位置信息和按键信息。
     
        注意二:在回调函数结束的时候,需要增加一个CallNextHookEx把消息再传递给下一个钩子或者操作系统。
        这个也很好理解,你截获消息以后,并不是要把这个消息真的截获,而只是想进行相应处理,然后再把消息传递给下一个接棒者。
     
        步骤三:释放钩子
        在程序结束后,需要把钩子摘掉,否则,一直会监听系统的消息。
     
        Call UnhookWindowsHookEx(hHook)
     
        六、完整的VB钩子程序
     
    模块代码:
    Option Explicit
    Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
    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 Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal nCode As Long, ByVal wParam As Long, lparam As Any) As Long
    Private Const HC_ACTION = 0
    Private Const WH_MOUSE_LL As Long = 14
    Private Const WM_MOUSEMOVE = &H200
    Private Const WM_LBUTTONDOWN = &H201
    Private Const WM_LBUTTONUP = &H202
    Private Const WM_LBUTTONDBLCLK = &H203
    Private Const WM_RBUTTONDOWN = &H204
    Private Const WM_RBUTTONUP = &H205
    Private Const WM_RBUTTONDBLCLK = &H206
    Private Const WM_MBUTTONDOWN = &H207
    Private Const WM_MBUTTONUP = &H208
    Private Const WM_MBUTTONDBLCLK = &H209
    Private Const WM_MOUSEACTIVATE = &H21
    Private Const WM_MOUSEFIRST = &H200
    Private Const WM_MOUSELAST = &H209
    Private Const WM_MOUSEWHEEL = &H20A   '以上是鼠标的各个值
    Private Type POINTAPI
       x As Long
       y As Long
    End Type
    Private Type MSLLHOOKSTRUCT
        pt As POINTAPI
        mouseData As Long
        Flags As Long
        time As Long
        dwExtraInfo As Long
    End Type
    Public hHook As Long
    Public Sub EnableHook()
        If hHook = 0 Then
           hHook = SetWindowsHookEx(WH_MOUSE_LL, AddressOf HookProc, App.hInstance, 0)
        End If
    End Sub
    Public Sub FreeHook()
        If hHook <> 0 Then
           Call UnhookWindowsHookEx(hHook)
           hHook = 0
        End If
    End Sub
    Public Function HookProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lparam As Long) As Long
        Dim typMHS As MSLLHOOKSTRUCT, pt As POINTAPI
        If wParam = WM_MOUSEMOVE Then
            Call CopyMemory(typMHS, ByVal lparam, LenB(typMHS))
            pt = typMHS.pt
            Debug.Print "mouse Cursor at " + CStr(pt.x) + "," + CStr(pt.y)
        End If
       
        If wParam = WM_LBUTTONDOWN Then
           Debug.Print "l"
        End If
       
        If wParam = WM_RBUTTONDOWN Then
           Debug.Print "r"
        End If
       
        HookProc = CallNextHookEx(hHook, nCode, wParam, lparam)
     
    End Function

     
     
    窗口代码:
     
    Private Sub Form_Load()
        EnableHook
    End Sub
    Private Sub Form_Unload(Cancel As Integer)
        FreeHook
    End Sub
  • 相关阅读:
    Unix IPC之共享内存区(1)
    linux下的二进制文件的编辑和查看
    Posix 信号量
    Unix IPC之Posix信号量实现生产者消费者
    整型信号量与记录型信号量
    C++之友元
    C++之异常处理
    C++之STL(标准模板库)
    C++之继承
    C++之封装
  • 原文地址:https://www.cnblogs.com/lbnnbs/p/4782053.html
Copyright © 2011-2022 走看看