Code Snippet
// your using statements may differ
using System.Diagnostics;
using System.Threading;
using System.Windows.Automation;
using System.Runtime.InteropServices;
namespace foo
{
class bar
{
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
//Search for a elment just by name starting from root
private static AutomationElement GetElement(AutomationElement root, string name, bool recursive)
{
PropertyCondition condName = new PropertyCondition(AutomationElement.NameProperty, name);
return root.FindFirst(recursive ? TreeScope.Descendants : TreeScope.Children, condName);
}
//Search for the first occurance of a given type of control
private static AutomationElement GetElement(AutomationElement root, ControlType controlType)
{
PropertyCondition condType = new PropertyCondition(AutomationElement.ControlTypeProperty, controlType);
return root.FindFirst(TreeScope.Descendants, condType);
}
static void Main(string[] args)
{
ProcessStartInfo psInfo = new ProcessStartInfo(@"C:\foo\bar\baz.exe");
Process prov = Process.Start(psInfo);
Thread.Sleep(1000);
// get the system tray item
AutomationElement aeTray = GetElement(AutomationElement.RootElement, "Baz", true);
InvokePattern ipTrayClick = (InvokePattern)aeTray.GetCurrentPatter(InvokePattern.Pattern);
// Here we just double click to bring the tray item UI to the foreground.
// Future Note to Self: Context Menu controls are children of the Desktop.
ipTrayClick.Invoke();
ipTrayClick.Invoke();
// get the form for the UI and button control
AutomationElement aeBazForm = GetElement(AutomationElement.RootElement, "Baz-o-matic", true);
AutomationElement aeButtonGroup = GetElement(aeBazForm, "ModalGroup", true);
AutomationElement aeModalButton = GetElement(aeButtonGroup, "SpawnModal", true);
// create the pattern and then spin it into a non-blocking thread
InvokePattern ipSpawnModalButton = (InvokePattern)aeModalButton.GetCurrentPattern(InvokePattern.Pattern);
ThreadStart tsInvokeModalDelegate = new ThreadStart(ipSpawnModalButton.Invoke);
Thread tModal = new Thread(tsInvokeModalDelegate);
tModal.Start();
// this is a silly kludge which you probably won't need
Thread.Sleep(500);
// This works because the modal form when opened has foreground focus
// by default. This may not be the case in everyones situations. YMMV.
AutomationElement aeModalForm = AutomationElement.FromHandle(GetForegroundWindow());
/* At this point you should be able to read over the controls present
in the form. A caveat however: when spinning this new thread and
invoking the desired pattern. This will make that new Modal Form
"invisible" from tools like UISpy. When manually closed, and then
manually Invoked (from the same thread) the Modal Form will be
present as a child of the parent form. That might complicate and
annoy while developing your automation. The discovery of controls or
elements within the child Modal Form should be as normal by the
FindFirst() and FindAll() methods. Just FYI. */
// close the Modal, this sample code is done.
AutomationElement aeModalTitleBar = GetElement(aeModalForm, ControlType.TitleBar);
AutomationElement aeCloseExitButton = GetElement(aeModalTitleBar, "Close", true);
// invoke the close, we're done
InvokePattern ipCloseButtonClick = (InvokePattern)aeCloseExitbutton.GetCurrentPattern(InvokePattern.Pattern);
ipCloseButtonClick.Invoke();
}
}
}