Get IAccessible of UserForm control without reference

Jack George

New Member
Joined
Jul 8, 2023
Messages
6
Office Version
  1. 2019
Platform
  1. Windows
I know we can get IAccessible of an object by first declaring a variable of type IAccessible and set it to the object we want the interface from, but that requires a reference to a TypeLib in VBE menu -> Tools ->References.
Wondering if we can do that without reference and with API only. Ideally we don't want to have to reference TypeLib for IUnknown either.

The following is what I've got so far (didn't get to sleep last night just for this):

Code in UserForm module with a textbox named "TextBox1" on it
VBA Code:
Option Explicit

#If Win64 Then
    Private Const PTR_SIZE As LongLong = 8
#Else
    Private Const PTR_SIZE As Long = 4
    Private Enum LongPtr
        [_]
    End Enum
#End If

Private Type GUID
    Data1 As Long
    Data2 As Integer
    Data3 As Integer
    Data4(0 To 7) As Byte
End Type

Private Declare PtrSafe Function DispCallFunc Lib "oleAut32.dll" ( _
    ByVal pvInstance As LongPtr, _
    ByVal offsetinVft As LongPtr, _
    ByVal CallConv As Long, _
    ByVal retTYP As Integer, _
    ByVal paCNT As Long, _
    ByVal paTypes As LongPtr, _
    ByVal paValues As LongPtr, _
    ByVal retVAR As LongPtr _
) As Long

Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
    Destination As Any, _
    Source As Any, _
    ByVal Length As LongPtr _
)


Private Sub UserForm_Initialize()

    Dim DispCallFuncResult As Long
    Dim result As Long
    
    'IID_IAccessible: {618736E0-3C3D-11CF-810C-00AA00389B71}
    'DEFINE_GUID(IID_IAccessible, 0x618736e0, 0x3c3d, 0x11cf, 0x81, 0x0c, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
    Dim acc_guid As GUID
    With acc_guid
        .Data1 = &H618736E0
        .Data2 = &H3C3D
        .Data3 = &H11CF
        .Data4(0) = &H81
        .Data4(1) = &HC
        .Data4(2) = &H0
        .Data4(3) = &HAA
        .Data4(4) = &H0
        .Data4(5) = &H38
        .Data4(6) = &H9B
        .Data4(7) = &H71
    End With
    
    Dim pacc As LongPtr

    Dim varTypes(0 To 1) As Integer
    varTypes(0) = 29 ' VT_USERDEFINED
    varTypes(1) = VarType(pacc)

    Dim varPointers(0 To 1) As LongPtr
    varPointers(0) = VarPtr(acc_guid.Data1)
    varPointers(1) = VarPtr(pacc)

    ' Get IAccessible of TextBox1 with call to IUnknown::QueryInterface(REFIID,void**)
    DispCallFuncResult = DispCallFunc(ObjPtr(TextBox1), 0, 4, 3, 2, VarPtr(varTypes(0)), VarPtr(varPointers(0)), VarPtr(result))

    Debug.Print result, DispCallFuncResult
    
    Dim acc As Object
    If pacc <> 0 Then
        CopyMemory acc, ByVal pacc, PTR_SIZE
    End If

    Dim racc As IAccessible ' test only. our acc should equal to racc
    Set racc = TextBox1
    Debug.Print "accValue: " & racc.accValue(0&)
    
    Debug.Assert acc Is racc
    Debug.Print acc.accValue(0&)

End Sub

WARNING: The above code will crash Excel for sure...DO NOT run it directly.

Don't know what have I done wrong, or is there any better way to get the IAccessible without "type" other than "Object".
Any help would be appreciated.

Regards
 

Excel Facts

Square and cube roots
The =SQRT(25) is a square root. For a cube root, use =125^(1/3). For a fourth root, use =625^(1/4).
Look at stdAcc ; critically the Create methods. I.E. CreateFromPoint, CreateFromHwnd, CreateFromApplication etc.

Note this class does use IUnknown from stdole. Theoretically though this is not required. Office includes IAccessible interface. Edit: Just realised it requires reference to office tlb... Additionally IAccessible is a Dual interface so derefing a pointer and setting it to an object will likely do the trick too. I.E.

VBA Code:
Dim myObj as object: set myObj = Deref(ptr)
 
Last edited:
Upvote 1
Ahhh, no I think I understand what you're trying to do now. I'd try with stdCOM to query the interface. That'll at least show you if it's possible or not.

VBA Code:
stdCOM.Create(TextBox2).unkQueryInterface("618736E0-3C3D-11CF-810C-00AA00389B71").CallVT(...)

To fully remove all TLBs is definitely a good aspiration which I applaud. Definitely sure it's doable, but will be quite mind bending :) Raw dogging COM is mind bending generally.
 
Upvote 1
I know we can get IAccessible of an object by first declaring a variable of type IAccessible and set it to the object we want the interface from, but that requires a reference to a TypeLib in VBE menu -> Tools ->References.
Wondering if we can do that without reference and with API only. Ideally we don't want to have to reference TypeLib for IUnknown either.
By default, the office library implements the IAccessible interface and the Stdole library implements the IUnknown interface (they are hidden in the vbe) . So, really, you don't need to worry about adding any references to any external typelibs when in excel/vba. They are all there already loaded in your vba project.
 
Upvote 0
Ahhh, no I think I understand what you're trying to do now. I'd try with stdCOM to query the interface. That'll at least show you if it's possible or not.

VBA Code:
stdCOM.Create(TextBox2).unkQueryInterface("618736E0-3C3D-11CF-810C-00AA00389B71").CallVT(...)

To fully remove all TLBs is definitely a good aspiration which I applaud. Definitely sure it's doable, but will be quite mind bending :) Raw dogging COM is mind bending generally.
That module looks promising, but when I use it in my project, the error goes like "Automation Error: the object has disconnected from the client."

And I don't want to have to "install" a whole 3rd party module just to get only one of its functionality. For this purpose, I'm going to learn how to use the DispCallFunc directly, and use it like an "inline function" in VBA.

Thank you for your reply and the provided link. I came across the stdCOM module months ago, but never took it seriously. But now I'll take a closer look at it to see how to make it work.
 
Upvote 0
By default, the office library implements the IAccessible interface and the Stdole library implements the IUnknown interface (they are hidden in the vbe) . So, really, you don't need to worry about adding any references to any external typelibs when in excel/vba. They are all there already loaded in your vba project.
I'm quite aware of that.

Problem is, these references can be unchecked, deliberately or not. And if the module containing the type IAccessible is dragged and dropped into another VBA project that hasn't reference these TypeLibs already, compile error "User-defined type not defined" will arise, as a "surprise."

In a word, I'm trying to develop a module to be used by others, and I don't want any of these "suprises" to happen at all (as a good first impression, if put another way).

So far, I've managed to get the IAccessible interface of TextBox object, but failed to get the accValue of that interface on the next several lines:
VBA Code:
Option Explicit

Private Type GUID
    Data1 As Long
    Data2 As Integer
    Data3 As Integer
    Data4(0 To 7) As Byte
End Type

#If VBA7 Then

    Private Declare PtrSafe Function DispCallFunc Lib "oleaut32" ( _
        ByVal pvInstance As LongPtr, _
        ByVal oVft As LongPtr, _
        ByVal cc As Long, _
        ByVal vtReturn As Integer, _
        ByVal cActuals As Long, _
        ByRef prgvt As Integer, _
        ByRef prgpvarg As LongPtr, _
        ByRef pvargResult As Variant _
    ) As Long
    
    Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
        Destination As Any, _
        Source As Any, _
        ByVal Length As LongPtr _
    )

#Else

    Private Declare PtrSafe Function DispCallFunc Lib "oleaut32" ( _
        ByVal pvInstance As Long, _
        ByVal oVft As Long, _
        ByVal cc As Long, _
        ByVal vtReturn As Integer, _
        ByVal cActuals As Long, _
        ByRef prgvt As Integer, _
        ByRef prgpvarg As Long, _
        ByRef pvargResult As Variant _
    ) As Long
    
    Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
        Destination As Any, _
        Source As Any, _
        ByVal Length As Long _
    )

#End If



Private Sub UserForm_Initialize()

    Const CC_STDCALL As Long = 4&
#If Win64 Then
    Const PTR_SIZE As LongLong = 8^
    Const oVft_IUnknown_QueryInterface As LongLong = 0^
    Const oVft_IAccessible_accValue As LongLong = 88^
    Dim pacc As LongPtr
    Dim varPointers(0 To 1) As LongPtr
    Dim vp(0 To 0) As LongPtr
#Else
    Const PTR_SIZE As Long = 4&
    Const oVft_IUnknown_QueryInterface As Long = 0&
    Const oVft_IAccessible_accValue As Long = 44&
    Dim pacc As Long
    Dim varPointers(0 To 1) As Long
    Dim vp(0 To 0) As Long
#End If

    'IID_IAccessible: {618736E0-3C3D-11CF-810C-00AA00389B71}
    Dim acc_guid As GUID
    With acc_guid
        .Data1 = &H618736E0
        .Data2 = &H3C3D
        .Data3 = &H11CF
        .Data4(0) = &H81
        .Data4(1) = &HC
        .Data4(2) = &H0
        .Data4(3) = &HAA
        .Data4(4) = &H0
        .Data4(5) = &H38
        .Data4(6) = &H9B
        .Data4(7) = &H71
    End With

    Dim vGUID As Variant
    Dim vpacc As Variant
    vGUID = CVar(VarPtr(acc_guid.Data1))
    vpacc = CVar(VarPtr(pacc))

    Dim varTypes(0 To 1) As Integer
    varTypes(0) = VarType(vGUID)
    varTypes(1) = VarType(vpacc)

    varPointers(0) = VarPtr(vGUID)
    varPointers(1) = VarPtr(vpacc)


    Dim DispCallFuncResult As Long
    Dim result As Variant

    ' Get IAccessible of TextBox1 with call to IUnknown::QueryInterface(REFIID,void**)
    DispCallFuncResult = DispCallFunc(ObjPtr(TextBox1), oVft_IUnknown_QueryInterface, _
                            CC_STDCALL, vbLong, 2, varTypes(0), varPointers(0), result)

    Debug.Assert DispCallFuncResult = 0 And result = 0
    
    Dim acc As Object
    If pacc <> 0 Then
        CopyMemory acc, pacc, PTR_SIZE
    End If

    Dim racc As IAccessible
    Set racc = TextBox1
    Debug.Print "TextBoxText: " & racc.accValue
    Debug.Assert acc Is racc
    '
    ' so far so good on Windows 10 x64
    
    
    ' and now we are going to get accValue of IAccessible of TextBox1 using DispCallFunc
    '
    Dim varChild As Variant: varChild = 0&
    vp(0) = VarPtr(varChild)
    
    Dim vt(0 To 0) As Integer
    vt(0) = VarType(varChild)
    
    Dim TextBoxText As Variant
    TextBoxText = ""

    ' Excel crash on the following line:
    DispCallFuncResult = DispCallFunc(pacc, 11 * PTR_SIZE, _
                            CC_STDCALL, vbString, 1, vt(0), vp(0), TextBoxText)
    
    Debug.Assert DispCallFuncResult = 0
    Debug.Print TextBoxText

End Sub

BTW, the above code mimics the code from the following link:
DispCallFunc - 64bit VBA post #4
In which the DispCallFunc is used directly as well.

I read so many articles on the web, tried for days only to get this function to work properly. Yet until now I still don't know the correct way to feed arguments to this monster. Feeling desperate every time Excel crashes before my face.

I need help.
 
Upvote 0
@Jack George

The DispCallFunc api is very unforgiving. You must get the arguments and their var types right or it will crash the application before your face hence making the debuging more difficult.

You made a couple of mistakes:
* The pszValue var (out parameter) that expects to receive a pointer to the BSTR string was missing.
* The vtReturn arg should be vbLong not vbString

Always consult the library header of the interfaces you want to work with.
oleacc.h

VBA Code:
HRESULT (STDMETHODCALLTYPE *get_accValue)(
        IAccessible* This,
        VARIANT varID,
        BSTR *pszValue);


Here is the working code:

Code in UserForm module with a textbox named "TextBox1" on it
VBA Code:
Option Explicit

Private Type GUID
    Data1 As Long
    Data2 As Integer
    Data3 As Integer
    Data4(0 To 7) As Byte
End Type

Private Declare PtrSafe Function DispCallFunc Lib "oleaut32" ( _
        ByVal pvInstance As LongPtr, _
        ByVal oVft As LongPtr, _
        ByVal cc As Long, _
        ByVal vtReturn As Integer, _
        ByVal cActuals As Long, _
        ByRef prgvt As Integer, _
        ByRef prgpvarg As LongPtr, _
        ByRef pvargResult As Variant _
    ) As Long '
 
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
        Destination As Any, _
        Source As Any, _
        ByVal Length As LongPtr _
)

Private Declare PtrSafe Function lstrlen Lib "kernel32" Alias "lstrlenW" ( _
        ByVal lpString As LongPtr _
) As Long


Private Sub UserForm_Click()

    #If Win64 Then
        Const PTR_SIZE As Long = 8&
    #Else
        Const PTR_SIZE As Long = 4&
    #End If

    Const CC_STDCALL As Long = 4&, S_OK = 0&
    Const oVft_IUnknown_QueryInterface As Long = 0&
    Const oVft_IUnknown_Release As Long = 2& * PTR_SIZE
    Const oVft_IAccessible_accValue As Long = 11& * PTR_SIZE
    Dim pAcc As LongPtr
    Dim varPointers(0 To 1) As LongPtr
    Dim vp(0 To 1) As LongPtr
    Dim vp2(0) As LongPtr
    Dim pszValue As LongPtr

    'IID_IAccessible: {618736E0-3C3D-11CF-810C-00AA00389B71}
    Dim acc_guid As GUID
    With acc_guid
        .Data1 = &H618736E0
        .Data2 = &H3C3D
        .Data3 = &H11CF
        .Data4(0) = &H81
        .Data4(1) = &HC
        .Data4(2) = &H0
        .Data4(3) = &HAA
        .Data4(4) = &H0
        .Data4(5) = &H38
        .Data4(6) = &H9B
        .Data4(7) = &H71
    End With

    Dim vGUID As Variant, vpacc As Variant
 
    vGUID = VarPtr(acc_guid.Data1)
    vpacc = VarPtr(pAcc)
 
    Dim varTypes(0 To 1) As Integer
    varTypes(0) = VarType(vGUID)
    varTypes(1) = VarType(vpacc)
 
    varPointers(0) = VarPtr(vGUID)
    varPointers(1) = VarPtr(vpacc)

    Dim DispCallFuncResult As Long
    Dim result As Variant

    ' Get IAccessible of TextBox1 with call to IUnknown::QueryInterface(REFIID,void**)
    DispCallFuncResult = DispCallFunc(ObjPtr(TextBox1), oVft_IUnknown_QueryInterface, CC_STDCALL, _
                                      vbLong, 2&, varTypes(0&), varPointers(0&), result)

    If DispCallFuncResult = S_OK And result = S_OK Then
 
        Dim varID As Long: varID = 0&
        Dim vchild As Variant, vAccVal As Variant
 
        vchild = VarPtr(varID)
        vAccVal = VarPtr(pszValue)
 
        Dim vt(0 To 1) As Integer
        vt(0) = VarType(vchild)
        vt(1) = VarType(vAccVal)
 
        vp(0) = VarPtr(vchild)
        vp(1) = VarPtr(vAccVal)

        'IAccessible::get_accValue
        DispCallFuncResult = DispCallFunc(pAcc, oVft_IAccessible_accValue, CC_STDCALL, _
                                          vbLong, 2&, vt(0&), vp(0&), result)
                                   
        If DispCallFuncResult = S_OK And result = S_OK Then
            Dim TextBoxText As String
            TextBoxText = GetStrFromPtrW(pszValue)
            MsgBox "TextBox1 text is:" & vbLf & vbLf & TextBoxText
        End If
 
        Dim vt2(0) As Integer
        'IUnknown::Release
        DispCallFuncResult = DispCallFunc(pAcc, oVft_IUnknown_Release, CC_STDCALL, _
                             vbLong, 0&, vt2(0&), vp2(0&), result)
    End If

End Sub

Private Function GetStrFromPtrW(ByVal lpString As LongPtr) As String
   Dim lLength As Long, sBuffer As String
   lLength = lstrlen(lpString)
   sBuffer = Space$(lLength)
   Call CopyMemory(ByVal StrPtr(sBuffer), ByVal lpString, lLength * 2&)
   GetStrFromPtrW = sBuffer
End Function

PS: Since this is just for illustrative purposes, I omitted conditional compilation code for VBA6/VBA5
 
Last edited:
Upvote 1
Solution
@Jack George

The DispCallFunc api is very unforgiving. You must get the arguments and their var types right or it will crash the application before your face hence making the debuging more difficult.

You made a couple of mistakes:
* The pszValue var (out parameter) that expects to receive a pointer to the BSTR string was missing.
* The vtReturn arg should be vbLong not vbString

Always consult the library header of the interfaces you want to work with.
oleacc.h

VBA Code:
HRESULT (STDMETHODCALLTYPE *get_accValue)(
        IAccessible* This,
        VARIANT varID,
        BSTR *pszValue);


Here is the working code:

Code in UserForm module with a textbox named "TextBox1" on it
VBA Code:
Option Explicit

Private Type GUID
    Data1 As Long
    Data2 As Integer
    Data3 As Integer
    Data4(0 To 7) As Byte
End Type

Private Declare PtrSafe Function DispCallFunc Lib "oleaut32" ( _
        ByVal pvInstance As LongPtr, _
        ByVal oVft As LongPtr, _
        ByVal cc As Long, _
        ByVal vtReturn As Integer, _
        ByVal cActuals As Long, _
        ByRef prgvt As Integer, _
        ByRef prgpvarg As LongPtr, _
        ByRef pvargResult As Variant _
    ) As Long '
 
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
        Destination As Any, _
        Source As Any, _
        ByVal Length As LongPtr _
)

Private Declare PtrSafe Function lstrlen Lib "kernel32" Alias "lstrlenW" ( _
        ByVal lpString As LongPtr _
) As Long


Private Sub UserForm_Click()

    #If Win64 Then
        Const PTR_SIZE As Long = 8&
    #Else
        Const PTR_SIZE As Long = 4&
    #End If

    Const CC_STDCALL As Long = 4&, S_OK = 0&
    Const oVft_IUnknown_QueryInterface As Long = 0&
    Const oVft_IUnknown_Release As Long = 2& * PTR_SIZE
    Const oVft_IAccessible_accValue As Long = 11& * PTR_SIZE
    Dim pAcc As LongPtr
    Dim varPointers(0 To 1) As LongPtr
    Dim vp(0 To 1) As LongPtr
    Dim vp2(0) As LongPtr
    Dim pszValue As LongPtr

    'IID_IAccessible: {618736E0-3C3D-11CF-810C-00AA00389B71}
    Dim acc_guid As GUID
    With acc_guid
        .Data1 = &H618736E0
        .Data2 = &H3C3D
        .Data3 = &H11CF
        .Data4(0) = &H81
        .Data4(1) = &HC
        .Data4(2) = &H0
        .Data4(3) = &HAA
        .Data4(4) = &H0
        .Data4(5) = &H38
        .Data4(6) = &H9B
        .Data4(7) = &H71
    End With

    Dim vGUID As Variant, vpacc As Variant
 
    vGUID = VarPtr(acc_guid.Data1)
    vpacc = VarPtr(pAcc)
 
    Dim varTypes(0 To 1) As Integer
    varTypes(0) = VarType(vGUID)
    varTypes(1) = VarType(vpacc)
 
    varPointers(0) = VarPtr(vGUID)
    varPointers(1) = VarPtr(vpacc)

    Dim DispCallFuncResult As Long
    Dim result As Variant

    ' Get IAccessible of TextBox1 with call to IUnknown::QueryInterface(REFIID,void**)
    DispCallFuncResult = DispCallFunc(ObjPtr(TextBox1), oVft_IUnknown_QueryInterface, CC_STDCALL, _
                                      vbLong, 2&, varTypes(0&), varPointers(0&), result)

    If DispCallFuncResult = S_OK And result = S_OK Then
 
        Dim varID As Long: varID = 0&
        Dim vchild As Variant, vAccVal As Variant
 
        vchild = VarPtr(varID)
        vAccVal = VarPtr(pszValue)
 
        Dim vt(0 To 1) As Integer
        vt(0) = VarType(vchild)
        vt(1) = VarType(vAccVal)
 
        vp(0) = VarPtr(vchild)
        vp(1) = VarPtr(vAccVal)

        'IAccessible::get_accValue
        DispCallFuncResult = DispCallFunc(pAcc, oVft_IAccessible_accValue, CC_STDCALL, _
                                          vbLong, 2&, vt(0&), vp(0&), result)
                                  
        If DispCallFuncResult = S_OK And result = S_OK Then
            Dim TextBoxText As String
            TextBoxText = GetStrFromPtrW(pszValue)
            MsgBox "TextBox1 text is:" & vbLf & vbLf & TextBoxText
        End If
 
        Dim vt2(0) As Integer
        'IUnknown::Release
        DispCallFuncResult = DispCallFunc(pAcc, oVft_IUnknown_Release, CC_STDCALL, _
                             vbLong, 0&, vt2(0&), vp2(0&), result)
    End If

End Sub

Private Function GetStrFromPtrW(ByVal lpString As LongPtr) As String
   Dim lLength As Long, sBuffer As String
   lLength = lstrlen(lpString)
   sBuffer = Space$(lLength)
   Call CopyMemory(ByVal StrPtr(sBuffer), ByVal lpString, lLength * 2&)
   GetStrFromPtrW = sBuffer
End Function

PS: Since this is just for illustrative purposes, I omitted conditional compilation code for VBA6/VBA5
Thank you Jaafar!
The code you posted is amazing! Worked like a charm.

As for
PS: Since this is just for illustrative purposes, I omitted conditional compilation code for VBA6/VBA5
Never mind this, since I'm using Excel 2019 64 bit. And I even managed to make your code work on VBA6 with some minor change.

But now I'm confused.
* The pszValue var (out parameter) that expects to receive a pointer to the BSTR string was missing.
so because I used the software COMView to open oleacc.dll located in C:\Windows\System32 to get the syntax for accValue:
TypeInfo_IAccessible_accValue.png

And I got this:
VBA Code:
[hidden] Bstr  accValue (
 [in, optional] varChild:Variant )

Yet you said the syntax should be:
HRESULT (STDMETHODCALLTYPE *get_accValue)(
IAccessible* This,
VARIANT varID,
BSTR *pszValue);

Now, which is which...
Apparently they are very different, and the one you give seems more "correct."

Anyway, thank you for offering the code, and your precious time on it. Your code on this forum has always been so useful and educational. I learned a lot from your posts.

Before closing this thread (I'm quite satisfied with a working example by now), I hope you can answer that final question above. Looking forward to your reply.
 
Upvote 0
But now I'm confused. .... I got this: ... Yet you said the syntax should be: ... Now, which is which...
Good point.

I am no expert in COM programming so I stand to be corrected. It might be that when (Oleacc.dll) implements the IAccessible interface that is defined in the header file (Oleacc.h), it wraps it in some class that exposes the initial Accessibility functions with different signatures ... Client code(s) will then work with this *intermediary* wrapper class.

When performing direct low level vTable calls with apis such as DispCallFunc , we stick to the actual functions signatures that are defined in the library header file.

But like I said, this is pure guesswork. I will need to research this topic further.

Now, going back to the code and according to the documentation, I should have used SysFreeString to deallocate the BSTR (pszValue) string:

VBA Code:
Private Declare PtrSafe Function SysFreeString Lib "oleaut32" ( _
        ByVal lpbstr As LongPtr _
) As Long


VBA Code:
If DispCallFuncResult = S_OK And result = S_OK Then
     Dim TextBoxText As String
     TextBoxText = GetStrFromPtrW(pszValue)
     Call SysFreeString(pszValue)
     MsgBox "TextBox1 text is:" & vbLf & vbLf & TextBoxText
 End If
 
Upvote 1
Good point.

I am no expert in COM programming so I stand to be corrected. It might be that when (Oleacc.dll) implements the IAccessible interface that is defined in the header file (Oleacc.h), it wraps it in some class that exposes the initial Accessibility functions with different signatures ... Client code(s) will then work with this *intermediary* wrapper class.

When performing direct low level vTable calls with apis such as DispCallFunc , we stick to the actual functions signatures that are defined in the library header file.

But like I said, this is pure guesswork. I will need to research this topic further.

Now, going back to the code and according to the documentation, I should have used SysFreeString to deallocate the BSTR (pszValue) string:

VBA Code:
Private Declare PtrSafe Function SysFreeString Lib "oleaut32" ( _
        ByVal lpbstr As LongPtr _
) As Long


VBA Code:
If DispCallFuncResult = S_OK And result = S_OK Then
     Dim TextBoxText As String
     TextBoxText = GetStrFromPtrW(pszValue)
     Call SysFreeString(pszValue)
     MsgBox "TextBox1 text is:" & vbLf & vbLf & TextBoxText
 End If
Thanks for the explanations. I think I'll stick to the header files then.

As for the SysFreeString, very kind reminder, never thought about it before.
Thank you Jaafar, for all this, in this thread.

Regards.
 
Upvote 0

Forum statistics

Threads
1,223,703
Messages
6,173,973
Members
452,540
Latest member
haasro02

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top