aherrick
aherrick

Reputation: 20179

C# AutomationElement - Get All Tray Icons Including Hidden (Windows 10)

I'm using the following code to attempt to get all Tray Icons, including the ones hidden by Windows 10.

    public static List<AutomationElement> EnumNotificationIcons()
    {
        var data = new List<AutomationElement>();

        foreach (var button in AutomationElement.RootElement.Find(
                        "User Promoted Notification Area").EnumChildButtons())
        {
            data.Add(button);
        }

        foreach (var button in AutomationElement.RootElement.Find(
                      "System Promoted Notification Area").EnumChildButtons())
        {
            data.Add(button);
        }

        var chevron = AutomationElement.RootElement.Find("Notification Chevron");
        if (chevron != null && chevron.InvokeButton())
        {
            foreach (var button in AutomationElement.RootElement.Find(
                               "Overflow Notification Area").EnumChildButtons())
            {
                data.Add(button);
            }
        }

        return data;
    }

However the list returned only includes visible icons. Anything hidden is skipped over. The tray icons hidden aren't being returned.

What am I missing here?

EDIT:

I've updated the code to look like this. Still not pulling in hidden icons. https://blogs.msdn.microsoft.com/oldnewthing/20141013-00/?p=43863

    public static IEnumerable<AutomationElement> EnumNotificationIcons()
    {
        var userArea = AutomationElement.RootElement.Find("User Promoted Notification Area");
        if (userArea != null)
        {
            foreach (var button in userArea.EnumChildButtons())
            {
                yield return button;
            }

            foreach (var button in userArea.GetTopLevelElement().Find("System Promoted Notification Area").EnumChildButtons())
            {
                yield return button;
            }
        }

        var chevron = AutomationElement.RootElement.Find("Notification Chevron");
        if (chevron != null && chevron.InvokeButton())
        {
            foreach (var button in AutomationElement.RootElement.Find("Overflow Notification Area").EnumChildButtons())
            {
                yield return button;
            }
        }
    }

Upvotes: 5

Views: 1725

Answers (1)

aherrick
aherrick

Reputation: 20179

I was able to get this working with the following code. I had to force wait it appears.

    /// <summary>
    /// Enums the notification icons in the Tray.
    /// </summary>
    /// <returns>List of Notification Icons from the Tray.</returns>
    public static IEnumerable<AutomationElement> EnumNotificationIcons()
    {
        var userArea = AutomationElement.RootElement.Find(UINotificationAreaConstants.UserPromotedNotificationArea);
        if (userArea != null)
        {
            foreach (var button in userArea.EnumChildButtons())
            {
                yield return button;
            }

            foreach (var button in userArea.GetTopLevelElement().Find(UINotificationAreaConstants.SystemPromotedNotificationArea).EnumChildButtons())
            {
                yield return button;
            }
        }

        var chevron = AutomationElement.RootElement.Find(UINotificationAreaConstants.NotificationChevron);
        if (chevron != null && chevron.InvokeButton())
        {
            var elm = AutomationElement.RootElement.Find(
                                UINotificationAreaConstants.OverflowNotificationArea);

            WaitForElm(elm);

            foreach (var button in elm.EnumChildButtons())
            {
                yield return button;
            }
        }
    }

    /// <summary>
    /// Waits for elm to be ready for processing.
    /// </summary>
    /// <param name="targetControl">The target control.</param>
    /// <returns>The WindowPattern.</returns>
    private static WindowPattern WaitForElm(AutomationElement targetControl)
    {
        WindowPattern windowPattern = null;

        try
        {
            windowPattern =
                targetControl.GetCurrentPattern(WindowPattern.Pattern)
                as WindowPattern;
        }
        catch (InvalidOperationException)
        {
            // object doesn't support the WindowPattern control pattern
            return null;
        }
        // Make sure the element is usable.
        if (!windowPattern.WaitForInputIdle(10000))
        {
            // Object not responding in a timely manner
            return null;
        }
        return windowPattern;
    }

Upvotes: 3

Related Questions