Search code examples
c++windowsautomationui-automationmicrosoft-ui-automation

How to find UI automation element via UIA_AutomationIdPropertyId


I want to get a group element which is only identifyable by the UIA_AutomationIdPropertyId.

I got the AutomationId from Inspect.exe

So i wrote following function.

IUIAutomationElement* FindBy_UIA_AID(std::wstring UID)
{
    IUIAutomationElement* pElement = nullptr;
    IUIAutomationCondition* condition = nullptr;
    
    VARIANT var{};
    var.bstrVal = SysAllocStringLen(UID.c_str(), UID.size());
    var.vt = VT_BSTR;

    hr = pAutomation->CreatePropertyCondition(UIA_AutomationIdPropertyId, var, &condition);
    if (FAILED(hr))
    {
        std::cout << "Error Creating Condition\n";
        return nullptr;
    }

    hr = MainElement->FindFirst(TreeScope_Subtree, condition, &pElement);
    if (FAILED(hr))
    {
        std::cout << "Error Finding First Occurence\n";
        condition->Release();
        return nullptr;
    }

    condition->Release();
    SysFreeString(var.bstrVal);
    return pElement;
}

but this always return nullptr (but without error). So i looked at Inspect.exe to check if the group is a descendants of my MainElement, which it is. I also wrote another function before which absolutley works fine.

The function does the exact same just searching by UIA_LegacyIAccessibleNamePropertyId. This works and the element found is in same treescope as the element im looking for with .

IUIAutomationElement* FindBy_UIA_NPI(std::wstring name)
{
    IUIAutomationElement* pElement = nullptr;
    IUIAutomationCondition* condition = nullptr;

    VARIANT var{};
    var.bstrVal = SysAllocStringLen(name.c_str(), name.size());
    var.vt = VT_BSTR;

    hr = pAutomation->CreatePropertyCondition(UIA_LegacyIAccessibleNamePropertyId, var, &condition);
    if (FAILED(hr))
    {
        std::cout << "Error Creating Condition\n";
        return nullptr;
    }

    hr = MainElement->FindFirst(TreeScope_Subtree, condition, &pElement);
    if (FAILED(hr))
    {
        std::cout << "Error Finding First Occurence\n";
        condition->Release();
        return nullptr;
    }

    SysFreeString(var.bstrVal);
    condition->Release();

    return pElement;
}

So now i wonder where the issue could be or how to get an element by UIA_AutomationIdPropertyId in another way.

Note. Both of the previous functions are member functions and the class has following valid members

HRESULT hr{};
HWND hwnd{};
IUIAutomation* pAutomation{};
IUIAutomationElement* MainElement{};

EDIT: After manually looping through every descendant of MainElement I found out that many elements have no AutomationID even though in Inspect.exe they do, which is quite weird. Maybe someone knows why this is and how to fix this


Solution

  • After some investigation, I discovered that the issue was with the Inspect.exe tool itself. I had accidentally left it in Raw View mode, which was causing it to show the Raw Tree instead of the Actual Tree which is used by the UI Automation API.

    The element i was looking for was not a Control Element so there is no point in trying to search with FindAll as the IUIAutomationElement::IsControlElement property is set to FALSE.

    To fix the issue, one can either change the mode to Control View or use "IUIAutomationTreeWalker".

    This is also worth taking a look at.