我的應用程序使用的系統有問題:有時候,當我們問這個系統的數據時,他彈出一個MessageBox來告訴我們一些事情:「I無法檢索您的數據,有太多的數據要搜索「。防止創建MessageBox的過程
這樣做的問題是用戶可能無法看到或關閉彈出窗口,從而阻止了整個應用程序(解釋用戶無法關閉/看到彈出窗口的原因將花費太多時間和主題,很糟糕,但我們必須處理它)。
因此,作爲一個臨時解決方案,我想阻止這個特定的過程來創建MessageBox。
我在網上尋找一個解決方案,發現約CBTProc似乎提供了一種方式來響應一個特定的Windows事件(來自一個進程的請求創建一個窗口),並指示操作系統阻止請求。
這是要走的路嗎?
我測試SetWinEventHook檢測過程,請求建立一個窗口和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不能用於破壞由像MSDN文檔另一個線程說,這是understable創建的窗口。所以我的測試沒有成功。我該如何解決這個問題?
我可能犯了錯誤,我不太瞭解Windows API,只是聽說過CBTProc。
更新
我改變了以下@DavidHeffernan和@AlexK建議的代碼,它的工作原理:
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
}
有這個代碼相當多的錯誤。您不會執行任何錯誤檢查,並且您不通過在靜態變量中保存引用來保護GC的委託。我認爲你可能會發佈一個WM_QUIT消息給對話框,而不是調用DestroyWindow。 –
DestroyWindow不合適,您可以發送WM_CLOSE或使用UIAutomation,這是更好的選擇,因爲它也可用於檢測消息框的創建而無需掛鉤。 –
謝謝你們兩位的解決方案,我會努力工作,有些回饋給你! – nkoniishvt