我想知道是否有任何方法可以向方法声明参数,使其始终保留所提供的精确ObjPtr/Interface。
我已经尝试了我能想到的As Object/IUnknown
、ByRef/ByVal
的每一种组合:
Option Explicit
Sub t()
Dim obj As New Class1
Debug.Print "--- Default Interface ---"; ObjPtr(obj) 'check objptr before...
A obj: B obj: C obj: D obj
Debug.Print "--- Default Interface ---"; ObjPtr(obj) '... and after to make sure it wasn't modified by calling the methods
Dim asObject As Object
Set asObject = obj
Debug.Print "------- As Object -------"; ObjPtr(asObject)
A obj: B obj: C obj: D obj
Debug.Print "------- As Object -------"; ObjPtr(asObject)
Dim asUnk As IUnknown
Set asUnk = obj
Debug.Print "-------- As Unk ---------"; ObjPtr(asUnk)
A obj: B obj: C obj: D obj
Debug.Print "-------- As Unk ---------"; ObjPtr(asUnk)
End Sub
Sub A(ByVal obj As IUnknown)
Debug.Print "ByVal IUnk", ObjPtr(obj)
End Sub
Sub B(ByVal obj As Object)
Debug.Print "ByVal Object", ObjPtr(obj)
End Sub
Sub C(ByRef obj As IUnknown)
Debug.Print "ByRef IUnk", ObjPtr(obj)
End Sub
Sub D(ByRef obj As Object)
Debug.Print "ByRef Object", ObjPtr(obj)
End Sub
但我得到了这个(彩色显示匹配的ObjPtrs(:
--- Default Interface --- 1446521360 🟥
ByVal IUnk 1446521388 🔵
ByVal Object 1446521360 🟥
ByRef IUnk 1446521388 🔵
ByRef Object 1446521360 🟥
--- Default Interface --- 1446521360 🟥
------- As Object ------- 1446521360 🟥
ByVal IUnk 1446521388 🔵
ByVal Object 1446521360 🟥
ByRef IUnk 1446521388 🔵
ByRef Object 1446521360 🟥
------- As Object ------- 1446521360 🟥
-------- As Unk --------- 1446521388 🔵
ByVal IUnk 1446521388 🔵
ByVal Object 1446521360 🟥
ByRef IUnk 1446521388 🔵
ByRef Object 1446521360 🟥
-------- As Unk --------- 1446521388 🔵
这表明,无论调用方法t()
中变量的ObjPtr是什么,ObjPtr总是与子程序中声明的类型匹配。我想要一些方法来保存ObjPtr。
这当然会起作用:
E ObjPtr(pObj)
'...
Sub E(ByVal pObj As LongPtr)
但我想传递对象,而不是用于1:ref计数安全性和2:betterapi的指针(我正在为不知道指针是什么的人设计函数,我想隐藏这种复杂性(
示例
Public Function CallCOMObjectVTableEntry( _
??? COMInterface As ???, _
ByVal VTableByteOffset As LongPtr, _
ByVal FunctionReturnType As CALLRETURNTUYPE_ENUM, _
ParamArray FunctionParameters() As Variant _
) As Variant
Dim vParams() As Variant
'@Ignore DefaultMemberRequired: apparently not since this code works fine
vParams() = FunctionParameters() ' copy passed parameters, if any
LetSet(CallCOMObjectVTableEntry) = DispCallFunctionWrapper(ObjPtr(COMInterface), VTableByteOffset, FunctionReturnType, CC_STDCALL, vParams)
End Function
我想接受一个非常具体的接口,因为我需要在内存中获得VTable条目的正确偏移量。我希望这是可能的,因为ObjPtr函数本身正是我想要的——接收COM接口而不将其强制转换为另一种形式
每当我们将从IDispatch派生的对象传递给需要类型为IUnknown的函数时,不可避免地会在后台调用IUnknown::QueryInterface
,并且由于隐式强制转换,到达函数的接口将与我们传递的接口不同。
在不使用原始指针的情况下,我能想到的绕过隐式QueryInterface的唯一方法就是将函数参数声明为Variant
。类似于:
Option Explicit
Sub Main()
Dim c As New Class1
Dim u As IUnknown: Set u = c
Debug.Print ObjPtr(c)
TestCOMOBject c
Debug.Print ObjPtr(u)
TestCOMOBject u
End Sub
Public Function TestCOMOBject(ByVal COMOBject As Variant) As Variant
If Not IsObject(COMOBject) Then
If VarType(COMOBject) <> vbDataObject Then Exit Function
End If
If COMOBject Is Nothing Then Exit Function
'
Debug.Print ObjPtr(COMOBject)
Debug.Print
End Function
我知道这并不理想,因为现在我们需要在运行时而不是编译时进行额外的检查。
您可以公开两个单独的方法,一个应为Object
,一个为IUnknown
,但无论如何都无法强制用户调用正确的方法。
所以,它要么是Variant
,要么是原始指针。