Results 1 to 17 of 17

Thread: Get array data from the array pointer?

  1. #1

    Thread Starter
    Addicted Member
    Join Date
    Jun 2022
    Posts
    202

    Get array data from the array pointer?

    Code:
    Option Explicit
    
    Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
    
    Sub test()
        Const PTR_LEN = 4
        Dim src(0 To 1) As Object
        Dim des(0 To 1) As Object
        Dim ptr As Long
        
        Set src(0) = Application: Set src(1) = ThisWorkbook
        ptr = VarPtr(src(0))
        
        CopyMemory des(0), ByVal ptr, PTR_LEN * (UBound(src) + 1)
        Debug.Print "Application name: " & des(0).Name & vbNewLine & "Workbook name: " & des(1).Name
        CopyMemory des(0), 0, PTR_LEN * (UBound(src) + 1)
    End Sub
    The above code stores the application and workbbook objects into a 2 element object array.
    It then simply copies the array into a destination array.

    Question:
    How would this work if we didn't know the size of the source array beforehand?

    I have a situation where an api function returns a pointer to an array of objects and I want to retrieve the array data from the pointer BUT I don't know the size of the array. I just know the pointer & nothing else.

    How can this be achieved? Thanks.
    Last edited by AngelV; Feb 8th, 2024 at 09:06 AM.

  2. #2
    Frenzied Member VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    1,200

    Talking Re: Get array data from the array pointer?

    This should work if you have a pointer to the safearray structure:

    Code:
    Private Declare Function SafeArrayAccessData Lib "oleaut32" Alias "#23" (ByVal pSA As Long, pData As Long) As Long
    Private Declare Function SafeArrayUnaccessData Lib "oleaut32" Alias "#24" (ByVal pSA As Long) As Long
    
    Dim pSA As Long ' <-- pointer to the safearray structure
    Dim pData As Long ' <-- pointer to the array data
        SafeArrayAccessData pSA, pData: SafeArrayUnaccessData pSA

  3. #3
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,518

    Re: Get array data from the array pointer?

    Which API, specifically? Because most won't be returning a SAFEARRAY.

    VB holds the reference as a double pointer; so if it's VB you have to first dereference the SAFEARRAY** into SAFEARRAY* then you can fill in the SAFEARRAY type, which for a 1D array:

    Code:
    Public Type SAFEARRAY1D
        cDims      As Integer
        fFeatures  As Integer
        cbElements As Long
        cLocks     As Long
        pvData     As LongPtr
        Bounds     As SAFEARRAYBOUND
    End Type
    Public Type SAFEARRAYBOUND
        cElements As Long
        lLbound   As Long
    End Type
    Then if you have
    Code:
        Dim pArr As Long
        Dim pArr2 As Long
        Dim arr() As Long
        ReDim arr(1 To 5)
        pArr2 = ArrPtr(arr)
        GetMem4 pArr2, pArr
    pArr2 is now a pointer to a SAFEARRAY you can fill out:

    Code:
    Dim tSA As SAFEARRAY1D
    CopyMemory tSA, ByVal pArr2, LenB(tSA)
    .pvData is the pointer to the raw data.

  4. #4
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,614

    Re: Get array data from the array pointer?

    If it's not a SafeArray (or something similar), I don't see how you're going to find the end without also having a length (and maybe, number of dims) argument. Or, I guess there could be some kind of end-of-array marker like many strings have.

    Beyond that (or maybe just knowledge about the API telling you how many array items it returns), I don't think it'd be possible.

    What API call are we talking about?
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  5. #5

    Thread Starter
    Addicted Member
    Join Date
    Jun 2022
    Posts
    202

    Re: Get array data from the array pointer?

    Thanks for answering.

    Let me explain and provide some more context:

    What I am actually trying to do is to retrieve all descendant accessible elements from a hwnd at runtime.

    If I was to set a reference to the UIAutomationClient library in my vba project @ design time, I would simply use the following code and that would be it.
    Code:
        Set oAutomation = New CUIAutomation
        Set oElement = oAutomation.ElementFromHandle(ByVal hwnd)
        Set oCondition = oAutomation.CreateTrueCondition
        Set oAllElements = oElement.FindAll(TreeScope_Descendants, oCondition)
      
        For i = 0 To oAllElements.Length - 1
            Set oElement = oAllElements.GetElement(i)
            Debug.Print oElement.CurrentName
        Next i
    But for the sake of learning, I want to achieve the above @ runtime w/o the need to reference the tlb.

    I am performing some low level vtbl calls (with CoCreateInstance--DispCallFunc) to get the interface pointers of all the relevant interfaces and then call the required interface functions respectively.

    I have successfully obtained pointers to the IID_CUIAUTOMATION Class and to the IID_IUIAUTOMATION, IUIAutomationElement and IUIAutomationCondition interfaces but for some reason, I am stuck at the IUIAutomationElement::FindAll call and can't obtain the accessible elements in the passed array.

    Here is the problematic relevant portion of the code
    Code:
    Const TreeScope_Descendants = 4&
    Dim pArray As Long
    vtblOffset = 6 * PTR_LEN ' IUIAutomationElement::FindAll
    
    lRet = vtblCall(pElement, vtblOffset, vbLong, CC_STDCALL, TreeScope_Descendants, pTrueCond, VarPtr(pArray))
    
    Debug.Print lRet ' <== Returns S_OK indicating success of vtblCall
    
    Dim tSA As SAFEARRAY1D
    CopyMemory tSA, ByVal pArray, LenB(tSA)
    
    Debug.Print tSA.pvData; tSA.cDims; tSA.Bounds.cElements; tSA.fFeatures
    
    output:
    pvData : -1
    cDims : -13912
    cElements : -1
    fFeatures :  9863
    I had already tried using the SafeArray logic but as you guys pointed out, I am not even sure the IUIAutomationElement::FindAll function returns a SafeArray and the documentation from the header file looks like this:
    Code:
    virtual HRESULT STDMETHODCALLTYPE FindAll( 
                /* [in] */ enum TreeScope scope,
                /* [in] */ __RPC__in_opt IUIAutomationCondition *condition,
                /* [retval][out] */ __RPC__deref_out_opt IUIAutomationElementArray **found) = 0;
    According to the results I am getting, it looks like the array is unintialised.

    Useful Documentation References:
    UIAutomationClient.h
    IUIAutomationElement::FindAll

    EDIT:
    BTW, I am using this in a x64 process (excel) Win 10 x64 (but I am careful using 8bit pointers), if that makes a difference.
    Last edited by AngelV; Feb 9th, 2024 at 12:47 AM.

  6. #6
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,568

    Re: Get array data from the array pointer?

    I'm no COM expert but this looks very wrong.

    According to the documentation, FindAll doesn't return a SAFEARRAY, it returns a pointer to an interface called IUIAutomationElementArray which I'm guessing means what is actually returned is a live object that implements this interface. The documentation for this interface implies that this object is something like VB6's Collection object. According to the documentation here, this interface has a method called get_Length that tells you how many elements are contained in this collection and it has a GetElement method to retrieve individual items from the collection. Even your original VBA code shows this is the case:-
    Code:
     Set oAutomation = New CUIAutomation
        Set oElement = oAutomation.ElementFromHandle(ByVal hwnd)
        Set oCondition = oAutomation.CreateTrueCondition
        Set oAllElements = oElement.FindAll(TreeScope_Descendants, oCondition)
      
        For i = 0 To oAllElements.Length - 1
            Set oElement = oAllElements.GetElement(i)
            Debug.Print oElement.CurrentName
        Next i
    Highlighted in red are your calls to the methods/properties of the IUIAutomationElementArray interface. So you're not enumerating a SAFEARRAY, you're enumerating some kind of COM Collection type object. So in your VB6 code where you have this:-
    Code:
    Dim pArray As Long
    It should actually be:-
    Code:
    Dim pArray As IUIAutomationElementArray
    Like I said, I'm no COM expert so I have no idea how to make that work in VB6. Perhaps you need a type library to declare p as IUIAutomationElementArray legally and call it's methods from VB6. I leave that one to the experts.
    Last edited by Niya; Feb 9th, 2024 at 04:21 AM.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  7. #7
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,518

    Re: Get array data from the array pointer?

    Niya is correct; that's an object pointer, not a SAFEARRAY.

    You can keep it As LongPtr to avoid the TLB, but then you need to make the calls you made with DispCallFunc instead, passing pArray, assuming it's valid, which I couldn't say without seeing your vtblcall method.


    PS- I'm assuming you changed to to Long to fit here; obviously if it's actually a Long in your project that's wrong. In the future, leave LongPtr as LongPtr, there's enough VB6/VBA64/tB64 cross-compatible code out there now and experience with those that people here get what LongPtr is, and it will help us better help you, like if the above was actually a Long.
    Last edited by fafalone; Feb 9th, 2024 at 04:51 AM.

  8. #8

    Thread Starter
    Addicted Member
    Join Date
    Jun 2022
    Posts
    202

    Re: Get array data from the array pointer?

    According to the documentation, FindAll doesn't return a SAFEARRAY, it returns a pointer to an interface called IUIAutomationElementArray which I'm guessing means what is actually returned is a live object that implements this interface
    Good point Niya. Thanks.

    I have managed to get the pointer to the IUIAutomationElementArray interface
    Code:
        vtblOffset = 6 * PTR_LEN ' IUIAutomationElement::FindAll
            
        lRet = vtblCall(pElement, vtblOffset, vbLong, CC_STDCALL, Scope, pTrueCond, VarPtr(pElementArray))
        
        vtblOffset = 3 * PTR_LEN ' IUIAutomationElementArray :get_Length
        
        lRet = vtblCall(pElementArray, vtblOffset, vbLong, CC_STDCALL, VarPtr(Lenghth))
    
        vtblOffset = 4 * PTR_LEN ' IUIAutomationElementArray :GetElement
    
        lRet = vtblCall(pElementArray, vtblOffset, vbLong, CC_STDCALL, j, VarPtr(pElement))
    I am trying to wrap this in a small class for making the horrible and much unfriendly IAccessibility tree search functionality a bit easier and all w/o the need to reference the external IAUtomationClient library. I am sure this will come in handy for vba coders at some point.

  9. #9

    Thread Starter
    Addicted Member
    Join Date
    Jun 2022
    Posts
    202

    Re: Get array data from the array pointer?

    Ok- In case anyone is interested, I am posting here the class code (C_AccEx) for office applications.

    The class is supposed to retrieve automation elements for a specified window and extends the native IAccessible interface with a few more handy Properties and Methods. All done @ runtime w/o setting a reference to the UIAutomationClient library.

    I hope the class is robust enough.

    Download file
    File removed by moderator
    Last edited by dday9; Feb 12th, 2024 at 09:15 AM.

  10. #10
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Location
    South Louisiana
    Posts
    11,657

    Re: Get array data from the array pointer?

    @AngelV - As a general rule of thumb file uploads are permitted, however there are a few exceptions with office macros being one of them. This is because macros allow users to automate tasks in Excel, but they can also execute malicious code that is easily obfuscated. Because of this, I removed the download.

    You're more than welcome to share the raw code. That away users can determine its safety without downloading anything, but you cannot upload the macro as a downloadable file.
    "Code is like humor. When you have to explain it, it is bad." - Cory House
    VbLessons | Code Tags | Sword of Fury - Jameram

  11. #11

    Thread Starter
    Addicted Member
    Join Date
    Jun 2022
    Posts
    202

    Re: Get array data from the array pointer?

    Quote Originally Posted by dday9 View Post
    @AngelV - As a general rule of thumb file uploads are permitted, however there are a few exceptions with office macros being one of them. This is because macros allow users to automate tasks in Excel, but they can also execute malicious code that is easily obfuscated. Because of this, I removed the download.

    You're more than welcome to share the raw code. That away users can determine its safety without downloading anything, but you cannot upload the macro as a downloadable file.
    No worries. since the code is quite large and there is a limit to # of characters we can post, I will split the raw code into sections and will share it in the next few posts.

    Thanks.
    Last edited by AngelV; Feb 12th, 2024 at 09:42 AM.

  12. #12

    Thread Starter
    Addicted Member
    Join Date
    Jun 2022
    Posts
    202

    Re: Get array data from the array pointer?

    1 -First section of the C_AccEx Class:
    Code:
    Option Explicit
    
    Implements IAccElement
    
    #If Win64 Then
        Private Const NULL_PTR = 0^
        Private Const PTR_LEN = 8&
    #Else
        Private Const NULL_PTR = 0&
        Private Const PTR_LEN = 4&
    #End If
    
    Public Enum TreeScope
        TreeScope_None = 0&
        TreeScope_Element = 1&
        TreeScope_Children = 2&
        TreeScope_Descendants = 4&
        TreeScope_Subtree = ((TreeScope_Element + TreeScope_Children) + TreeScope_Descendants)
    End Enum
    
    #If VBA7 Then
        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 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, ByRef paTypes As Integer, ByRef paValues As LongPtr, ByRef retVAR As Variant) As Long
        Private Declare PtrSafe Sub SetLastError Lib "kernel32" (ByVal dwErrCode As Long)
        Private Declare PtrSafe Function StringFromGUID2 Lib "ole32" (ByRef rguid As GUID, ByVal lpsz As LongPtr, ByVal cchMax As Long) As Long
        Private Declare PtrSafe Function IIDFromString Lib "ole32.dll" (ByVal lpsz As LongPtr, ByVal lpiid As LongPtr) As LongPtr
        Private Declare PtrSafe Function CLSIDFromString Lib "ole32" (ByVal OleStringCLSID As LongPtr, ByRef cGUID As GUID) As Long
        Private Declare PtrSafe Function CoCreateInstance Lib "ole32" (ByRef rclsid As GUID, ByVal pUnkOuter As LongPtr, ByVal dwClsContext As Long, ByRef riid As GUID, ByRef ppv As LongPtr) As Long
        Private Declare PtrSafe Function AccessibleChildren Lib "oleacc" (ByVal paccContainer As Office.IAccessible, ByVal iChildStart As Long, ByVal cChildren As Long, ByRef rgvarChildren As Any, ByRef pcObtained As Long) As Long
        Private Declare PtrSafe Function IsWindow Lib "user32" (ByVal hwnd As LongPtr) As Long
    #Else
        Private Enum LongPtr
            [_]
        End Enum
        Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
        Private Declare Function lstrlen Lib "kernel32" Alias "lstrlenW" (ByVal lpString As LongPtr) As Long
        Private Declare 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, ByRef paTypes As Integer, ByRef paValues As LongPtr, ByRef retVAR As Variant) As Long
        Private Declare Sub SetLastError Lib "kernel32" (ByVal dwErrCode As Long)
        Private Declare Function StringFromGUID2 Lib "ole32" (ByRef rguid As GUID, ByVal lpsz As LongPtr, ByVal cchMax As Long) As Long
        Private Declare Function IIDFromString Lib "ole32.dll" (ByVal lpsz As LongPtr, ByVal lpiid As LongPtr) As LongPtr
        Private Declare Function CLSIDFromString Lib "ole32" (ByVal OleStringCLSID As LongPtr, ByRef cGUID As GUID) As Long
        Private Declare Function CoCreateInstance Lib "ole32" (ByRef rclsid As GUID, ByVal pUnkOuter As LongPtr, ByVal dwClsContext As Long, ByRef riid As GUID, ByRef ppv As LongPtr) As Long
        Private Declare Function AccessibleChildren Lib "oleacc" (ByVal paccContainer As Office.IAccessible, ByVal iChildStart As Long, ByVal cChildren As Long, ByRef rgvarChildren As Any, ByRef pcObtained As Long) As Long
        Private Declare Function IsWindow Lib "user32" (ByVal hwnd As LongPtr) As Long
    #End If
    
    Private Type RECT
        Left As Long
        Top As Long
        Right As Long
        Bottom As Long
    End Type
        
    Private Type RECT_PTR
        Left As LongPtr
        Top As LongPtr
        Right As LongPtr
        Bottom As LongPtr
    End Type
    
    Private Type POINTAPI
        X As Long
        Y As Long
    End Type
    
    Private Type GUID
        Data1 As Long
        Data2 As Integer
        Data3 As Integer
        Data4(0& To 7&) As Byte
    End Type
    
    Private oElements As Collection
    Private oElement  As C_AccEx
    
    Private pAutomation As LongPtr
    Private pPattern As LongPtr
    Private pElement As LongPtr
    Private pElementArray As LongPtr
    Private pTrueCond As LongPtr
    
    Private pLegacyName As LongPtr
    Private pAccKey As LongPtr
    Private pItemType As LongPtr
    Private pLocalControlType As LongPtr
    Private pDefaultAction As LongPtr
    Private pKeyboardShortcut As LongPtr
    Private pClassName As LongPtr
    Private pValue As LongPtr
    Private pLegacyDescription As LongPtr
    Private pLegacyHelp As LongPtr
    Private lHwnd As LongPtr
    
    Private lOrientation As Long
    Private lItemStatus As Long
    Private lProcID As Long
    Private lRole As Long
    Private lState As Long
    Private lControlType As Long
    Private lProcessID As Long
    
    Private sName As String
    Private sDescription As String
    Private sHelpText As String
    Private sValue As String
    Private sDefaultAction As String
    Private sKeyboardShortcut As String
    Private sAcceleratorKey As String
    Private sClassName As String
    Private sItemType As String
    Private sLocalControlType As String
    
    Private bHasKeyboardFocus As Boolean
    Private bIsEnabled As Boolean
    Private bOffScreen As Boolean
    Private bIsPassword As Boolean
    
    
    Private Sub Class_Initialize()
        Set oElements = New Collection
    End Sub
    
    ' __________________________________________ Public Members __________________________________________________
    
    Sub GetAccessibleChildrenFromHwnd(ByVal hwnd As LongPtr, Optional ByVal Scope As TreeScope = TreeScope_Subtree)
        If IsWindow(hwnd) = 0& Then
            MsgBox "Invalid Window Handle !":    Exit Sub
        End If
        Call FindElements(hwnd, Scope)
    End Sub
    
    Function ElementsCount() As Long
        ElementsCount = oElements.Count
    End Function
    
    Property Get Items() As Collection
        Set Items = oElements
    End Property
    
    
    Property Get Name() As String
        Name = sName
    End Property
    Property Let Name(ByVal vNewValue As String)
        sName = vNewValue
    End Property
    
    Property Get Role() As Long
        Role = lRole
    End Property
    Property Let Role(ByVal vNewValue As Long)
        lRole = vNewValue
    End Property
    
    Property Get Description() As String
        Description = sDescription
    End Property
    Property Let Description(ByVal vNewValue As String)
        sDescription = vNewValue
    End Property
    
    Property Get HelpText() As String
        HelpText = sHelpText
    End Property
    Property Let HelpText(ByVal vNewValue As String)
        sHelpText = vNewValue
    End Property
    
    Property Get State() As Long
        State = lState
    End Property
    Property Let State(ByVal vNewValue As Long)
        lState = vNewValue
    End Property
    
    Property Get Value() As String
        Value = sValue
    End Property
    Property Let Value(ByVal vNewValue As String)
        sValue = vNewValue
    End Property
    
    Property Get DefaultAction() As String
        DefaultAction = sDefaultAction
    End Property
    Property Let DefaultAction(ByVal vNewValue As String)
        sDefaultAction = vNewValue
    End Property
    
    Property Get KeyboardShortcut() As String
        KeyboardShortcut = sKeyboardShortcut
    End Property
    Property Let KeyboardShortcut(ByVal vNewValue As String)
        sKeyboardShortcut = vNewValue
    End Property
    
    Property Get AcceleratorKey() As String
        AcceleratorKey = sAcceleratorKey
    End Property
    Property Let AcceleratorKey(ByVal vNewValue As String)
        sAcceleratorKey = vNewValue
    End Property
    
    Property Get ControlType() As Long
        ControlType = lControlType
    End Property
    Property Let ControlType(ByVal vNewValue As Long)
        lControlType = vNewValue
    End Property
    
    Property Get HasKeyboardFocus() As Boolean
        HasKeyboardFocus = bHasKeyboardFocus
    End Property
    Property Let HasKeyboardFocus(ByVal vNewValue As Boolean)
        bHasKeyboardFocus = vNewValue
    End Property
    
    Property Get IsEnabled() As Boolean
        IsEnabled = bIsEnabled
    End Property
    Property Let IsEnabled(ByVal vNewValue As Boolean)
        bIsEnabled = vNewValue
    End Property
    
    Property Get ClassName() As String
        ClassName = sClassName
    End Property
    Property Let ClassName(ByVal vNewValue As String)
        sClassName = vNewValue
    End Property
    
    Property Get IsOffScreen() As Boolean
        IsOffScreen = bOffScreen
    End Property
    Property Let IsOffScreen(ByVal vNewValue As Boolean)
        bOffScreen = vNewValue
    End Property
    
    Property Get ItemType() As String
       ItemType = sItemType
    End Property
    Property Let ItemType(ByVal vNewValue As String)
        sItemType = vNewValue
    End Property
    
    Property Get ProcessID() As Long
        ProcessID = lProcessID
    End Property
    Property Let ProcessID(ByVal vNewValue As Long)
        lProcessID = vNewValue
    End Property
    
    Property Get LocalControlType() As String
        LocalControlType = sLocalControlType
    End Property
    Property Let LocalControlType(ByVal vNewValue As String)
        sLocalControlType = vNewValue
    End Property
    
    Property Get Orientation() As Long
        Orientation = lOrientation
    End Property
    Property Let Orientation(ByVal vNewValue As Long)
        lOrientation = vNewValue
    End Property
    
    Property Get ItemStatus() As Long
        ItemStatus = lItemStatus
    End Property
    Property Let ItemStatus(ByVal vNewValue As Long)
        lItemStatus = vNewValue
    End Property
    
    Property Get IsPassword() As Boolean
        IsPassword = bIsPassword
    End Property
    Property Let IsPassword(ByVal vNewValue As Boolean)
        bIsPassword = vNewValue
    End Property
    
    Property Get WindowHandle() As LongPtr
        WindowHandle = lHwnd
    End Property
    Property Let WindowHandle(ByVal vNewValue As LongPtr)
        lHwnd = vNewValue
    End Property
    
    Property Get pIAutomation() As LongPtr
        pIAutomation = pAutomation
    End Property
    Property Let pIAutomation(ByVal vNewValue As LongPtr)
        pAutomation = vNewValue
    End Property
    
    Property Get pIPattern() As LongPtr
        pIPattern = pPattern
    End Property
    Property Let pIPattern(ByVal vNewValue As LongPtr)
        pPattern = vNewValue
    End Property
    
    Property Get pITrueCond() As LongPtr
        pITrueCond = pTrueCond
    End Property
    Property Let pITrueCond(ByVal vNewValue As LongPtr)
        pTrueCond = vNewValue
    End Property
    
    Property Get pIElementArray() As LongPtr
        pIElementArray = pElementArray
    End Property
    Property Let pIElementArray(ByVal vNewValue As LongPtr)
        pElementArray = vNewValue
    End Property
    
    Property Get pIElement() As LongPtr
        pIElement = pElement
    End Property
    Property Let pIElement(ByVal vNewValue As LongPtr)
        pElement = vNewValue
    End Property
    
    Sub GetClickablePoint(ByRef X As Long, ByRef Y As Long)
        Call ClickablePoint(X, Y)
    End Sub
    
    Sub GetScreenBoundingRectangle(X As Long, Y As Long, nWidth As Long, nHeight As Long)
        Call ScreenBoundingRectangle(X, Y, nWidth, nHeight)
    End Sub
    
    Sub SelectMe()
        Call Select_Item
    End Sub
    
    Sub DoDefaultAction()
        Call DoDefaultAct
    End Sub
    
    
    
    ' _____________________________________________ Interface Imp Routines ___________________________________________
    
    Private Property Get IAccElement_pIAutomation() As LongPtr
        IAccElement_pIAutomation = pAutomation
    End Property
    
    Private Property Get IAccElement_pITrueCond() As LongPtr
        IAccElement_pITrueCond = pTrueCond
    End Property
    
    Private Property Get IAccElement_pIElementArray() As LongPtr
        IAccElement_pIElementArray = pElementArray
    End Property
    
    Private Property Get IAccElement_pIElement() As LongPtr
        IAccElement_pIElement = pElement
    End Property
    
    Private Property Get IAccElement_pIPattern() As LongPtr
        IAccElement_pIPattern = pPattern
    End Property
    
    
    Private Property Get IAccElement_DefaultAction() As String
        IAccElement_DefaultAction = sDefaultAction
    End Property
    
    Private Property Get IAccElement_Description() As String
        IAccElement_Description = sDescription
    End Property
    
    Private Property Get IAccElement_AcceleratorKey() As String
        IAccElement_AcceleratorKey = sAcceleratorKey
    End Property
    
    Private Property Get IAccElement_HelpText() As String
        IAccElement_HelpText = sHelpText
    End Property
    
    Private Property Get IAccElement_KeyboardShortcut() As String
        IAccElement_KeyboardShortcut = sKeyboardShortcut
    End Property
    
    Private Property Get IAccElement_Name() As String
        IAccElement_Name = sName
    End Property
    
    Private Property Get IAccElement_Role() As Long
        IAccElement_Role = lRole
    End Property
    
    Private Property Get IAccElement_State() As Long
        IAccElement_State = lState
    End Property
    
    Private Property Get IAccElement_Value() As String
        IAccElement_Value = sValue
    End Property
    
    Private Property Get IAccElement_ClassName() As String
        IAccElement_ClassName = sClassName
    End Property
    
    Private Property Get IAccElement_ControlType() As Long
        IAccElement_ControlType = lControlType
    End Property
    
    Private Property Get IAccElement_HasKeyboardFocus() As Boolean
        IAccElement_HasKeyboardFocus = bHasKeyboardFocus
    End Property
    
    Private Property Get IAccElement_IsEnabled() As Boolean
        IAccElement_IsEnabled = bIsEnabled
    End Property
    
    Private Property Get IAccElement_IsOffScreen() As Boolean
        IAccElement_IsOffScreen = bOffScreen
    End Property
    
    Private Property Get IAccElement_IsPassword() As Boolean
        IAccElement_IsPassword = bIsPassword
    End Property
    
    Private Property Get IAccElement_ItemStatus() As Long
        IAccElement_ItemStatus = lItemStatus
    End Property
    
    Private Property Get IAccElement_ItemType() As String
        IAccElement_ItemType = sItemType
    End Property
    
    Private Property Get IAccElement_LocalControlType() As String
        IAccElement_LocalControlType = sLocalControlType
    End Property
    
    Private Property Get IAccElement_Orientation() As String
        IAccElement_Orientation = lOrientation
    End Property
    
    Private Property Get IAccElement_ProcessID() As Long
        IAccElement_ProcessID = lProcessID
    End Property
    
    Private Property Get IAccElement_WindowHandle() As LongPtr
        IAccElement_WindowHandle = lHwnd
    End Property
    
    
    Private Sub IAccElement_SelectMe()
        Call Select_Item
    End Sub
    
    Private Sub IAccElement_DoDefaultAction()
        Call DoDefaultAct
    End Sub
    
    Private Sub IAccElement_GetClickablePoint(ByRef X As Long, ByRef Y As Long)
        Call ClickablePoint(X, Y)
    End Sub
    
    Private Sub IAccElement_GetScreenBoundingRectangle(ByRef X As Long, ByRef Y As Long, ByRef nWidth As Long, ByRef nHeight As Long)
        Call ScreenBoundingRectangle(X, Y, nWidth, nHeight)
    End Sub
    
    
    ' ___________________________________________ Private Routines __________________________________________________
    
    Private Function GetAutomationPtr() As LongPtr
    
        Const IID_CUIAUTOMATION = "{FF48DBA4-60EF-4201-AA87-54103EEF594E}"
        Const IID_IUIAUTOMATION = "{30CBE57D-D9D0-452A-AB13-7AC5AC4825EE}"
        Const CLSCTX_INPROC_SERVER = &H1, CC_STDCALL = 4&, S_OK = 0&
        
        Dim iidCuiAuto As GUID, iidIuiAuto As GUID, lRet As Long
        
        lRet = CLSIDFromString(StrPtr(IID_CUIAUTOMATION), iidCuiAuto)
        Call DispGUID(iidCuiAuto)
        lRet = CLSIDFromString(StrPtr(IID_IUIAUTOMATION), iidIuiAuto)
        Call DispGUID(iidIuiAuto)
        lRet = CoCreateInstance(iidCuiAuto, NULL_PTR, CLSCTX_INPROC_SERVER, iidIuiAuto, pAutomation)
        
        If lRet = S_OK Then GetAutomationPtr = pAutomation
    
    End Function
    Last edited by AngelV; Feb 12th, 2024 at 09:37 AM.

  13. #13

    Thread Starter
    Addicted Member
    Join Date
    Jun 2022
    Posts
    202

    Re: Get array data from the array pointer?

    2- Second section of the C_AccEx Class:
    Code:
    Private Sub FindElements(ByVal hwnd As LongPtr, Optional ByVal Scope As TreeScope = TreeScope_Subtree)
    
        Const CC_STDCALL = 4&, TreeScope_Descendants = 4&, UIA_LegacyIAccessiblePatternId = 10018&
        Const IID_IUIAutomationLegacyIAccessiblePattern = "{828055ad-355b-4435-86d5-3b51c14a9b1b}"
        Dim lIndex As Long, lElementsCount As Long
        Dim lRet As Long, vTblOffset As Long, vFuncOrdinal As Long
        Dim iidCuiAuto As GUID
    
    
        pAutomation = GetAutomationPtr
        If pAutomation = NULL_PTR Then MsgBox "Automation failed.": Exit Sub
     
        vFuncOrdinal = 6& ' IUIAutomation::ElementFromHandle
        vTblOffset = vFuncOrdinal * PTR_LEN
        lRet = vtblCall(pAutomation, vTblOffset, vbLong, CC_STDCALL, hwnd, VarPtr(pElement))
        
        vFuncOrdinal = 21& ' IUIAutomation::CreateTrueCondition
        vTblOffset = vFuncOrdinal * PTR_LEN
        lRet = vtblCall(pAutomation, vTblOffset, vbLong, CC_STDCALL, VarPtr(pTrueCond))
       
        vFuncOrdinal = 6& ' IUIAutomationElement::FindAll
        vTblOffset = vFuncOrdinal * PTR_LEN ' IUIAutomationElement::FindAll
        lRet = vtblCall(pElement, vTblOffset, vbLong, CC_STDCALL, Scope, pTrueCond, VarPtr(pElementArray))
    
        vFuncOrdinal = 3& ' IUIAutomationElementArray :get_Length
        vTblOffset = vFuncOrdinal * PTR_LEN
        lRet = vtblCall(pElementArray, vTblOffset, vbLong, CC_STDCALL, VarPtr(lElementsCount))
    
        If lElementsCount = 0& Then
            MsgBox "No Accessible descendants were found.": Exit Sub
        End If
        
        For lIndex = 0& To lElementsCount - 1&
        
            vFuncOrdinal = 4& ' IUIAutomationElementArray :GetElement
            vTblOffset = vFuncOrdinal * PTR_LEN
            lRet = vtblCall(pElementArray, vTblOffset, vbLong, CC_STDCALL, lIndex, VarPtr(pElement))
            
            lRet = CLSIDFromString(StrPtr(IID_IUIAutomationLegacyIAccessiblePattern), iidCuiAuto)
            Call DispGUID(iidCuiAuto)
            vFuncOrdinal = 14& 'IID_IUIAutomationElement::GetCurrentPatternAs
            vTblOffset = vFuncOrdinal * PTR_LEN
            lRet = vtblCall(pElement, vTblOffset, vbLong, CC_STDCALL, UIA_LegacyIAccessiblePatternId, VarPtr(iidCuiAuto), VarPtr(pPattern))
          
            If pPattern <> NULL_PTR Then
                
                'Store Interfaces Ptrs in each new class instance.
                Set oElement = New C_AccEx
                With oElement
                    .pIAutomation = pAutomation
                    .pITrueCond = pTrueCond
                    .pIElementArray = pElementArray
                    .pIElement = pElement
                    .pIPattern = pPattern
                End With
                
                'Retrieve descendants properties.
                vFuncOrdinal = 7& 'IID_IUIAutomationLegacyIAccessiblePattern::get_CurrentName
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(pPattern, vTblOffset, vbLong, CC_STDCALL, VarPtr(pLegacyName))
                oElement.Name = GetStrFromPtrW(pLegacyName)
                
                vFuncOrdinal = 10& 'IID_IUIAutomationLegacyIAccessiblePattern::get_CurrentRole
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(pPattern, vTblOffset, vbLong, CC_STDCALL, VarPtr(lRole))
                oElement.Role = lRole
                
                vFuncOrdinal = 9& 'IID_IUIAutomationLegacyIAccessiblePattern::get_CurrentDescription
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(pPattern, vTblOffset, vbLong, CC_STDCALL, VarPtr(pLegacyDescription))
                oElement.Description = GetStrFromPtrW(pLegacyDescription)
                
                vFuncOrdinal = 12& 'IID_IUIAutomationLegacyIAccessiblePattern::get_CurrentHelp
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(pPattern, vTblOffset, vbLong, CC_STDCALL, VarPtr(pLegacyHelp))
                oElement.HelpText = GetStrFromPtrW(pLegacyHelp)
                
                vFuncOrdinal = 11& 'IID_IUIAutomationLegacyIAccessiblePattern::get_CurrentState
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(pPattern, vTblOffset, vbLong, CC_STDCALL, VarPtr(lState))
                oElement.State = lState
                
                vFuncOrdinal = 8& 'IID_IUIAutomationLegacyIAccessiblePattern::get_CurrentValue
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(pPattern, vTblOffset, vbLong, CC_STDCALL, VarPtr(pValue))
                oElement.Value = GetStrFromPtrW(pValue)
                
                vFuncOrdinal = 15& 'IID_IUIAutomationLegacyIAccessiblePattern::get_CurrentDefaultAction
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(pPattern, vTblOffset, vbLong, CC_STDCALL, VarPtr(pDefaultAction))
                oElement.DefaultAction = GetStrFromPtrW(pDefaultAction)
                
                vFuncOrdinal = 13& 'IID_IUIAutomationLegacyIAccessiblePattern::get_CurrentKeyboardShortcut
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(pPattern, vTblOffset, vbLong, CC_STDCALL, VarPtr(pKeyboardShortcut))
                oElement.KeyboardShortcut = GetStrFromPtrW(pKeyboardShortcut)
                
                vFuncOrdinal = 21& 'IUIAutomationElement::get_CurrentControlType
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(pElement, vTblOffset, vbLong, CC_STDCALL, VarPtr(lControlType))
                oElement.ControlType = lControlType
                
                vFuncOrdinal = 24& 'IUIAutomationElement::get_CurrentAcceleratorKey
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(pElement, vTblOffset, vbLong, CC_STDCALL, VarPtr(pAccKey))
                oElement.AcceleratorKey = GetStrFromPtrW(pAccKey)
                
                vFuncOrdinal = 26& 'IUIAutomationElement::get_CurrentHasKeyboardFocus
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(pElement, vTblOffset, vbLong, CC_STDCALL, VarPtr(bHasKeyboardFocus))
                oElement.HasKeyboardFocus = bHasKeyboardFocus
                
                vFuncOrdinal = 28& 'IUIAutomationElement::get_CurrentIsEnabled
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(pElement, vTblOffset, vbLong, CC_STDCALL, VarPtr(bIsEnabled))
                oElement.IsEnabled = bIsEnabled
                
                vFuncOrdinal = 30& 'IUIAutomationElement::get_CurrentClassName
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(pElement, vTblOffset, vbLong, CC_STDCALL, VarPtr(pClassName))
                oElement.ClassName = GetStrFromPtrW(pClassName)
                
                vFuncOrdinal = 38& 'IUIAutomationElement::get_CurrentIsOffscreen
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(pElement, vTblOffset, vbLong, CC_STDCALL, VarPtr(bOffScreen))
                oElement.KeyboardShortcut = bOffScreen
                
                vFuncOrdinal = 37& 'IUIAutomationElement::get_CurrentItemType
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(pElement, vTblOffset, vbLong, CC_STDCALL, VarPtr(pItemType))
                oElement.ItemType = GetStrFromPtrW(pItemType)
                
                vFuncOrdinal = 20& 'IUIAutomationElement::get_CurrentProcessId
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(pElement, vTblOffset, vbLong, CC_STDCALL, VarPtr(lProcID))
                oElement.ProcessID = lProcID
                
                vFuncOrdinal = 22& 'IUIAutomationElement::get_CurrentLocalizedControlType
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(pElement, vTblOffset, vbLong, CC_STDCALL, VarPtr(pLocalControlType))
                oElement.LocalControlType = GetStrFromPtrW(pLocalControlType)
                
                vFuncOrdinal = 39& 'IUIAutomationElement::get_CurrentOrientation
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(pElement, vTblOffset, vbLong, CC_STDCALL, VarPtr(lOrientation))
                oElement.Orientation = lOrientation
                
                vFuncOrdinal = 43& 'IUIAutomationElement::get_CurrentItemStatus
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(pElement, vTblOffset, vbLong, CC_STDCALL, VarPtr(lItemStatus))
                oElement.ItemStatus = lOrientation
                
                vFuncOrdinal = 35& 'IUIAutomationElement::get_CurrentIsPassword
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(pElement, vTblOffset, vbLong, CC_STDCALL, VarPtr(bIsPassword))
                oElement.IsPassword = bIsPassword
                
                vFuncOrdinal = 36& 'IUIAutomationElement::get_CurrentNativeWindowHandle
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(pElement, vTblOffset, vbLong, CC_STDCALL, VarPtr(lHwnd))
                oElement.WindowHandle = lHwnd
                
                'Release IUIAutomationElement Interface.
                vFuncOrdinal = 2& 'IUIAutomationElement::Release
                vTblOffset = vFuncOrdinal * PTR_LEN
                lRet = vtblCall(Me.pIElement, vTblOffset, vbEmpty, CC_STDCALL)
                
                'Add all found elements to collection.
                oElements.Add oElement
                
            End If
            
        Next lIndex
            
        'Release other Automation Interfaces.
        If Me.pIAutomation Then
            lRet = vtblCall(Me.pIElementArray, vTblOffset, vbEmpty, CC_STDCALL) 'IUIAutomationElementArray ::Release
            lRet = vtblCall(Me.pITrueCond, vTblOffset, vbEmpty, CC_STDCALL)     'IUIAutomationCondition ::Release
            lRet = vtblCall(Me.pIAutomation, vTblOffset, vbEmpty, CC_STDCALL)   'IUIAutomation::Release
        End If
        
    End Sub
    
    Private Sub ClickablePoint(ByRef X As Long, ByRef Y As Long)
    
        Const CC_STDCALL = 4&
        Dim Pt1 As Currency, Pt2 As POINTAPI
        Dim lClickable As Long
        Dim lRet As Long, vTblOffset As Long, vFuncOrdinal As Long
    
        vFuncOrdinal = 84& 'IUIAutomationElement::GetClickablePoint
        vTblOffset = vFuncOrdinal * PTR_LEN
        lRet = vtblCall(Me.pIElement, vTblOffset, vbLong, CC_STDCALL, VarPtr(Pt1), VarPtr(lClickable))
        Call CopyMemory(Pt2, Pt1, LenB(Pt2))
        X = Pt2.X: Y = Pt2.Y
    
    End Sub
    
    Private Sub ScreenBoundingRectangle(X As Long, Y As Long, nWidth As Long, nHeight As Long)
    
        Const CC_STDCALL = 4&
        Dim lRet As Long, vTblOffset As Long, vFuncOrdinal As Long
    
        vFuncOrdinal = 43& 'IUIAutomationElement::get_CurrentBoundingRectangle
        vTblOffset = vFuncOrdinal * PTR_LEN
    
        #If Win64 Then
            Dim R As RECT_PTR
            Dim Pt1 As POINTAPI, Pt2 As POINTAPI
            
            lRet = vtblCall(Me.pIElement, vTblOffset, vbLong, CC_STDCALL, VarPtr(R))
            Call CopyMemory(Pt1, ByVal VarPtr(R), PTR_LEN)
            Call CopyMemory(Pt2, ByVal VarPtr(R) + PTR_LEN, PTR_LEN)
            X = Pt1.X: Y = Pt1.Y
            nWidth = Pt2.X - X: nHeight = Pt2.Y - Y
        #Else
            Dim R As RECT
            
            lRet = vtblCall(Me.pIElement, vTblOffset, vbLong, CC_STDCALL, VarPtr(R))
            With R
                X = .Left: Y = .Top
                nWidth = .Right - .Left: nHeight = .Bottom - .Top
            End With
        #End If
    
    End Sub
    
    Private Sub DoDefaultAct()
    
        Const CC_STDCALL = 4&
        Dim lRet As Long, vTblOffset As Long, vFuncOrdinal As Long
        
        vFuncOrdinal = 4& 'IID_IUIAutomationLegacyIAccessiblePattern::DoDefaultAction
        vTblOffset = vFuncOrdinal * PTR_LEN
        lRet = vtblCall(Me.pIPattern, vTblOffset, vbEmpty, CC_STDCALL)
    
    End Sub
    
    Private Sub Select_Item()
    
        Const CC_STDCALL = 4&, SELFLAG_TAKEFOCUS = 1&, SELFLAG_TAKESELECTION = 2&
        Dim lRet As Long, vTblOffset As Long, vFuncOrdinal As Long, selFlag As Long
        
        selFlag = SELFLAG_TAKEFOCUS + SELFLAG_TAKESELECTION
        vFuncOrdinal = 3& 'IUIAutomationLegacyIAccessiblePattern::Select
        vTblOffset = vFuncOrdinal * PTR_LEN
        lRet = vtblCall(Me.pIPattern, vTblOffset, vbLong, CC_STDCALL, selFlag)
    
    End Sub
    
    
    
    ' __________________________________________ Helper Routines _______________________________________________
    
    Private Sub DispGUID(objGuid As GUID)
        Dim lRet As Long, sTmp As String, buf(100&) As Byte
        lRet = StringFromGUID2(objGuid, VarPtr(buf(0&)), UBound(buf) - 1&)
        sTmp = buf
    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
    
    Private Function vtblCall(ByVal InterfacePointer As LongPtr, ByVal VTableOffset As Long, ByVal FunctionReturnType As Long, ByVal CallConvention As Long, ParamArray FunctionParameters() As Variant) As Variant
        Dim vParamPtr() As LongPtr
        Dim pIndex As Long, pCount As Long
        Dim vParamType() As Integer
        Dim vRtn As Variant, vParams() As Variant
    
        vParams() = FunctionParameters()
        pCount = Abs(UBound(vParams) - LBound(vParams) + 1&)
        If pCount = 0& Then
            ReDim vParamPtr(0& To 0&)
            ReDim vParamType(0& To 0&)
        Else
            ReDim vParamPtr(0& To pCount - 1&)
            ReDim vParamType(0& To pCount - 1&)
            For pIndex = 0& To pCount - 1&
                vParamPtr(pIndex) = VarPtr(vParams(pIndex))
                vParamType(pIndex) = VarType(vParams(pIndex))
            Next
        End If
    
         pIndex = DispCallFunc(InterfacePointer, VTableOffset, CallConvention, FunctionReturnType, pCount, vParamType(0&), vParamPtr(0&), vRtn)
    
        If pIndex = 0& Then
            vtblCall = vRtn
        Else
            Call SetLastError(pIndex)
        End If
    End Function
    Last edited by AngelV; Feb 12th, 2024 at 09:37 AM.

  14. #14

    Thread Starter
    Addicted Member
    Join Date
    Jun 2022
    Posts
    202

    Re: Get array data from the array pointer?

    3- IAccElement Interface Class:
    Code:
    Option Explicit
    
    ' ReadOnly Interface.
    
    Property Get Name() As String
        '
    End Property
    
    Property Get Role() As Long
        '
    End Property
    
    Public Property Get Description() As String
       '
    End Property
    
    Public Property Get HelpText() As String
        '
    End Property
    
    Public Property Get State() As Long
        '
    End Property
    
    Public Property Get Value() As String
        '
    End Property
    
    Public Property Get DefaultAction() As String
        '
    End Property
    
    Public Property Get KeyboardShortcut() As String
        '
    End Property
    
    Public Property Get AcceleratorKey() As String
        '
    End Property
    
    Public Property Get ControlType() As Long
        '
    End Property
    
    Public Property Get HasKeyboardFocus() As Boolean
        '
    End Property
    
    Public Property Get IsEnabled() As Boolean
        '
    End Property
    
    Public Property Get ClassName() As String
        '
    End Property
    
    Public Property Get IsOffScreen() As Boolean
        '
    End Property
    
    Public Property Get ItemType() As String
        '
    End Property
    
    Public Property Get ProcessID() As Long
        '
    End Property
    
    Public Property Get LocalControlType() As String
        '
    End Property
    
    Public Property Get Orientation() As String
        '
    End Property
    
    Public Property Get ItemStatus() As Long
        '
    End Property
    
    Public Property Get IsPassword() As Boolean
        '
    End Property
    
    Public Property Get WindowHandle() As LongPtr
        '
    End Property
    
    Public Property Get pIAutomation() As LongPtr
        '
    End Property
    
    Public Property Get pITrueCond() As LongPtr
        '
    End Property
    
    Public Property Get pIElementArray() As LongPtr
        '
    End Property
    
    Public Property Get pIPattern() As LongPtr
        '
    End Property
    
    Public Property Get pIElement() As LongPtr
        '
    End Property
    
    Public Sub DoDefaultAction()
    '
    End Sub
    
    Public Sub SelectMe()
        '
    End Sub
    
    Public Sub GetClickablePoint(ByRef X As Long, ByRef Y As Long)
    '
    End Sub
    
    Public Sub GetScreenBoundingRectangle(ByRef X As Long, ByRef Y As Long, nWidth As Long, nHeight As Long)
    '
    End Sub
    Last edited by AngelV; Feb 12th, 2024 at 09:38 AM.

  15. #15

    Thread Starter
    Addicted Member
    Join Date
    Jun 2022
    Posts
    202

    Re: Get array data from the array pointer?

    4- Test examples:

    Code:
    Option Explicit
    
    #If VBA7 Then
        Private Declare PtrSafe Function SetCursorPos Lib "user32" (ByVal X As Long, ByVal Y As Long) As Long
    #Else
        Private Declare Function SetCursorPos Lib "user32" (ByVal X As Long, ByVal Y As Long) As Long
    #End If
    
    Sub SelectCell_Test()
    
        Dim oParent As C_AccEx
        Dim oChild As IAccElement
        Dim X As Long, Y As Long
        Dim nWidth As Long, nHeight As Long
    
        Set oParent = New C_AccEx
        Call oParent.GetAccessibleChildrenFromHwnd(Application.hwnd, TreeScope_Descendants)
        
        For Each oChild In oParent.Items
            With oChild
                If .Name = "A4" Then
                    .DoDefaultAction
                    .SelectMe
                    .GetScreenBoundingRectangle X, Y, nWidth, nHeight
                    Call SetCursorPos(X, Y)
                    Exit Sub
                End If
            End With
        Next oChild
    
    End Sub
    
    Sub CloseExcel_Test()
    
        Dim oParent As C_AccEx
        Dim oChild As IAccElement
        Dim X As Long, Y As Long
        Dim nWidth As Long, nHeight As Long
        
        Set oParent = New C_AccEx
       Call oParent.GetAccessibleChildrenFromHwnd(Application.hwnd, TreeScope_Descendants)
        
        For Each oChild In oParent.Items
            With oChild
                If .Name = "Close" Then
                    ThisWorkbook.Saved = False
                    .DoDefaultAction
                    .SelectMe
                    .GetClickablePoint X, Y
    '                Call SetCursorPos(X, Y)
                    Exit Sub
                End If
            End With
        Next oChild
    
    End Sub
    
    Sub TreeWalk_Test()
    
        Dim oParent As C_AccEx
        Dim oChild As IAccElement
        Dim i As Long
    
    
        Set oParent = New C_AccEx
        Call oParent.GetAccessibleChildrenFromHwnd(Application.hwnd, TreeScope_Descendants)
        
        If oParent.ElementsCount Then
            For Each oChild In oParent.Items
                With oChild
                    ' Display some element Properties.
                    i = i + 1&
                    Debug.Print i; "- Name: " & .Name & vbTab & "|" & "ClassName: " & .ClassName & _
                    vbTab & "|" & "Role: " & .Role & vbTab & "|" & "ControlType: " & .ControlType & _
                    vbTab & "|" & "DefaultAction: " & .DefaultAction & vbTab & "|" & "Description: " & .Description & _
                    vbTab & "|" & "LocalControlType: " & .LocalControlType & vbTab & "|" & "AcceleratorKey: " & .AcceleratorKey
                    Debug.Print
                End With
            Next oChild
            
            MsgBox "Total elements found : [" & oParent.ElementsCount & "] elements." & vbLf & _
                    vbLf & "Check Immdiate Window for details."
        End If
    
    End Sub
    Last edited by AngelV; Feb 12th, 2024 at 09:38 AM.

  16. #16
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Location
    South Louisiana
    Posts
    11,657

    Re: Get array data from the array pointer?

    Quote Originally Posted by AngelV View Post
    No worries. since the code is quite large and there is a limit to # of characters we can post, I will share the raw code in the next two posts.

    Thanks
    Thank you, I appreciate it!

    Also, just so you know in the future, one thing that some forum members do to get around the post character limit (including myself) is setup a GitHub repository with the code and then just link to the repo. That away not only do they get the code, but it's pretty-printed too.
    "Code is like humor. When you have to explain it, it is bad." - Cory House
    VbLessons | Code Tags | Sword of Fury - Jameram

  17. #17

    Thread Starter
    Addicted Member
    Join Date
    Jun 2022
    Posts
    202

    Re: Get array data from the array pointer?

    Quote Originally Posted by dday9 View Post
    Thank you, I appreciate it!

    Also, just so you know in the future, one thing that some forum members do to get around the post character limit (including myself) is setup a GitHub repository with the code and then just link to the repo. That away not only do they get the code, but it's pretty-printed too.
    Thanks for the pointers

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width