Skip to content

AddressOf 运算符 ​

一元运算符,返回其操作数的函数指针引用。

语法:

AddressOf procedurename
AddressOf instance.procedurename (twinBASIC)

procedurename
需要获取地址的 Sub、Function 或 Property 过程的名称。
instance
可选 (twinBASIC) 对象引用,其成员 procedurename 为目标。生成的指针绑定到 instance,因此通过该指针调用会在该特定对象上调用方法。

当过程名出现在参数列表中时,通常会调用该过程并传递其返回值。AddressOf 抑制调用,改为传递过程的地址。最常见的用途是在Windows API中安装回调——API随后从项目代码外部调用该过程,这个过程称为回调。

AddressOr 生成的值与 LongPtr 在位级别兼容,因此可以传递给任何需要函数指针的地方——包括使用 As Long 或 As LongPtr 类型的传统 Declare 参数。当目标类型为 Delegate 时,编译器还会检查操作数的签名是否与委托的签名匹配。

在经典VBA中,procedurename 必须是当前项目标准 Module 中的过程名称;目标参数必须为 As Long 类型;生成的指针只能由Basic外部的代码(如DLL)调用。twinBASIC解除了所有限制——参见下文twinBASIC增强功能。

WARNING

回调内部引发的错误无法传播回外部调用者——API运行在项目的错误处理链之外。在用作 AddressOf 目标的任何过程顶部放置 On Error Resume Next(或显式错误处理程序)。

twinBASIC增强功能 ​

  • 通过Basic间接回调。 持有 AddressOf 值的委托变量可以直接调用:Dim op As Operation = AddressOf Add: r = op(5, 6)。经典VBA可以在过程之间传递此类指针,但无法在Basic内部通过它们调用。参见 Delegate。
  • 类、窗体和用户控件的成员。 AddressOf 接受在类、窗体或用户控件上声明的方法。通过用对象引用限定名称来获取实例方法的指针:AddressOf myInstance.MyMethod。生成的指针记住实例——通过它调用会分派到该对象。
  • CDecl回调。 在目标过程和匹配的 Delegate(或 Declare 参数)上同时标记 CDecl,以建模 cdecl 回调。经典VBA的 AddressOf 固定使用 __stdcall。参见 API声明。
  • 无需 FARPROC 垫片。 将函数指针赋值给局部变量是直接的——Dim lpfn As LongPtr = AddressOf MyFunc——无需编写中间转发过程。

示例 ​

在Basic内部通过类型化委托调用:

vb
Private Delegate Function Operation (ByVal A As Long, ByVal B As Long) As Long

Public Function Addition(ByVal A As Long, ByVal B As Long) As Long
    Return A + B
End Function

Private Sub Demo()
    Dim op As Operation = AddressOf Addition
    Debug.Print op(5, 6)     ' 11
End Sub

在Win32 API中安装回调。EnumWindows 对每个顶层窗口调用一次 EnumProc:

vb
Public Declare PtrSafe Function EnumWindows Lib "user32" ( _
    ByVal lpEnumFunc As LongPtr, ByVal lParam As LongPtr) As Long

Public Function EnumProc(ByVal hwnd As LongPtr, ByVal lParam As LongPtr) As Long
    On Error Resume Next
    Debug.Print hwnd
    EnumProc = 1     ' Continue enumeration.
End Function

Public Sub ListTopLevelWindows()
    EnumWindows AddressOf EnumProc, 0
End Sub

通过用对象引用限定来获取实例方法的指针:

vb
Class CFoo
    Public Sub Bar()
        Debug.Print "Bar on instance"
    End Sub
End Class

Public Sub Demo()
    Dim foo1 As New CFoo
    Dim lpfn As LongPtr = AddressOf foo1.Bar
End Sub

另请参阅 ​

twinBASIC及其LOGO版权为作者"韦恩"所有