Search code examples
c++winapiui-automation

How to get LegacyIAccessible data using UiAutomation?


I'm trying to get the LegacyIAccessible values marked on the picture below:

enter image description here

So far I have been able to read these:

#include <UIAutomation.h> // UIAutomation includes.
#include <UIAutomationCore.h>
#include <UIAutomationClient.h>
#include "Oleacc.h"
#include "atlbase.h"
#pragma comment(lib,"Oleacc.lib")

LPCWSTR Acc(HWND hwnd) {

    CComPtr<IUIAutomation> pUIAutomation;
    CoInitialize(NULL);
    HRESULT hr = CoCreateInstance(__uuidof(CUIAutomation), NULL, CLSCTX_INPROC_SERVER, __uuidof(IUIAutomation), (void**)&pUIAutomation);
    if (SUCCEEDED(hr))
    {
        IUIAutomationElement* pRoot = NULL;
        hr = pUIAutomation->ElementFromHandle(hwnd, &pRoot);
        if (SUCCEEDED(hr))
        {
            IUIAutomationElementArray* pElementArray = nullptr;
            IUIAutomationCondition* pCondition;
            hr = pUIAutomation->CreateTrueCondition(&pCondition);
            IUIAutomationElementArray* pEA;
            IUIAutomationCacheRequest* pCacheRequest;
            hr = pUIAutomation->CreateCacheRequest(&pCacheRequest);
            pCacheRequest->AddProperty(UIA_NamePropertyId);
            pCacheRequest->AddProperty(UIA_AutomationIdPropertyId);
            pCacheRequest->AddProperty(UIA_LocalizedControlTypePropertyId);
            //pCacheRequest->put_TreeScope((TreeScope)(TreeScope_Element | TreeScope_Descendants));
            hr = pRoot->FindAllBuildCache(TreeScope_Descendants, pCondition, pCacheRequest, &pEA);
            if (SUCCEEDED(hr))
            {
                int nNbItems = 0;
                hr = pEA->get_Length(&nNbItems);
                for (int nItem = 0; nItem <= nNbItems - 1; nItem++)
                {
                    IUIAutomationElement* pElement = nullptr;
                    hr = pEA->GetElement(nItem, &pElement);

                    BSTR name;
                    pElement->get_CurrentName(&name);

                    UIA_HWND uia_hwnd = nullptr;
                    pElement->get_CurrentNativeWindowHandle(&uia_hwnd);

                    BSTR classname = nullptr;
                    pElement->get_CurrentClassName(&classname);
                    
                    RECT rect;
                    pElement->get_CurrentBoundingRectangle(&rect);
        
                    pElement->Release();
                }
            }

            pCacheRequest->Release();
            pCondition->Release();
            pRoot->Release();
        }

        
        //pUIAutomation->Release();   // <- needed?
    }


    CoUninitialize();
    return (L"SUCCEEDED");
}

When I try to call for:

    DWORD CurrentState;
    pElement->get_CurrentState(&CurrentState);

I get this error: class "IUIAutomationElement" has no member "get_CurrentState".

I think I should be using IUIAutomationLegacyIAccessiblePattern but I couldn't figure out how to properly rewrite the function using it.

Also, what's the difference between the functions with and without 'cache'?


Solution

  • A example of GetCurrentPatternAs. Caching is not involved.

    #include <Windows.h>
    #include <UIAutomation.h>
    #include <wchar.h>
    
    int Element(IUIAutomation* automation)
    {
        // Get the element under the cursor
    // Use GetPhysicalCursorPos to interact properly with
    // High DPI
        POINT pt;
        GetPhysicalCursorPos(&pt);
    
        IUIAutomationElement* pAtMouse;
        HRESULT hr = automation->ElementFromPoint(pt, &pAtMouse);
        if (FAILED(hr))
            return hr;
    
        // Get the element's name and print it
        BSTR name;
        hr = pAtMouse->get_CurrentName(&name);
        if (SUCCEEDED(hr))
        {
            wprintf(L"Element's Name: %s \n", name);
            SysFreeString(name);
    
            //IUIAutomationValuePattern* pattern;
            //pAtMouse->GetCurrentPatternAs(UIA_ValuePatternId, IID_IUIAutomationValuePattern,(void**)&pattern);
            IUIAutomationLegacyIAccessiblePattern* pattern;
            
            //pAtMouse->GetCurrentPatternAs(UIA_LegacyIAccessiblePatternId, IID_IUIAutomationLegacyIAccessiblePattern,(void**)&pattern);
            pAtMouse->GetCurrentPatternAs(UIA_LegacyIAccessiblePatternId, IID_PPV_ARGS(&pattern));
            //TODO
            BSTR url = nullptr;
            pattern->get_CurrentValue(&url);
            DWORD state = 0;
            pattern->get_CurrentState(&state);
            BSTR elename = nullptr;
            pattern->get_CurrentName(&elename);
            DWORD role = 0;
            pattern->get_CurrentRole(&role);
            //wprintf(L"Element's ValuePattern: %s \n", url);
            SysFreeString(url);
            SysFreeString(elename);
        }
    
        // Get the element's Control Type (in the current languange)
        // and print it
        BSTR controlType;
        hr = pAtMouse->get_CurrentLocalizedControlType(&controlType);
        if (SUCCEEDED(hr))
        {
            wprintf(L"Element's Control Type: %s \n", controlType);
            SysFreeString(controlType);
        }
    
        // Clean up our COM pointers
        pAtMouse->Release();
        return hr;
    }
    
    int main(int argc, TCHAR* argv[])
    {
        // Initialize COM and create the main Automation object
        IUIAutomation* g_pAutomation;
        CoInitialize(NULL);
        HRESULT hr = CoCreateInstance(__uuidof(CUIAutomation), NULL,
            CLSCTX_INPROC_SERVER, __uuidof(IUIAutomation),
            (void**)&g_pAutomation);
        if (FAILED(hr))
            return (hr);
    
        bool quit = false;
        while (!quit)
        {
            SHORT leftControlMod = GetAsyncKeyState(VK_LCONTROL);
            if (leftControlMod != 0)
            {
                Element(g_pAutomation);
            }
            quit = GetAsyncKeyState(VK_ESCAPE);
        }
    
        g_pAutomation->Release();
        CoUninitialize();
        return 0;
    }
    

    enter image description here