I'm wondering if there's any way to declare the parameter to a method in such a way that it always preserves the exact ObjPtr/Interface supplied.
I've tried every combo of As Object/IUnknown
, ByRef/ByVal
I can think of:
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
But I get this (coloured to show matching 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
Which shows that regardless of the ObjPtr of the variable in calling method t()
, the ObjPtr always matches the declared type in the sub routine. I want some way to preserve the ObjPtr.
Of course this will work:
E ObjPtr(pObj)
'...
Sub E(ByVal pObj As LongPtr)
But I want to pass around objects, not pointers for 1: ref-count safety and 2: nicer api (I am designing functions for use by people who don't know what pointers are, I want to hide that complexity)
Example
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
I want to accept a very specific interface since I need to get the right offset in memory to the VTable entry. I'm hoping this is possible because the ObjPtr function itself does exactly what I want - receives a COM Interface without coercing it into another form.