c# - 如何抑制由我​​无法更改的代码显示的对话框?

标签 c# .net .net-4.0 com messagebox

我有一个来自第 3 方的 Inproc COM 服务器。如果我调用的函数之一捕获特定类型的错误,它将显示一个错误消息对话框。问题是我正在尝试批量处理数据,而我使用的数据源导致该错误对话框经常弹出。如果它生成 1000 个对话框,这将不是问题,但它会阻塞并且函数不会返回,直到您按下 OK。

enter image description here

如何禁止显示对话框,或以编程方式按“确定”?

这是等待我按 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]  

I doubt it will help (there are no options to disable the message box, events to subscribe to, or other overloads to the function) but here is the calling code.

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);
}

最佳答案

一个消息框泵出一个消息循环。这是您可以利用的东西,它允许您使用 Control.BeginInvoke() 注入(inject)代码,该代码在消息框出现时立即运行。然后您可以使用该代码找到对话窗口并关闭它。向您的项目添加一个新类并粘贴此代码:

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");
    }
}

关于c# - 如何抑制由我​​无法更改的代码显示的对话框?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12532812/

相关文章:

c# - 将参数传递给 NUnit 测试

c# - ICommand 不将更改推送到 Windows UWP 中的 UI

c# - 找不到 CodeDom 提供程序类型 "Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider ..."

wpf - 使用 DockPanel 滚动内容

c# - TCP 客户端指导、重新连接功能等

c# - .NET 十进制格式根据源的不同而不同

.NET Entity Framework FirstOrDefaultAsync 抛出强制转换错误

.net - 这个 OleDBCommand 有什么问题?

.NET 引用 "Copy Local"根据 GAC 的内容设置 True/False

c# - RegEx、StringBuilder 和大对象堆碎片