private void OnVisibleWindowTitleChanged(IntPtr topLevelhWnd, IntPtr hWnd, Process process, string title) { GlobalLog.LogDebug(string.Format("UI Title Changed: {0} {1} '{2}'", process.ProcessName, hWnd, title)); //Invoke the UIHandlers registered for this UI (If any exist) ProcessUIHandlers(topLevelhWnd, hWnd, process, title, UIHandlerNotification.TitleChanged); }
/// <summary> /// Closes the FileHost and delete all files it contains. /// </summary> public void Close() { EnsureState(); isClosed = true; // delete unique directory try { GlobalLog.LogDebug("Deleting folder " + uniqueWriteablePath); Directory.Delete(uniqueWriteablePath, true); } catch (IOException ioe) { GlobalLog.LogDebug("Could not delete " + uniqueWriteablePath + "."); GlobalLog.LogDebug("Exception message: " + ioe.Message); } // Delete custom uploaded files, if any. foreach (object fileToDelete in customUploadedFiles) { try { File.Delete((string)fileToDelete); } catch (IOException ioe) { GlobalLog.LogDebug("Could not delete " + (string)fileToDelete + "."); GlobalLog.LogDebug("Exception message: " + ioe.Message); } } alreadyUploadedFiles.Clear(); }
/// <summary> /// Compares to bitmaps based on tolerance criteria /// </summary> /// <param name='sourceImage'>Master image for comparison.</param> /// <param name='targetImage'>Sampled image for comparison.</param> /// <param name='differenceImage'>On return, bitmap with differences highlighted /// if any were found, null otherwise.</param> /// <param name='criteria'>Criteria for image comparison.</param> /// <param name='logBitmaps'>Log bitmaps if comparison fails</param> /// <returns>true if master and sample are equal, false otherwise.</returns> public static bool AreBitmapsEqualUsingCriteria(Bitmap sourceImage, Bitmap targetImage, out Bitmap differenceImage, ComparisonCriteria criteria, bool logBitmaps) { ComparisonOperation operation; ComparisonResult result; operation = new ComparisonOperation(); operation.Criteria = criteria; operation.MasterImage = sourceImage; operation.SampleImage = targetImage; result = operation.Execute(); differenceImage = null; if ((result.CriteriaMet == false)) { AreBitmapsEqual(sourceImage, targetImage, out differenceImage); result.HighlightDifferences(differenceImage); if (logBitmaps) { GlobalLog.LogStatus("Logging Images: sourceImage targetImage differencesImage:\r\n"); GlobalLog.LogDebug(result.ToString()); LogImageOnDisk(sourceImage, "sourceImage" + _combinationIndex.ToString() + ".png"); LogImageOnDisk(targetImage, "targetImage" + _combinationIndex.ToString() + ".png"); LogImageOnDisk(differenceImage, "differencesImage" + _combinationIndex.ToString() + ".png"); _combinationIndex++; } } return(result.CriteriaMet); }
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); }
///<summary> ///</summary> public TestExtenderOutput Generate(int rootIndex) { TestExtenderOutput txro = new TestExtenderOutput(); Stopwatch timer = Stopwatch.StartNew(); CalculateDependenciesAndRoots(); if (rootIndex >= this.Generators.Count || rootIndex < 0) { throw new ArgumentOutOfRangeException("rootIndex"); } IVariationGenerator vg = this.RootGenerators[rootIndex]; foreach (VariationItem item in vg.Generate()) { item.IsRoot = true; txro.TestCases.Add(item); } timer.Stop(); GlobalLog.LogDebug("Generation Time " + rootIndex.ToString() + " : " + timer.Elapsed.TotalSeconds.ToString()); return(txro); }
/// <summary> /// Calls handlers of RenderedEvent. /// </summary> private void _FireRenderedEvent(object element) { // Call event handlers. if (RenderedEvent != null) { GlobalLog.LogDebug("Firing Rendered event..."); RenderedEvent(element, EventArgs.Empty); } }
/// <summary> /// Copies a file to an arbitrary path. File will not be cleaned up. /// </summary> /// <param name="filename">File to copy</param> /// <param name="copyToUrl">Path to server to copy to</param> public void UploadFileNonDefaultServer(string filename, string copyToUrl) { EnsureState(); string destination = copyToUrl + @"\" + Path.GetFileName(filename); GlobalLog.LogDebug("Copying " + filename + " to " + destination); File.Copy(filename, destination, true); customUploadedFiles.Add(destination); }
/// <summary> /// Uploads a file to the local directory (existing files will be overwritten) /// </summary> /// <param name="filename">path to the file to upload</param> public void UploadFileLocal(string filename) { EnsureState(); // construct path to destination string destination = Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + Path.GetFileName(filename); // copy file GlobalLog.LogDebug("Copying " + filename + " to " + destination); File.Copy(filename, destination, true); }
/// <summary> /// Uploads a file to the FileHost (existing files will be overwritten) /// </summary> /// <param name="filename">path to the file to upload</param> /// <param name="path">directory path to upload to</param> public void UploadFile(string filename, string path) { string directorySeparatorStr = Path.DirectorySeparatorChar.ToString(); if (path == null) { path = string.Empty; } if (path != string.Empty && !path.EndsWith(directorySeparatorStr)) { path += directorySeparatorStr; } EnsureState(); string origFileName = filename; // construct path to destination string destination = uniqueWriteablePath + path + Path.GetFileName(filename); // we should really use Path.Combine, but I didn't do it yet, b/c this method uses backslashes for directory // separators quite a bit // string destination = Path.Combine(Path.Combine(uniqueWriteablePath + path), Path.GetFileName(filename); // Trim the path if it's being copied from a binplace directory. // Might need to fix this later if anyone actually needs a path like this on a server (seriously doubt it) if (filename.ToLowerInvariant().StartsWith(@"bin" + directorySeparatorStr + "release" + directorySeparatorStr)) { filename = filename.Remove(0, 12); } if (PreserveDirectoryStructure) { // "path" overrides "filename" if (path != string.Empty) { CreateDirectory(Path.GetDirectoryName(destination)); } else if (filename.LastIndexOf(directorySeparatorStr) > 0) { destination = uniqueWriteablePath + filename; CreateDirectory(Path.GetDirectoryName(destination)); } } // copy file if (!alreadyUploadedFiles.Contains(filename)) { alreadyUploadedFiles.Add(filename); GlobalLog.LogDebug("Copying " + filename + " to " + destination); } File.Copy(origFileName, destination, true); }
private void CreateDirectory(string directoryPath) { if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); GlobalLog.LogDebug("Storing files at " + directoryPath); } else { GlobalLog.LogDebug("Path " + directoryPath + " already exists."); } }
//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> /// For all processes running on the system, show the process name /// and the name of the file that was used to create the process /// </summary> private void LogProcessesInfo() { ProcessSW[] processes = ProcessSW.GetProcesses(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < processes.Length; i++) { ProcessSW process = processes[i]; sb.Append(process.ProcessName); sb.Append(" "); } GlobalLog.LogDebug(sb.ToString()); }
/// <summary> /// Deletes all files hosted by the FileHost /// </summary> public void Clear() { EnsureState(); string [] files = Directory.GetFiles(uniqueWriteablePath); foreach (string file in files) { GlobalLog.LogDebug("Deleting file " + file + " from " + uniqueWriteablePath + "."); File.Delete(file); } alreadyUploadedFiles.Clear(); }
/// <summary> /// Creates a sandboxed instance of a type /// </summary> /// <param name="AssemblyName">The assembly where the type lives</param> /// <param name="TypeName">The name of the type to construct</param> /// <returns>An ObjectHandle of the constructed type</returns> internal ObjectHandle CreateInstance(string AssemblyName, string TypeName) { try { ObjectHandle oh = sandbox.CreateInstance(AssemblyName, TypeName, false, System.Reflection.BindingFlags.CreateInstance, null, new object[] { }, null, null, null); return(oh); } catch (Exception e) { GlobalLog.LogDebug(e.ToString()); return(null); } }
/// <summary> /// Uploads a file and its dependencies to the FileHost (existing files will be overritten) /// This methods supports .xps, .application, and .xaml files. /// </summary> /// <param name="filename">path to the file to upload</param> /// <param name="isLocal">Whether files should be copied over the local directory or remote</param> public void UploadFileWithDependencies(string filename, bool isLocal) { EnsureState(); string fileType = Path.GetExtension(filename).ToLowerInvariant(); switch (fileType) { case ".xps": { UploadFile(filename, isLocal); break; } case ApplicationDeploymentHelper.BROWSER_APPLICATION_EXTENSION: case ApplicationDeploymentHelper.STANDALONE_APPLICATION_EXTENSION: { ArrayList deployDependencies = GetDeployDependencies(filename); foreach (string file in deployDependencies) { UploadFile(file, isLocal); } break; } case ".xaml": { ArrayList xamlDependencies = GetXamlDependencies(filename); foreach (string file in xamlDependencies) { UploadFile(file, isLocal); } break; } default: { // don't know how to handle this file GlobalLog.LogDebug("Unknown file type, passing to UploadFile()."); UploadFile(filename, isLocal); break; } } }
private void OnProcessExited(Process process) { foreach (Process proc in activeProcessesToWaitFor) { if (proc.Id == process.Id) { activeProcessesToWaitFor.Remove(proc); if (activeProcessesToWaitFor.Count == 0) { GlobalLog.LogDebug("The process " + proc.Id + " has exited and no more processes with application lifetime are found. Aborting monitoring."); abortSignal.Set(); } break; } } }
public void KillProcesses() { lock (ProcessesToMonitor) { foreach (Process process in ProcessesToMonitor) { if (process.HasExited) { continue; } if (process.CloseMainWindow()) { GlobalLog.LogDebug("Closing Main window of process " + process.Id + ": " + GetProcessName(process)); if (!process.WaitForExit(5000)) { try { GlobalLog.LogDebug("Killing process " + process.Id + ": " + GetProcessName(process)); process.Kill(); process.WaitForExit(); } catch (InvalidOperationException) { //The process has already exited } catch (Win32Exception) { //The process has already exited or access is denied (this is probobly a whidbey } } } else { try { GlobalLog.LogDebug("Killing process " + process.Id + ": " + GetProcessName(process)); process.Kill(); process.WaitForExit(); } catch (InvalidOperationException) { //The process has already exited } catch (Win32Exception) { //The process has already exited or access is denied (this is probobly a whidbey } } } ProcessesToMonitor.Clear(); } }
/// <summary> /// Compare an exception string to the expected string using regular expression /// </summary> /// <param name="actual">String that you would like to compare to.</param> /// <param name="expected">Expected string from exception string table.</param> /// <returns></returns> public static bool CompareMessage(string actual, string expected) { // Pattern to find all special characters in a string. string specialPattern = @"[\^$|?*+()]"; // Pattern to match arguments in string comparison string argumentPattern = ".*"; // Need to escape metacharacters (specialChars) in string to ensure literal meaning. Regex escapeExpression = new Regex(specialPattern); MatchCollection escapeMatches = escapeExpression.Matches(expected); foreach (Match escapeMatch in escapeMatches) { expected = expected.Replace(escapeMatch.Value, string.Format(@"\{0}", escapeMatch.Value)); } // Need to find and replace string arguments ({0},{1},etc...) in string from resource with // argument pattern to match any argument that gets passed into the string. Regex argumentExpression = new Regex(@"{\d*}"); MatchCollection argumentMatches = argumentExpression.Matches(expected); foreach (Match match in argumentMatches) { expected = expected.Replace(match.Value, argumentPattern); } // Create regex expression from modified string from resource and compare it to actual string. Regex newExpression = new Regex(expected); //This code previously had an issue leading to false failures. //The exception string for a XamlParseException contains line/character information after the exception string, but the comparison below //was doing a length comparison between the two strings on top of the regex comparison. This clearly could never match for exceptions //containing line/character information. Just regex-comparing the strings themselves is sufficient and will actually work properly in all cases. if (newExpression.IsMatch(actual)) { return(true); } else { GlobalLog.LogDebug("Expected pattern: " + expected); GlobalLog.LogDebug("Actual string: " + actual); return(false); } }
///<summary> ///</summary> public TestExtenderOutput Generate() { TestExtenderOutput txro = new TestExtenderOutput(); Stopwatch timer = Stopwatch.StartNew(); CalculateDependenciesAndRoots(); for (int i = 0; i < RootGenerators.Length; i++) { TestExtenderOutput.MergeTEO(txro, Generate(i)); } timer.Stop(); GlobalLog.LogDebug("Generation Total Time: " + timer.Elapsed.TotalSeconds.ToString()); return(txro); }
/// <summary>Creates a bitmap with the image a user sees for a window.</summary> /// <param name="windowHandle">Handle to the window.</param> /// <returns>The created bitmap.</returns> public static Bitmap CreateBitmapFromWindowHandle(IntPtr windowHandle) { new SecurityPermission(PermissionState.Unrestricted).Assert(); Microsoft.Test.Win32.NativeStructs.RECT r = new Microsoft.Test.Win32.NativeStructs.RECT(0, 0, 0, 0); //Win32.GetClientRect(windowHandle, ref r); NativeMethods.GetClientRect(new HandleRef(new object(), windowHandle), ref r); if (r.Width == 0) { GlobalLog.LogDebug("Unable to retrieve client rectangle for window."); GlobalLog.LogDebug("The whole window will be used instead."); //Win32.GetWindowRect(windowHandle, ref r); NativeMethods.GetWindowRect(new HandleRef(new object(), windowHandle), ref r); if (r.Width == 0) { throw new Exception("The window refuses to provide width."); } } return(CreateBitmapFromWindowHandle(windowHandle, r)); }
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 void IgnoreRunningProcesses() { lock (ProcessesToIgnore) { foreach (Process process in Process.GetProcesses()) { if (!ProcessesToIgnore.Contains(process.Id)) { string procName; try { procName = process.ProcessName; } catch (InvalidOperationException) { //the process has exited continue; } catch (System.ComponentModel.Win32Exception) { //strange whidbey continue; } //If this process is on that we want to monitor for UI then don't ignore it foreach (string processNameToFind in ProcessesToFind) { if (procName.ToLowerInvariant() == processNameToFind.ToLowerInvariant()) { GlobalLog.LogDebug(string.Format("Ignoring {0} : {1}", procName, process.Id)); break; } } ProcessesToIgnore.Add(process.Id); } } } }
/// <summary> /// looks for a pattern on a given text, calling a method that can process a pattern and return a string to replace that ocurrence /// or null to just look for it. /// </summary> /// <param name="originalText"></param> /// <param name="pattern"></param> /// <param name="matchProcessor"></param> /// <returns></returns> internal static string ProcessMatches(string originalText, string pattern, MatchProcessor matchProcessor) { string text = originalText; Regex r = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant); Match m; int offset = 0; for (m = r.Match(text); m.Success; m = m.NextMatch()) { GlobalLog.LogDebug("found=" + m.Groups[1] + " at " + m.Groups[1].Index); if (matchProcessor != null) { Group current = m.Groups[1]; string replacement = matchProcessor(current.Value); if (replacement != null) { text = Replace(text, replacement, current.Index + offset, current.Length); offset += (replacement.Length - current.Value.Length); } } } return(text); }
// Used in XamlTest // internal static NavigationWindow CreateNavigationWindow(string filename, string callingAssembly, LoadCompletedEventHandler handler) { NavigationWindow navigationWindow; if (BrowserInteropHelper.IsBrowserHosted) { GlobalLog.LogDebug("Browser hosted"); navigationWindow = (NavigationWindow)Application.Current.MainWindow; } else { GlobalLog.LogDebug("not Browser hosted"); GlobalLog.LogEvidence("Creating a NavigationWindow"); NavigationWindow navwinsw = new NavigationWindow(); navigationWindow = navwinsw; } if (handler != null) { navigationWindow.LoadCompleted += handler; } string strUri = "pack://application:,,,/" + callingAssembly + ";component/" + filename; GlobalLog.LogEvidence("Navigating to " + strUri); navigationWindow.Navigate(new Uri(strUri, UriKind.RelativeOrAbsolute)); if (!BrowserInteropHelper.IsBrowserHosted) { GlobalLog.LogEvidence("Showing the Window"); navigationWindow.Show(); } DispatcherHelper.DoEvents(0, DispatcherPriority.Input); return(navigationWindow); }
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> /// Performs the Activation step /// </summary> /// <returns>returns true if the rest of the steps should be executed, otherwise, false</returns> protected override bool BeginStep() { //Create ApplicationMonitor appMonitor = new ApplicationMonitor(); // If defined, set a value in property bag. Used for communication test variations to target app if (PropertyBagValue != "") { // Update this code to allow > 1 prop bag values being set at once string[] values = PropertyBagValue.Trim().Split('='); if (values.Length == 2) { DictionaryStore.Current[values[0].Trim()] = values[1].Trim(); } else { throw new System.ArgumentException("Values must be a single 'foo=bar' format"); } } if (hostingPolicyResetter != null) { hostingPolicyResetter.Dispose(); } if (StrictHostingMode) { hostingPolicyResetter = HostingRuntimePolicyHelper.SetHostingRuntimePolicyValues( doNotLaunchV3AppInV4Runtime: true); } else { hostingPolicyResetter = HostingRuntimePolicyHelper.SetHostingRuntimePolicyValues( doNotLaunchV3AppInV4Runtime: false); } // upload files to FileHost is specified and scheme is not local if (Scheme != ActivationScheme.Local) { if (SupportFiles.Length > 0) { // Create host to copy files to... fileHost = new FileHost(UserDefinedDirectory, (Scheme == ActivationScheme.HttpInternetExternal)); // Upload each file foreach (SupportFile suppFile in SupportFiles) { // Whether to copy foo\bar\baz.xbap to the foo\bar created on the remote machine or just flattened fileHost.PreserveDirectoryStructure = suppFile.PreserveDirectoryStructure; if (suppFile.IncludeDependencies && !string.IsNullOrEmpty(suppFile.TargetDirectory)) { GlobalLog.LogEvidence("TargetDirectory with IncludeDependencies not yet implemented"); throw new NotImplementedException("TargetDirectory with IncludeDependencies not yet supported"); } if (suppFile.CustomTestScratchServerPath == null) { if (suppFile.IncludeDependencies) { fileHost.UploadFileWithDependencies(suppFile.Name); } else { fileHost.UploadFile(suppFile.Name, suppFile.TargetDirectory); } } else { fileHost.UploadFileNonDefaultServer(suppFile.Name, suppFile.CustomTestScratchServerPath); } } } // If no support files are listed, check the parent steps to see if one is a FileHostStep. // If this is the case, no need to upload the files as the FileHostStep has already. // Don't set throttle rate; this should be set in the markup for the parent's filehost. else { LoaderStep parent = this.ParentStep; while (parent != null) { if (parent.GetType() == typeof(Microsoft.Test.Loaders.Steps.FileHostStep)) { this.fileHost = ((FileHostStep)parent).fileHost; break; } // Failed to find it in the immediate parent: try til we hit null or the right one parent = parent.ParentStep; } } } // register UIHandlers foreach (UIHandler handler in UIHandlers) { if (handler.NamedRegistration != null) { appMonitor.RegisterUIHandler(handler, handler.NamedRegistration, handler.Notification); } else { appMonitor.RegisterUIHandler(handler, handler.ProcessName, handler.WindowTitle, handler.Notification); } } string param = ""; if (FileName.StartsWith("&") && FileName.EndsWith("&")) { param = DictionaryStore.Current[FileName.Substring(1, FileName.Length - 2)]; if (param == null) { throw new InvalidOperationException(FileName + " is not defined in the property bag; cannot be used to launch app"); } } else { // Allows for launching things in %program files%, which is localized. param = Environment.ExpandEnvironmentVariables(FileName); } if (Scheme != ActivationScheme.Local) { FileHostUriScheme hostScheme = FileHostUriScheme.Unc; if (Scheme != ActivationScheme.HttpInternetExternal) { hostScheme = (FileHostUriScheme)Enum.Parse(typeof(FileHostUriScheme), Scheme.ToString()); } param = fileHost.GetUri(FileName, hostScheme).ToString(); } // Clear the fusion cache by default. Can be disabled for custom ClickOnce scenarios if (ClearFusionCache) { ApplicationDeploymentHelper.CleanClickOnceCache(); } // Clear IE History but only if specified (defaults to false). Only matters for history-based navigation if (ClearIEHistory) { ApplicationDeploymentHelper.ClearIEHistory(); } // Launch the appropriate handler... switch (Method) { case ActivationMethod.Launch: { // This only works for local paths for security reasons. if (PresentationHostDebugMode) { param = Path.GetFullPath(param); // Workaround ... for some reason on XP64 there's no guarantee that it will actually find PresHost // Even though it verily is in the SysWOW64 directory. Solution... find the right one before we try string presHostPath = "presentationhost.exe"; if ((Environment.OSVersion.Version.Major == 5)) { presHostPath = (Directory.GetFiles(Environment.GetEnvironmentVariable("SystemRoot"), "PresentationHost.exe", SearchOption.AllDirectories))[0]; } appMonitor.StartProcess(presHostPath, " -debug \"" + param + "\""); } else { // Launch process with specified arguments. If shell: specified, then start that way. // If the arguments are for the URL, directly concatenate them. if ((Arguments.Length > 6) && (Arguments.ToLowerInvariant().StartsWith("shell:"))) { appMonitor.StartProcess(param, Environment.ExpandEnvironmentVariables(Arguments.Substring(6))); } else if ((Arguments.Length > 11) && (Arguments.ToLowerInvariant().StartsWith("currentdir:"))) { appMonitor.StartProcess(param, Path.Combine(Environment.CurrentDirectory, Arguments.Substring(11))); } else { appMonitor.StartProcess(param + Arguments); } } break; } case ActivationMethod.Navigate: { // If local we need to fully qualify the path if (Scheme == ActivationScheme.Local) { param = Path.GetFullPath(param); } // Fail to IE, since it has far more tests. string defaultBrowserExecutable = "iexplore.exe"; try { defaultBrowserExecutable = Registry.GetValue(@"HKEY_CURRENT_USER\Software\Clients\StartMenuInternet", null, "iexplore.exe").ToString(); } catch (Exception) { try { defaultBrowserExecutable = Registry.GetValue(@"HKEY_LOCAL_MACHINE\Software\Clients\StartMenuInternet", null, "iexplore.exe").ToString(); } catch (Exception) { // Do nothing, some machines have been seen in weird states where this is undefined. Log it anyways. GlobalLog.LogDebug("Unable to get StartMenuInternet key, FireFox or other non-standard browser tests may be affected. Contact Microsoft if this is the case"); } } // Handle the case where this value exists but isnt set to anything usable. IE is far more common so fall back to it. if (string.IsNullOrEmpty(defaultBrowserExecutable)) { defaultBrowserExecutable = "iexplore.exe"; } // start the default browser... currently just FF or IE. if (defaultBrowserExecutable.ToLowerInvariant().Contains("iexplore")) { // Create & register IE navigation handler // IE can be strange: About:NavigateIE sometimes gets a cancelled navigation // Workaround: Be less sensitive about the window title we trigger on. appMonitor.RegisterUIHandler(new NavigateIE(param + Arguments), "iexplore", "RegExp:(Internet Explorer)", UIHandlerNotification.All); appMonitor.StartProcess("iexplore.exe", "about:NavigateIE"); } else if (defaultBrowserExecutable.ToLowerInvariant().Contains("firefox")) { if (Scheme == ActivationScheme.Unc) { param = param.Replace("file:", "").Replace("/", @"\"); } } else { throw new InvalidOperationException("Don't know how to navigate an instance of \"" + defaultBrowserExecutable + "\" browser!!! Contact Microsoft with this message."); } break; } // GOTO used here for fallthrough since there's only 2 lines difference. case ActivationMethod.EHome: goto case ActivationMethod.EHomeFullScreen; case ActivationMethod.EHomeFullScreen: { // If local we need to fully qualify the path if (Scheme == ActivationScheme.Local) { param = Path.GetFullPath(param); } // Get a reference to the path for the ehome exe... string eHomePath = Environment.GetEnvironmentVariable("SystemRoot") + "\\ehome\\ehshell.exe"; // Fail hard if EHome isnt present on the system. // Need to mark testcases accurately in test DB to avoid this. if (!File.Exists(eHomePath)) { throw new InvalidOperationException("\"Ehome\" or \"EHomeFullScreen\" method selected but case was run on non-Media-Center-enabled SKU! \n Contact Microsoft for more info on this issue."); } // Construct args with path to content to launch (MUST be a Uri) string eHomeArgs = "/url:\"" + param + "\""; // Tack on the argument for full screen if requested if (Method == ActivationMethod.EHomeFullScreen) { eHomeArgs += " /directmedia:general"; } // Start MCE... appMonitor.StartProcess(eHomePath, eHomeArgs); break; } } // Store the activation path into the property bag. This way apps or child steps can directly figure out the deployment URI DictionaryStore.Current["ActivationStepUri"] = param; return(true); }
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); } }
/// <summary> /// Creates a new File Host for remote testing /// </summary> /// <param name="userDirectory">Custom-named directory to store files</param> /// <param name="useExternalServer"></param> public FileHost(string userDirectory, bool useExternalServer) { customUploadedFiles = new ArrayList(); GlobalLog.LogDebug("Checking server for old / abandoned test directories... "); // Get any directory name that starts with the same three chars as the current time (in Ticks) // At this level, these #'s only change once every 11 years or so. string[] testScratchDirs; try { testScratchDirs = Directory.GetDirectories(GetServerName() + @"\", DateTime.Now.Ticks.ToString().Substring(0, 3) + "*", SearchOption.TopDirectoryOnly); } catch (System.IO.IOException) { GlobalLog.LogEvidence("!!!! Error hit while attempting to instantiate FileHost. Erroring out. !!!!"); throw new Exception("Error! The user account running this automation does not have access to the path " + GetServerName() + "\nPlease load up an explorer window and verify read/write access to the path " + GetServerName() + "\nFailing that, contact Microsoft for assistance in debugging this issue."); } // Delete up to three directories. Three is an arbitrary amount but it prevents this stage from taking more than a couple seconds of time. // Will also always cause testcases running to delete more than they can create, which will keep the scratch dir scrubbed. for (int i = 0; i < Math.Min(testScratchDirs.Length, 3); i++) { long dirTime = -1; if ((long.TryParse(testScratchDirs[i].Replace(GetServerName() + @"\", "").Substring(0, 18), out dirTime)) && dirTime != 0) { // 900000000000 = 25 hours in Ticks (Millionths of a second) // At least 24 hours is needed for machines of different regional time zones executing // tests at the same time, since Ticks seems to be locale dependent. if ((DateTime.Now.Ticks - dirTime) > 900000000000) { GlobalLog.LogDebug("*** Removing > 2 hour old autogenerated directory " + testScratchDirs[i].Trim() + " from external testscratch server"); try { Directory.Delete(testScratchDirs[i], true); } catch { // Do nothing, this can happen occasionally when many testcases start at the exact same time. // Worst case scenario is that the file just doesnt get deleted... this will succeed at some later date. } } } } // set uniqueWriteablePath if (userDirectory != null) { myDirectoryName = userDirectory; } else { myDirectoryName = DateTime.Now.Ticks.ToString(); } uniqueWriteablePath = GetServerName() + @"\" + myDirectoryName + @"\"; // set uniqueReadOnlyPath. Long ago this was actually different from writeable path, and could change back again some day... uniqueReadOnlyPath = uniqueWriteablePath; // create directory GlobalLog.LogDebug("Creating directory " + uniqueWriteablePath); CreateDirectory(uniqueWriteablePath); }
public static void NavigateIEWindow(AutomationElement ieWindow, Uri UriToNavigate) { // Get a reference the address bar... GlobalLog.LogDebug("Finding the IE address bar"); AndCondition isAddrBar = new AndCondition(new PropertyCondition(ValuePattern.ValueProperty, "about:NavigateIE"), new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit)); AutomationElement addressBar = null; try { addressBar = ieWindow.FindFirst(TreeScope.Descendants, isAddrBar); } catch // Any exception type... can be one of several // Retry this a few times in a loop before we go the "old" route. { for (int countdown = 15; countdown > 0; countdown--) { try { Thread.Sleep(150); addressBar = ieWindow.FindFirst(TreeScope.Descendants, isAddrBar); countdown--; } catch { } // Still failing :( // Success! if (addressBar != null) { break; } } } // Type the URI and press return GlobalLog.LogDebug("Typing " + UriToNavigate.ToString() + " into the address bar"); if (addressBar != null) { // Don't focus the element because some OS'es will throw an InvalidOperationException // and this is unnecessary for ValuePattern. ValuePattern vp = addressBar.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern; if (vp == null) { throw new System.Exception("Couldn't get the valuePattern for the IE address bar! Please contact Microsoft to fix this."); } vp.SetValue(UriToNavigate.ToString()); } else { GlobalLog.LogEvidence("Could not set focus to address bar. Attempting to continue..."); //Sleep a few seconds to make sure that the address bar has focus Thread.Sleep(3500); // This section should only work as a backup, since this is unreliable in Japanese (possibly other) languages. // But if we fail to get the address bar or its valuepattern, it's better to try to continue. MTI.Input.SendUnicodeString(UriToNavigate.ToString(), 1, 15); } // Wait a second then send a 2nd Enter to the address bar if we're Japanese, as IME is on by default and requires this. // If this UIHandler fails for other languages, add their LCID's to the if statement. int tryCount = 10; Thread.Sleep(1500); AndCondition didNavigate = new AndCondition(new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Text), new PropertyCondition(AutomationElement.NameProperty, "NavigateIE")); AutomationElement navigationSuccessElement = null; do { tryCount--; // Can't trust setfocus to work, so instead click on the address bar... try { MTI.Input.MoveToAndClick(addressBar); } catch { // Do nothing... we'll try again in a little bit hoping this has fixed itself. } // Should disable IME. For most OS'es this is a no-op. For east asian, this will preclude the need to hit enter twice // (this is unreliable to do by culture) // This is broken by DD bugs 201197 - Invariant Assert in TextServicesLoader.Load() when setting IME State // If IME is enabled and it matters, we're out of luck since this Asserts. // Renable (InputMethod.Current.ImeState = InputMethodState.Off) if this is ever fixed MTI.Input.SendKeyboardInput(Key.Enter, true); MTI.Input.SendKeyboardInput(Key.Enter, false); Thread.Sleep(2000); try { navigationSuccessElement = ieWindow.FindFirst(TreeScope.Descendants, didNavigate); } catch // Any exception type... can be one of several { // Do nothing. Sometimes this happens when this handler is running while IE is shutting down. } } // Don't loop this in Vista... we'll take our chances. // LUA causes this to fail since some navigations launch new IE windows. while ((navigationSuccessElement != null) && tryCount > 0 && Environment.OSVersion.Version.Major != 6 && !UriToNavigate.ToString().EndsWith(ApplicationDeploymentHelper.STANDALONE_APPLICATION_EXTENSION)); }
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); }