阻止一个进程创build一个MessageBox

我有一个与我们的应用程序一起使用的系统的问题:有时候,当我们问这个系统的数据时,他popup一个MessageBox来告诉我们一些事情:“我无法检索你的数据,有办法太多的数据来search“。

问题在于用户可能无法看到或closurespopup窗口,从而阻塞了整个应用程序(解释为什么用户不能closures/看到popup窗口将花费太多的时间,而不是主题,这很糟糕,有处理它)。

所以,作为一个临时的解决scheme,我想阻止这个特定的过程来创buildMessageBox。

我在网上寻找一个解决scheme,发现有关CBTProc ,似乎提供了一种方式来响应一个特定的Windows事件(从一个进程的请求创build一个窗口),并指示操作系统阻止请求。

这是要走的路吗?

我testing了SetWinEventHook来检测进程请求创build一个窗口和DestroyWindow来销毁窗口:

public class PopupWatchdog { #region constructor public PopupWatchdog() { SetWinEventHook( EVENT_OBJECT_CREATED, EVENT_OBJECT_CREATED, IntPtr.Zero, HookCallback, 0, //id process 0, //id thread WINEVENT_OUTOFCONTEXT ); } #endregion #region functions private static void HookCallback(IntPtr hWinEventHook, int iEvent, IntPtr hWnd, int idObject, int idChild, int dwEventThread, int dwmsEventTime) { Console.WriteLine("window {0} requests creating an object, trying to destroy it...", idChild); DestroyWindow(hWnd); } [DllImport("user32.dll", SetLastError = true)] private static extern IntPtr SetWinEventHook(int eventMin, int eventMax, IntPtr hmodWinEventProc, HookProc lpfnWinEventProc, int idProcess, int idThread, int dwflags); [DllImport("user32.dll")] private static extern bool DestroyWindow(IntPtr hWnd); #endregion #region events #endregion #region variables #region const private const int EVENT_OBJECT_CREATED = 0x8000; private const int WINEVENT_OUTOFCONTEXT = 0; #endregion private delegate void HookProc( IntPtr hWinEventHook, int iEvent, IntPtr hWnd, int idObject, int idChild, int dwEventThread, int dwmsEventTime ); #endregion } 

DestroyWindow不能被用来销毁由另外一个Thread创build的Window,就像msdn文档所说的那样,是不可理喻的。 所以我的testing没有成功。 我怎样才能解决这个问题?

我可能犯了错误,我不太了解Windows API,只是听说了CBTProc。

更新

我改变了@DavidHeffernan和@AlexK的build议,它的工作原理:

 public class BlockingPopupWatchdog { #region ctor public BlockingPopupWatchdog(int processId) { _processId = processId; } #endregion #region functions internal bool Hook() { if (_hookId != IntPtr.Zero) { Unhook(); } _hookId = SetWinEventHook( EVENT_OBJECT_CREATED, EVENT_OBJECT_CREATED, IntPtr.Zero, _hook, _processId, //id process 0, //id thread WINEVENT_OUTOFCONTEXT ); if (_hookId == IntPtr.Zero) { Logger.Log(String.Format("Error {0} while hooking", Marshal.GetLastWin32Error()), EventTypes.WARNING); return false; } return true; } internal bool Unhook() { if (_hookId == IntPtr.Zero) return false; if (!UnhookWinEvent(_hookId)) { Logger.Log(String.Format("Error {0} while unhooking", Marshal.GetLastWin32Error()), EventTypes.WARNING); return false; } return true; } private static void HookCallback(IntPtr hWinEventHook, int iEvent, IntPtr hWnd, int idObject, int idChild, int dwEventThread, int dwmsEventTime) { if (hWnd == IntPtr.Zero) return; try { AutomationElement elem = AutomationElement.FromHandle(hWnd); if (elem == null || !elem.Current.ClassName.Equals(MESSAGEBOX_CLASS_NAME)) { return; } object pattern; if (!elem.TryGetCurrentPattern(WindowPattern.Pattern, out pattern)) return; WindowPattern window = (WindowPattern)pattern; if (window.Current.WindowInteractionState == WindowInteractionState.ReadyForUserInteraction) { window.Close(); } } catch (Exception e) { Console.WriteLine(e); } } [DllImport("user32.dll", SetLastError = true)] private static extern IntPtr SetWinEventHook(int eventMin, int eventMax, IntPtr hmodWinEventProc, HookProc lpfnWinEventProc, int idProcess, int idThread, int dwflags); [DllImport("user32.dll", SetLastError = true)] private static extern bool UnhookWinEvent(IntPtr hWinEventHook); #endregion #region variables #region const private const String MESSAGEBOX_CLASS_NAME = "#32770"; private const int EVENT_OBJECT_CREATED = 0x8000; private const int WINEVENT_OUTOFCONTEXT = 0; #endregion private delegate void HookProc( IntPtr hWinEventHook, int iEvent, IntPtr hWnd, int idObject, int idChild, int dwEventThread, int dwmsEventTime ); private static readonly HookProc _hook = HookCallback; private IntPtr _hookId; private readonly int _processId; #endregion } 

感谢DavidHefferman和AlexK。 这是解决方案,使我想要的。

使用WinApi:

 public class BlockingPopupWatchdog { #region ctor public BlockingPopupWatchdog(int processId) { _processId = processId; } #endregion #region functions internal bool Hook() { if (_hookId != IntPtr.Zero) { Unhook(); } _hookId = SetWinEventHook( EVENT_OBJECT_CREATED, EVENT_OBJECT_CREATED, IntPtr.Zero, _hook, _processId, //id process 0, //id thread WINEVENT_OUTOFCONTEXT ); if (_hookId == IntPtr.Zero) { Logger.Log(String.Format("Error {0} while hooking", Marshal.GetLastWin32Error()), EventTypes.WARNING); return false; } return true; } internal bool Unhook() { if (_hookId == IntPtr.Zero) return false; if (!UnhookWinEvent(_hookId)) { Logger.Log(String.Format("Error {0} while unhooking", Marshal.GetLastWin32Error()), EventTypes.WARNING); return false; } return true; } private static void HookCallback(IntPtr hWinEventHook, int iEvent, IntPtr hWnd, int idObject, int idChild, int dwEventThread, int dwmsEventTime) { if (hWnd == IntPtr.Zero) return; try { AutomationElement elem = AutomationElement.FromHandle(hWnd); if (elem == null || !elem.Current.ClassName.Equals(MESSAGEBOX_CLASS_NAME)) { return; } object pattern; if (!elem.TryGetCurrentPattern(WindowPattern.Pattern, out pattern)) return; WindowPattern window = (WindowPattern)pattern; if (window.Current.WindowInteractionState == WindowInteractionState.ReadyForUserInteraction) { window.Close(); } } catch (Exception e) { Console.WriteLine(e); } } [DllImport("user32.dll", SetLastError = true)] private static extern IntPtr SetWinEventHook(int eventMin, int eventMax, IntPtr hmodWinEventProc, HookProc lpfnWinEventProc, int idProcess, int idThread, int dwflags); [DllImport("user32.dll", SetLastError = true)] private static extern bool UnhookWinEvent(IntPtr hWinEventHook); #endregion #region variables #region const private const String MESSAGEBOX_CLASS_NAME = "#32770"; private const int EVENT_OBJECT_CREATED = 0x8000; private const int WINEVENT_OUTOFCONTEXT = 0; #endregion private delegate void HookProc( IntPtr hWinEventHook, int iEvent, IntPtr hWnd, int idObject, int idChild, int dwEventThread, int dwmsEventTime ); private static readonly HookProc _hook = HookCallback; private IntPtr _hookId; private readonly int _processId; #endregion } 

而使用UIAutomation的解决方案:

 private AutomationElement _watchedElement; private void PopupOpenedHandler(Object sender, AutomationEventArgs args) { var element = sender as AutomationElement; if (element == null || !element.Current.ClassName.Equals(MESSAGEBOX_CLASS_NAME)) { return; } object pattern; if (!element.TryGetCurrentPattern(WindowPattern.Pattern, out pattern)) return; WindowPattern window = (WindowPattern)pattern; if (window.Current.WindowInteractionState == WindowInteractionState.ReadyForUserInteraction) { window.Close(); } } internal bool Hook() { Process p = Process.GetProcessById(_processId); IntPtr wHnd = p.MainWindowHandle; if (wHnd != IntPtr.Zero) { _watchedElement = AutomationElement.FromHandle(wHnd); Automation.AddAutomationEventHandler ( WindowPattern.WindowOpenedEvent, _watchedElement, TreeScope.Descendants, PopupOpenedHandler ); return true; } return false; } internal bool Unhook() { if (_watchedElement == null) return false; Automation.RemoveAutomationEventHandler(WindowPattern.WindowOpenedEvent, _watchedElement, PopupOpenedHandler); return true; }