windowsvb.netui-automationspy++

How to get hidden/private UI element from UIAutomation, I can see it in Spy++ but can't get to it in code, only it's parents and siblings


I'm trying to use System.Windows.Automation to get to a UI element in VLC media player (specifically the status box in the left-most corner that shows the filename of the video currently being played). I can get the parent element and a sibling element but in Spy++ all of the elements that have a dimmed icon next to them I cannot reach in code... I'm assuming that dimmed icon means they are private or hidden or something like that. Here is an image showing what I mean:

enter image description here

Notice that I have a reference to the parent with the handle 0x30826, and I do a FindAll()* from that and end up with only one result, a reference to the child with the handle 0x30858. You can see in Spy++ there are 5 children of 0x30826, but only one of them, the one that I get when I do FindAll, has a fully black icon, the others have a gray icon and I cannot get to them. Notice also that the one I want is 0x20908 and it has a grey icon...

How can I get to this in code?

*This is the code I'm using to try to get all the children of 0x30826:

    Dim aeDesktop As AutomationElement
    Dim aeVLC As AutomationElement
    Dim c As AutomationElementCollection
    Dim cd As New AndCondition(New PropertyCondition(AutomationElement.IsEnabledProperty, True), New PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.StatusBar))

    aeVLC = aeDesktop.FindFirst(TreeScope.Children, New PropertyCondition(AutomationElement.NameProperty, "got s01e01.avi - VLC media player"))

    c = aeVLC.FindAll(TreeScope.Children, cd)

    c = c(0).FindAll(TreeScope.Children, Condition.TrueCondition)

The first FindAll() gives me only 0x30826, which is fine because that's what I want, but the second FindAll, with no conditions specified, gives only 0x30858 when I can see that plus 4 others in Spy++, including the one that I want.


Solution

  • You are really handicapping your efforts by using Spy++ instead of the Inspect Program. Using Inspect, you can easily see that the target element is a text element parented to a status bar element that is parented to the main window element.

    VLC in Inspect

    Using that information, getting a reference to the target text element is straight forward. Start by getting the main window, then its status bar and finally the first text element of the status bar.

    ' find the VLC process 
    Dim targets As Process() = Process.GetProcessesByName("vlc")
    
    If targets.Length > 0 Then
    
        ' assume its the 1st process 
        Dim vlcMainWindowHandle As IntPtr = targets(0).MainWindowHandle
    
        ' release all processes obtained
        For Each p As Process In targets
            p.Dispose()
        Next
    
        ' use vlcMainWindowHandle to get application window element
        Dim vlcMain As AutomationElement = AutomationElement.FromHandle(vlcMainWindowHandle)
    
        ' get the statusbar
        Dim getStatusBarCondition As Condition = New PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.StatusBar)
        Dim statusBar As AutomationElement = vlcMain.FindFirst(TreeScope.Children, getStatusBarCondition)
    
        ' get the 1st textbox in the statusbar
        Dim getTextBoxCondition As Condition = New PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Text)
        Dim targetTextBox As AutomationElement = statusBar.FindFirst(TreeScope.Children, getTextBoxCondition)
    
        ' normally you use either a TextPattern.Pattern or ValuePattern.Pattern
        ' to obtain the text, but this textbox exposes neither and it uses the
        ' the Name property for the text.
    
        Dim textYouWant As String = targetTextBox.Current.Name
    
    End If