我有来自第三方的Inproc COM服务器。如果它捕获特定类型的错误,我调用的函数之一将显示错误消息对话框。问题是我正在尝试批量处理数据,而我使用的数据源导致错误对话框弹出很多。如果它产生了1000个对话框,那么这不会成为问题,而是它会阻塞,并且在按下OK之前函数不会返回。
如何禁止显示对话框,或以编程方式按OK?
这是一个调用堆栈的副本,因为它正在等待我按OK
[Managed to Native Transition] > System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(System.IntPtr dwComponentID, int reason, int pvLoopData) Line 2198 + 0x1e bytes C# System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason, System.Windows.Forms.ApplicationContext context) Line 3422 + 0x1b bytes C# System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) Line 3306 + 0xc bytes C# System.Windows.Forms.dll!System.Windows.Forms.Application.Run(System.Windows.Forms.Form mainForm) Line 1495 + 0x31 bytes C# UniversalDataImporter.exe!UniversalDataImporter.Program.Main() Line 18 + 0x1d bytes C# [Native to Managed Transition] [Managed to Native Transition] mscorlib.dll!System.AppDomain.ExecuteAssembly(string assemblyFile, System.Security.Policy.Evidence assemblySecurity, string[] args) Line 2023 + 0x18 bytes C# Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() + 0x27 bytes mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) Line 68 + 0x27 bytes C# mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Line 581 + 0xd bytes C# mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Line 530 + 0xd bytes C# mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) Line 519 + 0xe bytes C# mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() Line 105 + 0x20 bytes C# [Native to Managed Transition]
我怀疑它会有所帮助(没有选项可以禁用消息框,订阅事件或函数的其他重载)但这里是调用代码。
for (int i = 1; i <= recordCount; i++)
{
//If the dialog shows up the following line blocks till you press OK.
var values = _comServer.GetValues(fileHandle, i);
sqlDataConsumer.LoadRow(values);
}
答案 0 :(得分:11)
消息框抽取消息循环。这是你可以利用的东西,它允许你使用Control.BeginInvoke()注入代码,该代码在消息框出现时立即运行。然后,您可以使用该代码查找对话框窗口并将其关闭。在项目中添加一个新类并粘贴此代码:
using System;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public class DialogCloser : IDisposable {
public DialogCloser() {
if (Application.OpenForms.Count == 0) throw new InvalidOperationException();
Application.OpenForms[0].BeginInvoke(new Action(() => {
// Enumerate windows to find dialogs
if (cancelled) return;
EnumThreadWndProc callback = new EnumThreadWndProc(checkWindow);
EnumThreadWindows(GetCurrentThreadId(), callback, IntPtr.Zero);
GC.KeepAlive(callback);
}));
}
public void Dispose() {
cancelled = true;
}
private static bool checkWindow(IntPtr hWnd, IntPtr lp) {
// Checks if <hWnd> is a Windows dialog
StringBuilder sb = new StringBuilder(260);
GetClassName(hWnd, sb, sb.Capacity);
if (sb.ToString() == "#32770") {
// Close it by sending WM_CLOSE to the window
SendMessage(hWnd, 0x0010, IntPtr.Zero, IntPtr.Zero);
}
return true;
}
private bool cancelled;
// P/Invoke declarations
private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
[DllImport("user32.dll")]
private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
[DllImport("kernel32.dll")]
private static extern int GetCurrentThreadId();
[DllImport("user32.dll")]
private static extern int GetClassName(IntPtr hWnd, StringBuilder buffer, int buflen);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
}
样本用法:
private void button1_Click(object sender, EventArgs e) {
using (new DialogCloser()) {
// Replace this with the call to the COM server method:
MessageBox.Show("you never see this");
}
}
答案 1 :(得分:1)
首先,如果COM服务器本身可以在不让不需要的UI操作让调用者失效的情况下进入模式,那肯定会更好。如果您无法改变第三方组件的行为,您仍然可以做的是挂钩消息处理和强制关闭消息框。
在第三方服务器上进行呼叫之前,您可以使用SetWindowsHookEx
和WH_CALLWNDPROC
安装消息挂钩,并且您的回调将能够监控消息。特别是你可以发布消息,钩子对话框的WindowProc等。包括当然以编程方式关闭消息框。