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