UIAutomation failing to find child nodes

729 views Asked by At

Trying to automate IIS (INetMgr) trying to use UIAutomation, i'm fixing mixed results. I'm able to get some if the screen elements good fine, others, even immediate children nodes, can't get either with a Find[First|All] or try in a treewalker (content|control|raw), just can't get the node(s) needed. Any suggestion what to use for driving the UI to automate it?

Window 10/11 desktop environment.

1

There are 1 answers

2
Simon Mourier On

Here is a C# Console app that dumps (max 2 levels) of InetMgr's items from the "Connections" pane.

This must be started as Administrator otherwise it will fail (not immediately). In general UIA clients must run at same UAC level as automated apps.

To determine what to get from the tree or if something can be done, before any coding, we can use the Inspect tool from Windows SDK or the more recent Accessibility Insights.

Also, I use Windows' UIAutomationClient COM object, not the old one from Windows XP era as it misses lots of stuff.

The code iterates all tree items recursively and expand them if they are not expanded using the ExpandCollapse Control Pattern because InetMgr's tree has a lazy loading behavior as it can potentially contains hundreds of thousands of items (mapped to disk folders at some points).

class Program
{
    // add a COM reference to UIAutomationClient (don't use .NET legacy UIA .dll)
    private static readonly CUIAutomation8 _automation = new CUIAutomation8(); // using UIAutomationClient;

    static void Main()
    {
        var process = Process.GetProcessesByName("InetMgr").FirstOrDefault();
        if (process == null)
        {
            Console.WriteLine("InetMgr not started.");
            return;
        }

        var inetmgr = _automation.ElementFromHandle(process.MainWindowHandle);
        if (inetmgr == null)
            return;

        // note: set "Embed Interop Type" to false in UIAutomationClient reference node or redefine all UIA_* used constants manually
        // also: you *must* this program as administrator to see this panel
        var connections = inetmgr.FindFirst(TreeScope.TreeScope_Subtree,
            _automation.CreatePropertyCondition(UIA_PropertyIds.UIA_AutomationIdPropertyId, "_hierarchyPanel"));
        if (connections == null)
            return;

        var treeRoot = connections.FindFirst(TreeScope.TreeScope_Subtree,
            _automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_TreeItemControlTypeId));

        Dump(0, treeRoot);
    }

    static void Dump(int indent, IUIAutomationElement element)
    {
        var s = new string(' ', indent);
        Console.WriteLine(s + "name: " + element.CurrentName);

        // get expand/collapse pattern. All treeitem support that
        var expandPattern = (IUIAutomationExpandCollapsePattern)element.GetCurrentPattern(UIA_PatternIds.UIA_ExpandCollapsePatternId);
        if (expandPattern != null && expandPattern.CurrentExpandCollapseState != ExpandCollapseState.ExpandCollapseState_Expanded)
        {
            try
            {
                expandPattern.Expand();
            }
            catch
            {
                // cannot be expanded
            }
        }

        // tree can be huge,only dump 2 levels max
        if (indent > 2)
            return;

        var children = element.FindAll(TreeScope.TreeScope_Children, _automation.CreateTrueCondition());
        for (var i = 0; i < children.Length; i++)
        {
            Dump(indent + 1, children.GetElement(i));
        }
    }
}