Get IAccessible of UserForm control without reference

Jack George

New Member
Joined
Jul 8, 2023
Messages
1
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

Excel motto
Not everything I do at work revolves around Excel. Only the fun parts.
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 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.
 
Upvote 0
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

Forum statistics

Threads
1,216,500
Messages
6,131,015
Members
449,615
Latest member
Nic0la

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