/// <summary> /// Compares current window to configured windows /// </summary> /// <param name="hwndPtr">Handle to window</param> /// <param name="pacc">Accessible representation of window</param> /// <param name="windowDescription">title and message of window</param> /// <param name="windowClass">window class</param> private void CompareToConfiguredWindows(IntPtr hwndPtr, IAccessible pacc, PopupMessage windowDescription, string windowClass) { IEnumerator children; PopupBasherConfiguration.PopupConfigChild currentChildWindow; IAccessible accControl = null; int childId; // Normal popup bashing behavior if (PopupBasherConfiguration.Instance.Windows != null && PopupBasherConfiguration.Instance.Windows.Windows != null) { // For each configured windows, search the couple windows name / class foreach (PopupBasherConfiguration.PopupConfigWindow currentWindow in PopupBasherConfiguration.Instance.Windows.Windows) { if (windowDescription.TitleBar == currentWindow.Title && windowClass == currentWindow.ClassName) { // The parent window has been found, so act on children Tracing.WriteDebugTextInfo(Tracing.ComponentId.ExcelDriver, Resources.PopupBasher_FoundParent, currentWindow.Title, currentWindow.ClassName); NativeMethods.ShowWindow(hwndPtr, ShowWindowMode.SW_NORMAL); NativeMethods.SetFocus(hwndPtr); // Iterate thru children (form elements) children = currentWindow.Children.GetEnumerator(); while (children.MoveNext()) { currentChildWindow = (PopupBasherConfiguration.PopupConfigChild)children.Current; Tracing.WriteDebugTextVerbose( Tracing.ComponentId.ExcelDriver, Resources.PopupBasher_SearchingForChild, currentChildWindow.Title, currentChildWindow.ClassName, currentChildWindow.Role); if (AccessibleHelper.FindChild(pacc, NativeMethods.CHILDID_SELF, currentChildWindow, out accControl, out childId)) { // Add popup to list of bashed popups this.bashedPopups.Add(windowDescription); Tracing.WriteDebugTextVerbose( Tracing.ComponentId.ExcelDriver, Resources.PopupBasher_FoundChild, currentChildWindow.Title, currentChildWindow.ClassName, currentChildWindow.Role, windowDescription.MessageText); if (currentChildWindow.Action == PopupBasherConfiguration.ActionType.DoDefault) { // Perform the default action LogDefaultAction( currentWindow.Title, currentWindow.ClassName, currentChildWindow.Title, currentChildWindow.ClassName, currentChildWindow.Role); accControl.accDoDefaultAction(childId); break; } } } // while (children.MoveNext()) } // if } // foreach popup window } // if windows != null }
/// <summary> /// Identify popups that are open. Try to bash ones that have matching configurations and trace about other windows. /// </summary> private void ExamineExcelPopups() { int hresult; IAccessible pacc = null; PopupMessage windowDescription; Dictionary <int, WindowStatus> openWindows = new Dictionary <int, WindowStatus>(); Guid iidIAccessible = new Guid(NativeMethods.IID_IAccessible); try { // Look at each window and proceed only if they were successfully enumerated hresult = NativeMethods.EnumWindows(new NativeMethods.CallBackPtr(PopupBasher.HandleWindow), 0); if (hresult != 0) { // Examine each window that was around last time or opened this time if (historicalWindows != null) { foreach (KeyValuePair <int, WindowStatus> blockingWindow in historicalWindows) { // If window is still around if (blockingWindow.Value.Open) { try { // Get access to the window properties IntPtr hwndPtr = (IntPtr)blockingWindow.Key; hresult = NativeMethods.AccessibleObjectFromWindow(hwndPtr, (uint)ObjIdentifier.OBJID_WINDOW, ref iidIAccessible, out pacc); if (hresult >= 0) { // Get window class string windowClass = AccessibleHelper.GetWindowClassForUIElement(pacc); // If window is not a main or supporting Excel process window then it's a popup and should be examined if (windowClass != EXCELWINCLASSNAME) { // Get the description windowDescription = AccessibleHelper.GetPopupWindowMessage(pacc, NativeMethods.CHILDID_SELF); // if the window doesn't have message text or title, it can't be examined if (windowDescription.MessageText != null && windowDescription.TitleBar != null) { this.CompareToConfiguredWindows(hwndPtr, pacc, windowDescription, windowClass); // If this is the Nth time the window is seen in a row, produce a warning if any are detected. DCR 8305. if (blockingWindow.Value.Recurrences == INTERVALSTOWARN) { // Trace potentially blocking window Tracing.TraceEvent(XlTraceLevel.Warning, Tracing.ComponentId.ExcelDriver, string.Format(Resources.PopupBasher_BlockingWindow, windowDescription.TitleBar, windowDescription.MessageText, windowClass), new EventWriterCallback(delegate { Tracing.EventProvider.LogExcelDriver_BlockingPopup(windowDescription.TitleBar, windowDescription.MessageText, windowClass); })); } } } } } catch { // If there is an error, write a debug log stating that something went wrong in examining the window Tracing.WriteDebugTextWarning(Tracing.ComponentId.ExcelDriver, Resources.PopupBasher_ExamineWindowFailed); } // Add to list of recurring windows. Reset state so that windows are evaluated freshly on the next timer trigger. WindowStatus state = blockingWindow.Value; state.Open = false; openWindows.Add(blockingWindow.Key, state); } } } } else { // Write debug log stating that we failed to enumerate the open windows Tracing.WriteDebugTextWarning(Tracing.ComponentId.ExcelDriver, Resources.PopupBasher_EnumWindowsFailed); } } catch (Exception ex) { // If there is an error, write a debug log stating that something went wrong in monitoring open windows Tracing.WriteDebugTextWarning(Tracing.ComponentId.ExcelDriver, Resources.PopupBasher_TracePopupFailed + ex.ToString()); } finally { // Release IAccessible COM object if (pacc != null) { System.Runtime.InteropServices.Marshal.FinalReleaseComObject(pacc); } // Clear out the last history and move the open windows in the historical list historicalWindows.Clear(); foreach (KeyValuePair <int, WindowStatus> window in openWindows) { historicalWindows.Add(window.Key, window.Value); } openWindows.Clear(); } }