VB HOOK

有关函数指针的知识
使用例子可以很好地说明函数指针的用法。首先,看一看 Win32 API 中的 EnumWindows 函数:

Declare Function EnumWindows lib "user32" _
(ByVal lpEnumFunc as Long, _
ByVal lParam as Long ) As Long

EnumWindows 是一个枚举函数,它能够列出系统中每一个打开的窗口的句柄。EnumWindows 的工作方式是重复地调用传递给它的第一个参数(lpEnumFunc,函数指针)。每当 EnumWindows 调用函数,EnumWindows 都传递一个打开窗口的句柄。

在代码中调用 EnumWindows 时,可以将一个自定义函数作为第一个参数传递给它,用来处理一系列的值。例如,可以编写一个函数将所有的值添加到一个列表框中,将 hWnd 值转换为窗口的名字,以及其它任何操作!

为了表明传递的参数是一个自定义函数,在函数名称的前面要加上 AddressOf 关键字。第二个参数可以是合适的任何值。例如,如果要把 MyProc 作为函数参数,可以按下面的方式调用 EnumWindows:

x = EnumWindows(AddressOf MyProc, 5)

在调用过程时指定的自定义函数被称为回调函数。回调函数(通常简称为“回调”)能够对过程提供的数据执行指定的操作。

回调函数的参数集必须具有规定的形式,这是由使用回调函数的 API 决定的。关于需要什么参数,如何调用它们,请参阅 API 文档。

使用 AddressOf 关键字
如果代码要调用 Visual Basic 5.0 的函数指针,则必须将该代码放到标准的 .BAS 模块中,不可以将其放到类模块中,也不能将其附加到窗体上。在使用 AddressOf 关键字声明函数时,必须注意下列事项:

AddressOf 只能紧接在是参数列表中的参数前;该参数可以是自定义的过程、函数或者属性的名字。


写在 AddressOf 后面的过程、函数、属性必须与有关的声明和过程在同一个工程中。


AddressOf 只能用于自定义的过程、函数和属性,不能将其用于 Declare 语句声明的外部函数,也不能将其用于类型库中的函数。


在声明的 Sub、Function 或自定义的类型定义中,可以将函数指针传递到 As Any 或 As Long 类型的参数。
注意   可创建用 Visual C++ (或类似的工具)编译的 DLL 中的回调函数原型。要使用 AddressOf 时,原型必须使用 __stdcall 调用约定。不能将缺省调用约定与 AddressOf 并用

在变量中存储函数指针
在某些情况下,在将函数指针传递到 DLL 之前需要将其存储在一个中间变量中。如果需要将函数指针从一个 Visual Basic 传递到另一个,这种做法是很有用的。例如,在调用 RegisterClass 之类的函数时就需要用结构 (WndClass) 的成员来传递函数指针。

要将一个函数指针赋予结构中的一个成员,需要编写一个包装函数(wrapper)。例如,下面创建的 FnPtrToLong 就是一个包装函数,使用它可以将函数指针放入任何结构中:

Function FnPtrToLong (ByVal lngFnPtr As Long) As Long
   FnPtrToLong = lngFnPtr
End Function

要使用该函数,首先需要声明类型,然后再调用 FnPtrToLong。AddressOf 加上回调函数的名字作为函数的参数。

Dim mt as MyType
mt.MyPtr = FnPtrToLong(AddressOf MyCallBackFunction)

子类派生
利用子类派生技术,可以截取发送到控件或窗体的消息。通过截取这些消息,可以编写自己的代码来改变或者扩展对象的行为。类的派生技术比较复杂,对它的全面讨论将超出本书的范围。下例只能提供该技术的大致轮廓。

重点   当 Visual Basic 处于中断模式时,不允许调用 vtable 方法或 AddressOf 函数。为了保证安全,Visual Basic 仅仅将 0 返回到 AddressOf 函数的调用者。对于子类派生情况,这意味着 WindowProc 将 0 返回到 Windows。Windows 要求它的许多消息返回非 0 值,因此返回的常数 0 将导致 Windows 与 Visual Basic 之间的死锁,从而迫使进程终止。

在下例中,应用程序包括一个简单的窗体,其中只有两个命令按钮。代码的作用是截取发送到窗体的 Windows 消息,并在“立即”窗口中打印出这些消息的值。

代码的第一部分是声明部分,包括 API 函数声明,常数声明和变量声明:

Declare Function CallWindowProc Lib "user32" Alias _
"CallWindowProcA" (ByVal lpPrevWndFunc As Long, _
   ByVal hwnd As Long, ByVal Msg As Long, _
   ByVal wParam As Long, ByVal lParam As Long) As Long

Declare Function SetWindowLong Lib "user32" Alias _
"SetWindowLongA" (ByVal hwnd As Long, _
ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Public Const GWL_WNDPROC = -4
Global lpPrevWndProc As Long
Global gHW As Long

下一步,使用两个例程“钩入”消息流。第一个过程 (Hook) 调用了 SetWindowLong 函数,它使用了 GWL_WNDPROC 索引来创建窗口类的子类,窗口类是用来创建窗口的。然后它使用 AddressOf 关键字和回调函数 (WindowProc) 来截取消息并在“立即”窗口中打印消息的值。第二个过程 (Unhook) 关闭了子类,重新使原来的 Windows 过程成为回调函数。

Public Sub Hook()
   lpPrevWndProc = SetWindowLong(gHW, GWL_WNDPROC, _
   AddressOf WindowProc)
End Sub

Public Sub Unhook()
   Dim temp As Long
   temp = SetWindowLong(gHW, GWL_WNDPROC, _
   lpPrevWndProc)
End Sub

Function WindowProc(ByVal hw As Long, ByVal uMsg As _
Long, ByVal wParam As Long, ByVal lParam As Long) As _
Long
   Debug.Print "Message: "; hw, uMsg, wParam, lParam
   WindowProc = CallWindowProc(lpPrevWndProc, hw, _
   uMsg, wParam, lParam)
End Function

最后,窗体的代码设置了 hWnd 的初始值,按钮的代码仅仅调用了上面的两个例程:

Private Sub Form_Load()
   gHW = Me.hwnd
End Sub

Private Sub Command1_Click()
   Hook
End Sub

Private Sub Command2_Click()
   Unhook
End Sub

使用函数指针的局限与风险
使用函数指针是有风险的。每当调用 DLL 的时候,就失去了 Visual Basic 开发环境的稳定性,使用函数指针的危险性就更大了,因为它很容易导致应用程序失败并因此而丢失已完成的工作。在工作的时候必须经常地保存和备份工作成果。下面列出了使用函数指针的一些注意事项:

调试。在中断模式下,如果应用程序引发了回调函数,那么回调函数将被正常执行,但是断点和单步设置将被忽略。如果回调函数产生了异常,则可以捕捉到它并返回当前值。在中断模式下,如果堆栈上有回调函数,那么禁止复位。


形实转换程序。形实转换是 Windows 实现代码重定位的手段。如果在中断模式下删除回调函数,它的形实转换程序将被修改返回 0。该值通常总是正确的,但是也有意外的情况。如果在中断模式下先删除了一个回调函数,然后又再次将其加入,那么有些被调用者可能对新的函数地址一无所知。在 .exe 中不使用形实转换程序,指针被直接传递到入口点。


被传递的函数的签名有误。如果函数的参数个数与调用者期望的不一致,或者在调用某个参数时错误地使用 ByRef 或 ByVal,则应用程序可能会失败。因此,在传递函数时签名一定要正确。


将函数传递给不存在的 Windows 过程。在对某个窗口进行子类派生的时候,需要将一个函数指针作为 Windows 过程 (WindowProc) 传递给 Windows。但是,在 IDE 中运行应用程序时,在调用 WindowProc 时下一层函数可能已经被破坏了。这可能导致一般性保护错误,并使 Visual Basic 开发环境遭到破坏。


不支持“Basic 到 Basic”的函数指针。在 Visual Basic 的内部不能传递指向 Visual Basic 函数的指针。目前,只支持从 Visual Basic 到 DLL 函数的指针。


回调过程中包含错误。回调过程中的任何错误都不应回传最初调用它的外部过程,这是很重要的。可以通过在回调过程的开始加上 On Error Resume Next 语句来实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
VB HookAPI是一种在Visual Basic中使用的编程技术,用于拦截和修改Windows操作系统的API调用。它可以通过拦截API函数的调用来监视和处理特定的系统事件和消息。 通过使用VB HookAPI,我们可以实现许多有趣和有用的功能。例如,我们可以拦截键盘和鼠标的输入,以便在特定按键或鼠标动作时执行特定的操作。我们还可以拦截窗口消息,并根据需要修改或禁止其执行。此外,可以利用VB HookAPI来实现对窗口的监视和控制,包括窗口焦点的管理、窗口的移动和调整大小等。 VB HookAPI的实现通常包括以下步骤:首先,我们需要确定要拦截的API函数,并在代码中声明它们的外部函数。然后,我们需要创建一个钩子过程(Hook Procedure),它会接收系统的消息和事件,并对其进行处理。接下来,我们使用VB HookAPI函数来安装和卸载钩子,并将钩子过程链接到特定的系统事件或消息上。最后,我们可以在钩子过程中编写我们自己的代码,用于处理相应的系统事件和消息。 需要注意的是,VB HookAPI需要一定的编程经验和对Windows操作系统的了解。此外,使用钩子技术需要谨慎,因为不正确的使用可能导致系统不稳定或产生安全风险。在使用VB HookAPI时,我们需要确保只拦截需要处理的事件和消息,并在不需要时及时卸载钩子,以确保系统的稳定和安全。 总的来说,VB HookAPI是一种强大的编程技术,可以让我们在Visual Basic中实现对系统事件和消息的监视和控制。通过合理运用它,我们可以实现各种功能和效果,为我们的应用程序增添更多的灵活性和个性化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值