如何燮preSS由code显示一个对话框,我不能改变? [英] How to suppress a dialog box displayed by code that I can't change?

查看:234
本文介绍了如何燮preSS由code显示一个对话框,我不能改变?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个第三方的一个进程内COM服务器。其中一个我称之为如果捕获错误的具体类型将显示一个错误消息对话框的功能。这个问题是我想处理数据的批量和我使用的数据源导致该错误对话框弹出了很多。这不会是一个问题,如果它催生了1000对话框,而是它块和函数不返回,直到preSS确定。

我怎么能晚饭从显示出来preSS对话框,或以编程方式preSS OK?

下面是调用堆栈,因为它是在等我preSS确定

副本

    [托管到本机转换]
> System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(System.IntPtr dwComponentID,诠释原因,INT pvLoopData)线2198 + 0X1E字节C#
    System.Windows.Forms.dll中!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(INT原因,System.Windows.Forms.ApplicationContext上下文)线3422 + 0x1b字节C#
    System.Windows.Forms.dll中!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(INT原因,System.Windows.Forms.ApplicationContext上下文)线3306 + 0xC字节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(字符串assemblyFile,System.Security.Policy.Evidence assemblySecurity,字串[] args)线2023 +为0x18字节C#
    Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() + 0x27字节
    mscorlib.dll中!System.Threading.ThreadHelper.ThreadStart_Context(对象状态)行68 + 0x27字节C#
    mscorlib.dll中!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext的ExecutionContext,System.Threading.ContextCallback回调,对象的状态,布尔preserveSyncCtx)线581 + 0xd中的字节C#
    mscorlib.dll中!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext的ExecutionContext,System.Threading.ContextCallback回调,对象的状态,布尔preserveSyncCtx)线530 + 0xd中的字节C#
    mscorlib.dll中!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext的ExecutionContext,System.Threading.ContextCallback回调,对象的状态)519线+ 0xe字节C#
    mscorlib.dll中!System.Threading.ThreadHelper.ThreadStart()线105 + 0x20的字节C#
    [原产于托管过渡]

我怀疑这将有助于(没有选项来禁用消息框,事件订阅,或其他重载的功能),但这里是调用code。

 的for(int i = 1; I< =的RecordCount;我++)
{
    //如果对话框显示了以下行块,直到你preSS确定。
    VAR值= _comServer.GetValues​​(文件句柄,我);

    sqlDataConsumer.LoadRow(值);
}
 

解决方案

一个消息框泵消息循环。这件事情,你可以利用的优势,它可以让你注入一些Control.BeginInvoke(code),一旦出现消息框运行。然后,您可以使用code找到对话窗口并关闭它。添加一个新类到您的项目并粘贴此code:

 使用系统;
使用System.Text;
使用System.Windows.Forms的;
使用了System.Runtime.InteropServices;

公共类DialogCloser:IDisposable的{
    公共DialogCloser(){
        如果(Application.OpenForms.Count == 0)抛出新的InvalidOperationException异常();
        Application.OpenForms [0] .BeginInvoke(新动作(()=> {
            //枚举窗口找到对话
            如果(取消)返回;
            EnumThreadWndProc回调=新EnumThreadWndProc(checkWindow);
            EnumThreadWindows(GetCurrentThreadId(),回调,IntPtr.Zero);
            GC.KeepAlive(回调);
        }));
    }

    公共无效的Dispose(){
        取消= TRUE;
    }

    私有静态布尔checkWindow(IntPtr的的HWND,IntPtr的LP){
        //检查是否<的hWnd>是一个Windows对话框
        StringBuilder的SB =新的StringBuilder(260);
        GetClassName(HWND,SB,sb.Capacity);
        如果(sb.ToString()==#32770){
            //通过发送WM_CLOSE窗口关闭它
            SendMessage消息(HWND,0×0010,IntPtr.Zero,IntPtr.Zero);
        }
        返回true;
    }

    私人BOOL取消;

    //的P / Invoke声明
    私人代表布尔EnumThreadWndProc(IntPtr的的HWND,IntPtr的LP);
    [的DllImport(user32.dll中)
    私人静态外部布尔EnumThreadWindows(INT TID,EnumThreadWndProc回调,IntPtr的LP);
    [的DllImport(KERNEL32.DLL)
    私人静态外部INT GetCurrentThreadId();
    [的DllImport(user32.dll中)
    私人静态外部INT GetClassName(IntPtr的的HWND,StringBuilder的缓冲,INT buflen);
    [的DllImport(user32.dll中)
    私人静态外部的IntPtr SendMessage函数(IntPtr的的HWND,INT味精,IntPtr的WP,IntPtr的LP);
}
 

使用范例:

 私人无效的button1_Click(对象发件人,EventArgs的){
    使用(新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");
    }
}

这篇关于如何燮preSS由code显示一个对话框,我不能改变?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆