In C# or else VB.Net, how I could use Microsoft UI Automation to retrieve the text of any control that contains text?.
I've been researching in the MSDN Docs, but I don't get it.
Obtain Text Attributes Using UI Automation
Then, for example, with the code below I'm trying to retrieve the text of the Window titlebar by giving the hwnd of that window, but I don't know exactlly how to follow the titlebar to find the child control (label?) that really contains the text.
Imports System.Windows.Automation
Imports System.Windows.Automation.Text
.
Dim hwnd As IntPtr = Process.GetProcessesByName("notepad").First.MainWindowHandle
Dim targetApp As AutomationElement = AutomationElement.FromHandle(hwnd)
' The control type we're looking for; in this case 'TitleBar'
Dim cond1 As New PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TitleBar)
Dim targetTextElement As AutomationElement =
targetApp.FindFirst(TreeScope.Descendants, cond1)
Debug.WriteLine(targetTextElement Is Nothing)
In the example above I'm trying with the titlebar, but just I would like to do it with any other control that contains text ...like a titlebar.
PS: I'm aware of P/Invoking GetWindowText
API.
With UI Automation, in general, you have to analyze the target application using the SDK tools (UISpy or Inspect - make sure it's Inspect 7.2.0.0, the one with a tree view).
So here for example, when I run notepad, I run inspect and see this:
I see the titlebar is a direct child of the main window, so I can just query the window tree for direct children and use the TitleBar control type as a discriminant because there's no other child of that type beneath the main window.
Here is a sample console app C# code that demonstrate how to get that 'Untitled - Notepad' title. Note the TitleBar also supports the Value pattern but we don't need here because the titlebar's name is also the value.
class Program
{
static void Main(string[] args)
{
// start our own notepad from scratch
Process process = Process.Start("notepad.exe");
// wait for main window to appear
while(process.MainWindowHandle == IntPtr.Zero)
{
Thread.Sleep(100);
process.Refresh();
}
var window = AutomationElement.FromHandle(process.MainWindowHandle);
Console.WriteLine("window: " + window.Current.Name);
// note: carefully choose the tree scope for perf reasons
// try to avoid SubTree although it seems easier...
var titleBar = window.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TitleBar));
Console.WriteLine("titleBar: " + titleBar.Current.Name);
}
}