public override UIHandlerAction HandleWindow(IntPtr topLevelhWnd, IntPtr hwnd, Process process, string title, UIHandlerNotification notification) { GlobalLog.LogDebug("Appearance settings window found."); AutomationElement window = AutomationElement.FromHandle(topLevelhWnd); GlobalLog.LogDebug("Finding Color Scheme combo box and selecting correct value."); Condition cond = new PropertyCondition(AutomationElement.AutomationIdProperty, "1114"); AutomationElement colorSchemeComboBox = window.FindFirst(TreeScope.Descendants, cond); // This gets us to the vertical scroll bar AutomationElement item = TreeWalker.ControlViewWalker.GetFirstChild(colorSchemeComboBox); // This gets us to the first item in the list item = TreeWalker.ControlViewWalker.GetNextSibling(item); // On systems which support DWM composition, the first item will be either // "Windows Vista Aero" or "Windows Vista Standard" (depending on the SKU). // The second item will be "Windows Vista Basic". // "Windows Vista Aero" features both DWM composition and glass. // "Windows Vista Standard" features DWM composition but no glass. // "Windows Vista Basic" does not feature DWM composition or glass. // No machine will ever support both Aero and Standard. All machines support Basic. // If this machine supports composition, but we want to turn it off, // we need to move to the second item in the list, "Windows Vista Basic". // Otherwise, we select the first item, either because composition is supported // and we want it enabled, or it is not supported. if (IsDwmCompositionSupported && newAppearance == DesktopAppearance.AeroWithoutComposition) { item = TreeWalker.ControlViewWalker.GetNextSibling(item); } object patternObject; item.TryGetCurrentPattern(SelectionItemPattern.Pattern, out patternObject); SelectionItemPattern selectionItemPattern = patternObject as SelectionItemPattern; selectionItemPattern.Select(); // HACK: On recent builds of Vista, UI Automation does not seem to properly // notify the dialog that the selection has changed. This message is normally // sent by the combo box to the dialog. IntPtr wParam = MakeWParam(1114, CBN_SELCHANGE); SendMessage(hwnd, WM_COMMAND, wParam, new IntPtr((int)colorSchemeComboBox.GetCurrentPropertyValue(AutomationElement.NativeWindowHandleProperty))); GlobalLog.LogDebug("Finding and clicking the OK Button"); cond = new PropertyCondition(AutomationElement.AutomationIdProperty, "1"); AutomationElement okBtn = window.FindFirst(TreeScope.Descendants, cond); okBtn.TryGetCurrentPattern(InvokePattern.Pattern, out patternObject); InvokePattern invokePattern = patternObject as InvokePattern; invokePattern.Invoke(); GlobalLog.LogDebug("Waiting for appearance to be applied..."); process.WaitForExit(); return(UIHandlerAction.Abort); }
public override UIHandlerAction HandleWindow(IntPtr topLevelhWnd, IntPtr hwnd, Process process, string title, UIHandlerNotification notification) { GlobalLog.LogDebug("Display Configuration window found."); AutomationElement window = AutomationElement.FromHandle(topLevelhWnd); // get a reference the address bar GlobalLog.LogDebug("Finding and clicking the OK Button"); Condition cond = new PropertyCondition(AutomationElement.AutomationIdProperty, "1"); AutomationElement okBtn = window.FindFirst(TreeScope.Descendants, cond); object patternObject; okBtn.TryGetCurrentPattern(InvokePattern.Pattern, out patternObject); InvokePattern invokePattern = patternObject as InvokePattern; invokePattern.Invoke(); GlobalLog.LogDebug("Waiting for theme to be applied..."); process.WaitForExit(); return(UIHandlerAction.Abort); }
public override UIHandlerAction HandleWindow(IntPtr topLevelhWnd, IntPtr hwnd, Process process, string title, UIHandlerNotification notification) { GlobalLog.LogDebug("Display Properties (Appearance tab) window found."); AutomationElement window = AutomationElement.FromHandle(topLevelhWnd); GlobalLog.LogDebug("Finding Color Scheme combo box and selecting '" + resourceString + "'."); Condition cond = new PropertyCondition(AutomationElement.AutomationIdProperty, "1114"); AutomationElement colorSchemeCombo = window.FindFirst(TreeScope.Descendants, cond); cond = new PropertyCondition(AutomationElement.NameProperty, resourceString); AutomationElement item = colorSchemeCombo.FindFirst(TreeScope.Descendants, cond); // Tell the correct combobox item to be selected object patternObject; item.TryGetCurrentPattern(SelectionItemPattern.Pattern, out patternObject); SelectionItemPattern selectionItemPattern = patternObject as SelectionItemPattern; selectionItemPattern.Select(); GlobalLog.LogDebug("Finding and clicking the OK Button"); cond = new PropertyCondition(AutomationElement.AutomationIdProperty, "1"); AutomationElement okBtn = window.FindFirst(TreeScope.Descendants, cond); okBtn.TryGetCurrentPattern(InvokePattern.Pattern, out patternObject); InvokePattern invokePattern = patternObject as InvokePattern; invokePattern.Invoke(); GlobalLog.LogDebug("Waiting for appearance to be applied..."); process.WaitForExit(); return(UIHandlerAction.Abort); }
public override UIHandlerAction HandleWindow(IntPtr topLevelhWnd, IntPtr hwnd, System.Diagnostics.Process process, string title, UIHandlerNotification notification) { // Sleep for a bit. Need to give the FF window a chance to render the address bar. Thread.Sleep(1000); // NOT SUPPORTED return(UIHandlerAction.Unhandled); }
/// <summary> /// HandleWindow /// </summary> /// <param name="topHwnd"></param> /// <param name="hwnd"></param> /// <param name="process"></param> /// <param name="title"></param> /// <param name="notification"></param> /// <returns></returns> public override UIHandlerAction HandleWindow(System.IntPtr topHwnd, System.IntPtr hwnd, System.Diagnostics.Process process, string title, UIHandlerNotification notification) { ILog log = null; FileStream f = null; try { // create a log log = LogFactory.Create(); log.StatusMessage = "CustomUIHandler invoked"; // wait when invoked; allow UIA properties to get in sync with Win32 Thread.Sleep(1000); // get a stream to the script file f = new FileStream(ScriptFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); // process the script file with the requested handler switch (Handler) { case HandlerID.Scripter: { S.Scripter script = new S.Scripter(f, log); } break; default: { UIScript script = new UIScript(f, topHwnd, log); script.Execute(); } break; } // we got here. it means script was executed with no exceptions if (String.Compare(SetPassWhenDone, Boolean.TrueString, true, CultureInfo.InvariantCulture) == 0) { log.PassMessage = "Test Passed. Script executed with no exceptions and setting result was requested"; } else if (String.Compare(SetPassWhenDone, Boolean.FalseString, true, CultureInfo.InvariantCulture) == 0) { log.StatusMessage = "CustomUIHandler done - not setting result"; } else { log.FailMessage = "Invalid 'SetPassWhenDone' property value specified"; } // end handler return(UIHandlerAction.Abort); } catch (Exception e) { if (log != null) { log.FailMessage = "Exception caught in the UIHandler: " + e.ToString(); } // end handler return(UIHandlerAction.Abort); } finally { // close the stream file if it was successfully created if (f != null) { f.Close(); } log.StatusMessage = "CustomUIHandler finished"; } }
public override UIHandlerAction HandleWindow(IntPtr topLevelhWnd, IntPtr hwnd, System.Diagnostics.Process process, string title, UIHandlerNotification notification) { // Sleep for a bit. Takes a bit longer for window to be ready in Longhorn. Thread.Sleep(800); // Get a reference to the IE window... GlobalLog.LogDebug("Finding IE window"); AutomationElement ieWindow = AutomationElement.FromHandle(topLevelhWnd); if (ApplicationDeploymentHelper.GetIEVersion() >= 8) { GlobalLog.LogDebug("IE8+ present, using IWebBrowser2 Navigate() for reliability"); Thread.Sleep(3000); // Other approaches are fine until they meet LCIE. // IF this proves to be 100% reliable, this could be the only implementation. IENavigationHelper.NavigateInternetExplorer(uriToNavigate.ToString(), process.MainWindowHandle); } else { NavigateIEWindow(ieWindow, uriToNavigate); } return(UIHandlerAction.Unhandled); }
/// <summary> /// Handles Browser Application error messages. Currently just logs the text, so if other UIHandlers are there they can still execute. /// This will cause exception tests to time out instead of logging failure... we can change that easily later. /// </summary> /// <param name="topLevelhWnd"></param> /// <param name="hwnd"></param> /// <param name="process"></param> /// <param name="title"></param> /// <param name="notification"></param> /// <returns></returns> public override UIHandlerAction HandleWindow(IntPtr topLevelhWnd, IntPtr hwnd, System.Diagnostics.Process process, string title, UIHandlerNotification notification) { // //AutomationElement moreInfoButton = IEWindow.FindFirst(TreeScope.Subtree, // new PropertyCondition(AutomationElement.NameProperty, ApplicationDeploymentHelper.ErrorPageMoreInfo)); //if (moreInfoButton == null) //{ // // if it's not showing for the "correct" name, try falling back to english // moreInfoButton = IEWindow.FindFirst(TreeScope.Subtree, // new PropertyCondition(AutomationElement.NameProperty, "More Information")); //} //// If the registry key is set, the error details will be shown automatically. //// Then the button will read "Less Information". //if (moreInfoButton == null) //{ // moreInfoButton = IEWindow.FindFirst(TreeScope.Subtree, // new PropertyCondition(AutomationElement.NameProperty, ApplicationDeploymentHelper.ErrorPageLessInfo)); // if (moreInfoButton == null) // { // IntPtr errorHwnd = Win32Helper.GetErrorPageHwnd(); // if (errorHwnd == IntPtr.Zero) // { // GlobalLog.LogEvidence("Could not find the More Information button.... "); // return UIHandlerAction.Unhandled; // } // else // { // Guid IID_IHTMLDocument = new Guid("626FC520-A41E-11CF-A731-00A0C9082637"); // HTMLDocument IEDomFromhWnd; // int ret1 = Win32Helper.RegisterWindowMessage("WM_HTML_GETOBJECT"); // if (ret1 == 0) // { // GlobalLog.LogEvidence("Failed to RegisterWindowMessage for WM_HTML_GETOBJECT\n"); // return UIHandlerAction.Unhandled; // } // int lRes = 0; // int ret2 = Win32Helper.SendMessageTimeout(errorHwnd, ret1, 0, 0, 2 /*abort if hung*/, 1000, out lRes); // if (ret2 == 0) // { // GlobalLog.LogEvidence("Failed to SendMessage to IE\n"); // return UIHandlerAction.Unhandled; // } // int hr = Win32Helper.ObjectFromLresult(lRes, ref IID_IHTMLDocument, 0, out IEDomFromhWnd); // if (hr != 0) // { // GlobalLog.LogEvidence("ObjectFromLresult Failed with hr: " + hr + "\n"); // return UIHandlerAction.Unhandled; // } // int ieVer = IEHelper.GetIEVersion(); // IHTMLDocument3 doc3 = (IHTMLDocument3)IEDomFromhWnd; // IHTMLElementCollection kids = doc3.getElementsByName((ieVer == 6) ? "toggleButton" : "infoSwitch"); // IHTMLElement infoSw = (IHTMLElement)kids.Item((ieVer == 6) ? "toggleButton" : "infoSwitch", 0); // if (infoSw.innerText.Contains(ApplicationDeploymentHelper.ErrorPageMoreInfo)) // { // infoSw.Click(); // //it didn't seem to need this on my test box but just to be safe, wait a bit // Thread.Sleep(1000); // } // kids = doc3.getElementsByName((ieVer == 6) ? "detailsText" : "errorInfo"); // IHTMLElement errorWindow = (IHTMLElement)kids.Item((ieVer == 6) ? "detailsText" : "errorInfo", 0); // string errorText = errorWindow.innerText; // GlobalLog.LogEvidence("Logging (and NOT setting result to fail) Browser Application Error... "); // GlobalLog.LogEvidence(" ***** BEGIN Error Log: ***** \n"); // GlobalLog.LogEvidence(errorText); // GlobalLog.LogEvidence("\n ***** END Error Log: ***** \n"); // return UIHandlerAction.Unhandled; // } // } //} //else //{ // switch (ApplicationDeploymentHelper.GetIEVersion()) // { // case 6: // InvokePattern ip = moreInfoButton.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern; // ip.Invoke(); // break; // case 7: // System.Windows.Rect r = (System.Windows.Rect)moreInfoButton.GetCurrentPropertyValue(AutomationElement.BoundingRectangleProperty); // double horizMidPt = r.Left + ((r.Right - r.Left) / 2.0); // double vertMidPt = r.Top + ((r.Bottom - r.Top) / 2.0); // MTI.Input.SendMouseInput(horizMidPt, vertMidPt, 0, MTI.SendMouseInputFlags.Absolute | MTI.SendMouseInputFlags.LeftDown | MTI.SendMouseInputFlags.Move); // MTI.Input.SendMouseInput(horizMidPt, vertMidPt, 0, MTI.SendMouseInputFlags.Absolute | MTI.SendMouseInputFlags.LeftUp | MTI.SendMouseInputFlags.Move); // break; // // 8 and 9 are currently the same as IE7... // default: // goto case 7; // } // // Sleep a couple seconds to let the name on the button change... // Thread.Sleep(2000); // if (moreInfoButton.Current.Name != ApplicationDeploymentHelper.ErrorPageLessInfo) // { // GlobalLog.LogEvidence("The More Information button did not toggle: \n"); // GlobalLog.LogEvidence("Value: " + moreInfoButton.Current.Name + " Expected: " + ApplicationDeploymentHelper.ErrorPageMoreInfo); // return UIHandlerAction.Unhandled; // } //} //// Getting to the error details text box: It's a child of the More Info button's parent. //// (IEWindow has many text boxes, so the search must be limited.) //AutomationElement elem = TreeWalker.RawViewWalker.GetParent(moreInfoButton); //AutomationElement errorDetailsElem = GetErrorDetails(moreInfoButton); //if (errorDetailsElem == null) //{ // GlobalLog.LogEvidence("Could not find error details element."); // GlobalLog.LogEvidence(" IE Version: " + ApplicationDeploymentHelper.GetIEVersion() + "\n"); // return UIHandlerAction.Unhandled; //} //ValuePattern vp = (ValuePattern)errorDetailsElem.GetCurrentPattern(ValuePattern.Pattern); //GlobalLog.LogEvidence("Logging (and NOT setting result to fail) Browser Application Error... "); //GlobalLog.LogEvidence(" ***** BEGIN Error Log: ***** \n"); //GlobalLog.LogEvidence(vp.Current.Value); //GlobalLog.LogEvidence("\n ***** END Error Log: ***** \n"); //switch (ApplicationDeploymentHelper.GetIEVersion()) //{ // case 6: // InvokePattern ip = moreInfoButton.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern; // ip.Invoke(); // break; // case 7: // System.Windows.Rect r = (System.Windows.Rect)moreInfoButton.GetCurrentPropertyValue(AutomationElement.BoundingRectangleProperty); // double horizMidPt = r.Left + ((r.Right - r.Left) / 2.0); // double vertMidPt = r.Top + ((r.Bottom - r.Top) / 2.0); // MTI.Input.SendMouseInput(horizMidPt, vertMidPt, 0, MTI.SendMouseInputFlags.Absolute | MTI.SendMouseInputFlags.LeftDown | MTI.SendMouseInputFlags.Move); // MTI.Input.SendMouseInput(horizMidPt, vertMidPt, 0, MTI.SendMouseInputFlags.Absolute | MTI.SendMouseInputFlags.LeftUp | MTI.SendMouseInputFlags.Move); // break; //} return(UIHandlerAction.Unhandled); }
public override UIHandlerAction HandleWindow(IntPtr topLevelhWnd, IntPtr hwnd, System.Diagnostics.Process process, string title, UIHandlerNotification notification) { //Sleep a second to make sure that the dialog is ready Thread.Sleep(2000); //Make sure that the Security Dialog has focus GlobalLog.LogDebug("Switching to TrustManager dialog"); AutomationElement trustManagerWindow; try { trustManagerWindow = AutomationElement.FromHandle(topLevelhWnd); // if (SystemInformation.Current.IsWow64Process) { GlobalLog.LogDebug("Running in a WOW64 process... UI automation unavailable. Using interop to dismiss dialog..."); //Make sure that the Security Dialog has focus SwitchToThisWindow(topLevelhWnd, false); // Switch from "Cancel" to "Install"... MTI.Input.SendKeyboardInput(Key.LeftShift, true); MTI.Input.SendKeyboardInput(Key.Tab, true); MTI.Input.SendKeyboardInput(Key.Tab, false); MTI.Input.SendKeyboardInput(Key.LeftShift, false); // ... And hit enter MTI.Input.SendKeyboardInput(Key.Enter, true); MTI.Input.SendKeyboardInput(Key.Enter, false); } else { //get the localized text of the run button ResourceManager resMan = new ResourceManager("System.Windows.Forms", typeof(System.Windows.Forms.Form).Assembly); string runBtnName = resMan.GetString("TrustManagerPromptUI_Run").Replace("&", ""); //try to click the run button with two identities then error out if (tryInvokeByAutomationId(trustManagerWindow, "btnInstall") != true) { if (tryInvokeByName(trustManagerWindow, "Run Anyway") != true) { GlobalLog.LogEvidence("Failed to click any of the expected buttons on the Trust Dialog. Aborting..."); return(UIHandlerAction.Abort); } } } if (DictionaryStore.Current["HandledTrustManagerDialog"] == null) { DictionaryStore.Current["HandledTrustManagerDialog"] = "once"; } // If we're handling a WOW .application, there is an expected second trust prompt. // This will not be fixed until the Whidbey SP1, which is expected post Vista shipping... // The workaround is simply to pretend we only saw the dialog once if it's WOW64. // The 2nd prompt will have the same process name as the app, NOT dfsvc... so use this to trigger. else { if (process.ProcessName == "dfsvc") { DictionaryStore.Current["HandledTrustManagerDialog"] = "multiple"; } else { GlobalLog.LogEvidence("Ignoring second trust dialog as it appears to be a WOW64 application... contact Microsoft if this is not the case"); } } return(UIHandlerAction.Handled); } // This happens when the dialog is already being dismissed for other reasons. catch (System.Windows.Automation.ElementNotAvailableException) { return(UIHandlerAction.Handled); } }
public UIHandlerRule(UIHandler handler, string processName, string title, UIHandlerNotification notification) { this.handler = handler; this.processName = processName; this.notification = handler.Notification; if (title != null) { //replace Managed resource macros with values //syntax: @@PARTIAL_ASSEMBLY_NAME;BASE_NAME;RESOURCE_ID@@ //You can usually identify these values by looking at the source code for the managed component you need resource strings from //The BASE_NAME is usually in a private static class called SR. You can also use ILDASM do dissassemble //the resource table and look up what you are interested in Regex regex = new Regex("@@(?<asmName>[^@;]*);(?<baseName>[^@;]*);(?<id>[^@;]*)@@", RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture); for (Match match = regex.Match(title); match.Success; match = match.NextMatch()) { //get the match groups string matchString = match.Groups[0].Value; string asmName = match.Groups["asmName"].Value; string baseName = match.Groups["baseName"].Value; string id = match.Groups["id"].Value; //load the assembly and get the resource string from the resource manager try { AssemblyName assemblyName = AssemblyName.GetAssemblyName(asmName); Assembly asm = AssemblyLoadContext.Default.LoadFromAssemblyName(assemblyName); ResourceManager resMan = new ResourceManager(baseName, asm); string value = resMan.GetString(id); //replace the macro with the resource value title = title.Replace(matchString, value); } catch (System.IO.FileNotFoundException) { // Do nothing. This is for the case of an unload-able assembly reference // This will happen when registering for both the 2.0 and 4.0 System.Windows.Forms resources for the ClickOnce install dialog, for instance. } catch (System.BadImageFormatException) { // Same as above, this just fails differently depending on the scenario. } } } if (title != null && title.ToLowerInvariant().StartsWith("unmanagedresourcestring:")) { string[] resourceLookup = title.Substring(24).Split(','); if (resourceLookup.Length != 2) { throw new ArgumentException("Resource identifiers must specify a dll and resouce id", "title"); } string filename = resourceLookup[0].Trim(); int resourceId = int.Parse(resourceLookup[1].Trim()); this.title = ResourceHelper.GetUnmanagedResourceString(filename, resourceId); } // Loads a static property from a given assembly from the work dir // Can be updated later to search different paths // Do not change the string handling to "To...Invariant()" as class name loading will fail. else if (title != null && title.ToLowerInvariant().StartsWith("property:")) { string[] inputs = title.Substring(9).Trim().Split(','); string property = inputs[0].Trim(); string assembly = inputs[1].Trim(); // LoadWithPartialName here should be OK since test execution tries to ensure // that only a matching TestRuntime.dll is present // and, currently the only AMC files using this feature reference solely TestRuntime. // We need to fix this if not. [Microsoft] #pragma warning disable 618 Assembly a = Assembly.LoadWithPartialName(assembly); #pragma warning restore 618 if (a == null) { throw new ArgumentException("Could not locate assembly " + assembly); } Type t = a.GetType(property.Substring(0, property.LastIndexOf(".")), true); PropertyInfo pi = t.GetProperty(property.Substring(property.LastIndexOf(".") + 1)); // Create this as a regular expression because for IE titles we can't predict "Windows" vs "Microsoft" Internet explorer this.title = "regexp:(" + pi.GetValue(null, null) + ")"; } else { this.title = title; } }
//Evaluate the rules for a UIHandlers that care about this UI private void ProcessUIHandlers(IntPtr topLevelhWnd, IntPtr hWnd, Process process, string title, UIHandlerNotification notification) { foreach (UIHandlerRule rule in handlerRules) { string procName; try { procName = process.ProcessName; } catch (InvalidOperationException) { // The process has exited so we do not need to process any more handlers GlobalLog.LogDebug("Tried to evaluate UI \"" + title + "\" but process had already exited."); return; } if (rule.Evaluate(title, procName, notification, hWnd)) { rule.HasBeenInvoked = true; UIHandlerAction action = UIHandlerAction.Abort; if (Debugger.IsAttached) { // If a debugger is attached then don't try catch since it makes debugging inconvenient action = rule.Handler.HandleWindow(topLevelhWnd, hWnd, process, title, notification); } else { // We can't trust the UIHandler to not throw an unhandled exception (crashes the app since the callback in on another thread) try { action = rule.Handler.HandleWindow(topLevelhWnd, hWnd, process, title, notification); } catch (Exception e) { // If an exception occurs log the exception and return abort GlobalLog.LogEvidence(e.ToString()); } } //If the action was handled then stop processing rules if (action == UIHandlerAction.Handled) { break; } //If the action was aborted then set the abort signal and stop processing rules else if (action == UIHandlerAction.Abort) { abortSignal.Set(); break; } } } }
/// <summary> /// Registers a UIHandler to handle the specified UI /// </summary> /// <param name="handler">UIHandler to be executed when the specified UI is shown</param> /// <param name="processName">Name of the process (excluding extention) hosting the UI, null indicates any process</param> /// <param name="windowTitle">Title of the window to be handled, null indicates any windowtitle</param> /// <param name="notification">The events that you want to handle the targed UI</param> public void RegisterUIHandler(UIHandler handler, string processName, string windowTitle, UIHandlerNotification notification) { if (processMonitor != null) { throw new InvalidOperationException("You cannot register UIHandlers after the process is executed"); } handlerRules.Push(new UIHandlerRule(handler, processName, windowTitle, notification)); }
public override UIHandlerAction HandleWindow(IntPtr topLevelhWnd, IntPtr hwnd, Process process, string title, UIHandlerNotification notification) { this.topLevelhWnd = topLevelhWnd; return(UIHandlerAction.Abort); }