1

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.

Idle_Mind
  • 38,363
  • 3
  • 29
  • 40
CHollman82
  • 576
  • 1
  • 8
  • 28

1 Answers1

1

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
TnTinMn
  • 11,522
  • 3
  • 18
  • 39
  • Thank you, I awarded you the bounty even though it doesn't quite work for me. Breaking on the last line "targetTextBox" equals nothing. – CHollman82 Apr 04 '19 at 13:43
  • Nevermind, I had to restart VLC for some reason and then it worked, but it found the textbox containing the time index so I had to use FindAll instead of FindFirst. Thanks again! – CHollman82 Apr 04 '19 at 13:57
  • @CHollman82, the joys of scrapping information and trying to build in resiliency. I guess that you could assume that it would be the left most text element and use something like this: `Dim targetTextBox As AutomationElement = Enumerable.OrderBy(statusBar.FindAll(TreeScope.Children, getTextBoxCondition).Cast(Of AutomationElement), Function(el) el.Current.BoundingRectangle.Left).FirstOrDefault` – TnTinMn Apr 04 '19 at 15:01