9

サードパーティのInprocCOMサーバーがあります。私が呼び出す関数の1つは、特定のタイプのエラーをトラップすると、エラーメッセージダイアログボックスを表示します。問題は、データをまとめて処理しようとしていることです。使用しているデータソースが原因で、エラーダイアログが頻繁に表示されます。これは、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)2198行目+ 0x1eバイトC#
    System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason、System.Windows.Forms.ApplicationContext context)行3422 + 0x1bバイトC#
    System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason、System.Windows.Forms.ApplicationContext context)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(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)行68 + 0x27バイトC#
    mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContextexecutionContext、System.Threading.ContextCallbackコールバック、オブジェクト状態、boolpreserveSyncCtx)行581 + 0xdバイトC#
    mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executeContext、System.Threading.ContextCallbackコールバック、オブジェクト状態、boolpreserveSyncCtx)行530 + 0xdバイトC#
    mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executeContext、System.Threading.ContextCallbackコールバック、オブジェクト状態)行519 + 0xeバイトC#
    mscorlib.dll!System.Threading.ThreadHelper.ThreadStart()行105 + 0x20バイトC#
    [ネイティブからマネージドへの移行]  

私はそれが役立つとは思えませんが(メッセージボックス、サブスクライブするイベント、または関数への他のオーバーロードを無効にするオプションはありません)、ここに呼び出し元のコードがあります。

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

2 に答える 2

12

メッセージボックスはメッセージループをポンプします。これは利用できるものであり、メッセージボックスが表示されるとすぐに実行される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");
    }
}
于 2012-09-23T18:30:15.030 に答える
1

まず第一に、COMサーバー自体が、不要なUIアクションで呼び出し元を失望させないときに、モードに切り替えることができれば、確かに良いでしょう。サードパーティコンポーネントの動作を変更できない場合でも、メッセージ処理をフックしてメッセージボックスを強制的に閉じることができます。

サードパーティのサーバーで呼び出しを行う前に、とを使用してメッセージフックをインストールするSetWindowsHookExWH_CALLWNDPROC、コールバックでメッセージを監視できるようになります。特に、メッセージを投稿したり、ダイアログのWindowProcをフックしたりすることができます。メッセージボックスをプログラムで閉じることも含まれます。

于 2012-09-21T15:02:13.533 に答える