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

How to suppress a dialog box displayed by code that I can#39;t change?(如何抑制由我​​无法更改的代码显示的对话框?)

本文介绍了如何抑制由我​​无法更改的代码显示的对话框?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

如何禁止显示对话框,或以编程方式按 OK?

这是调用堆栈的副本,​​因为它正在等待我按 OK

<上一页>[管理到本地转换]> 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) 第 1495 行 + 0x31 字节 C#UniversalDataImporter.exe!UniversalDataImporter.Program.Main() 第 18 行 + 0x1d 字节 C#[本机到托管转换][管理到本地转换]mscorlib.dll!System.AppDomain.ExecuteAssembly(string assemblyFile, System.Security.Policy.Evidence assemblySecurity, string[] args) 第 2023 行 + 0x18 字节 C#Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() + 0x27 字节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() 第 105 行 + 0x20 字节 C#[本机到托管转换]

我怀疑它会有所帮助(没有选项可以禁用消息框、要订阅的事件或函数的其他重载),但这里是调用代码.

for (int i = 1; i <= recordCount; i++){//如果对话框显示以下行块,直到您按确定.var values = _comServer.GetValues(fileHandle, i);sqlDataConsumer.LoadRow(值);}

解决方案

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

使用系统;使用 System.Text;使用 System.Windows.Forms;使用 System.Runtime.InteropServices;公共类 DialogCloser : IDisposable {公共对话关闭器(){if (Application.OpenForms.Count == 0) throw new InvalidOperationException();Application.OpenForms[0].BeginInvoke(new Action(() => {//枚举窗口以查找对话框如果(取消)返回;EnumThreadWndProc 回调 = new EnumThreadWndProc(checkWindow);EnumThreadWindows(GetCurrentThreadId(), 回调, IntPtr.Zero);GC.KeepAlive(回调);}));}公共无效处置(){取消=真;}私有静态布尔检查窗口(IntPtr hWnd,IntPtr lp){//检查是否 <hWnd>是一个 Windows 对话框StringBuilder sb = new StringBuilder(260);GetClassName(hWnd, sb, sb.Capacity);if (sb.ToString() == "#32770") {//通过向窗口发送 WM_CLOSE 来关闭它SendMessage(hWnd, 0x0010, IntPtr.Zero, IntPtr.Zero);}返回真;}私人布尔取消;//P/调用声明私人委托 bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);[DllImport("user32.dll")]private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);[DllImport("kernel32.dll")]私有静态外部 int GetCurrentThreadId();[DllImport("user32.dll")]private static extern int GetClassName(IntPtr hWnd, StringBuilder buffer, int buflen);[DllImport("user32.dll")]私有静态外部 IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);}

示例用法:

private void button1_Click(object sender, EventArgs e) {使用(新的 DialogCloser()){//将此替换为对 COM 服务器方法的调用:MessageBox.Show("你永远不会看到这个");}}

I have a Inproc COM Server from a 3rd party. One of the functions I call will display a error message dialog box if it traps a specific type of error. The issue is I am trying to process data in bulk, and the data source I am using is causing that error dialog to pop up a lot. This would not be a issue if it spawned 1000 dialog boxes, but instead it blocks and the function does not return until you press OK.

How can I suppress the dialog from showing up, or programmatically press OK?

Here is a copy of the call stack as it is waiting for me to press 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);
}

解决方案

A message box pumps a message loop. That's something you can take advantage of, it allows you to inject code with Control.BeginInvoke() that runs as soon as the message box appears. You can then use that code to find the dialog window and close it. Add a new class to your project and paste this code:

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

Sample usage:

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

这篇关于如何抑制由我​​无法更改的代码显示的对话框?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:如何抑制由我​​无法更改的代码显示的对话框?

基础教程推荐