using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; using System.Windows.Automation; using System.Windows.Forms; using System.Threading; namespace SWACalculatorExample { class Program { static void Main(string[] args) { IntPtr calculatorWindowHandle = LaunchCalculatorAndReturnWindowHandle(); //Here I use a window handle to get an AutomationElement for a specific window. AutomationElement calculatorElement = AutomationElement.FromHandle(calculatorWindowHandle); ThrowIfElementIsNull(calculatorElement, "calculator window"); PrintElementInfo(calculatorElement); //Grabs the main edit box from the calculator. PropertyCondition editBoxAutomationIDProperty = new PropertyCondition(AutomationElement.AutomationIdProperty, "403"); AutomationElement editBoxElement = calculatorElement.FindFirst(TreeScope.Descendants, editBoxAutomationIDProperty); ThrowIfElementIsNull(editBoxElement, "edit box"); PrintElementInfo(editBoxElement); //This won't work here because the calculator text box is read-only. On a non-read-only box, this would have worked. //ValuePattern editBoxValuePattern = (ValuePattern)editBoxElement.GetCurrentPattern(ValuePattern.Pattern); //editBoxValuePattern.SetValue("6"); //Since the direct ValuePattern method didn't work, this is Plan B, using SendKeys. //Type "6". editBoxElement.SetFocus(); SendKeys.SendWait("6"); //Press the multiplication button. InvokeChildButtonByName(calculatorElement, "*"); //Sleeps should be avoided whereever possible in automation code. //In some cases, however, they're useful as a quick fix to a timing issue. //Still, you should look for a better way to make sure an action is complete. Thread.Sleep(100); //Then type "9". editBoxElement.SetFocus(); SendKeys.SendWait("9"); //Press the equals button. InvokeChildButtonByName(calculatorElement, "="); //Now read the result from the calculator text box. ValuePattern editBoxValuePattern = (ValuePattern)editBoxElement.GetCurrentPattern(ValuePattern.Pattern); string editBoxResult = editBoxValuePattern.Current.Value; Console.WriteLine("The answer: {0}", editBoxResult); //Get the WindowPattern from the window and use it to close the calculator app. WindowPattern calculatorWindowPattern = (WindowPattern)calculatorElement.GetCurrentPattern(WindowPattern.Pattern); calculatorWindowPattern.Close(); Console.WriteLine("Done!"); Console.Read(); } #region SWA Helpers //Walks some of the more interesting properties on the AutomationElement. public static void PrintElementInfo(AutomationElement element) { Console.WriteLine("--------Element"); Console.WriteLine("AutomationId: {0}", element.Current.AutomationId); Console.WriteLine("Name: {0}", element.Current.Name); Console.WriteLine("ClassName: {0}", element.Current.ClassName); Console.WriteLine("ControlType: {0}", element.Current.ControlType.ProgrammaticName); Console.WriteLine("IsEnabled: {0}", element.Current.IsEnabled); Console.WriteLine("IsOffscreen: {0}", element.Current.IsOffscreen); Console.WriteLine("ProcessId: {0}", element.Current.ProcessId); //Commented out because it requires another library reference. //Console.WriteLine("BoundingRectangle: {0}", element.Current.BoundingRectangle); Console.WriteLine("Supported Patterns:"); foreach (AutomationPattern supportedPattern in element.GetSupportedPatterns()) { Console.WriteLine("\t{0}", supportedPattern.ProgrammaticName); } } public static void ThrowIfElementIsNull(AutomationElement element, string name) { if (element == null) { throw new Exception("Uh-oh, couldn't find the " + name + "..."); } } public static void InvokeChildButtonByName(AutomationElement parentElement, string name) { //Grab a button by name, then click on it. AutomationElement buttonElement = parentElement.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, name)); InvokePattern buttonInvokePattern = (InvokePattern)buttonElement.GetCurrentPattern(InvokePattern.Pattern); buttonInvokePattern.Invoke(); } #endregion SWA Helpers #region Non SWA Helpers //Launches the Windows Calculator and returns the Main Window's Handle. public static IntPtr LaunchCalculatorAndReturnWindowHandle() { Process calculatorProcess = Process.Start("calc.exe"); calculatorProcess.WaitForInputIdle(); return calculatorProcess.MainWindowHandle; } #endregion Non SWA Helpers } }