これは、私の前の質問の続きです。InprocCOMサーバーが表示するダイアログボックスを抑制する方法。
バックグラウンド:
私の状況の要約:サードパーティからDelphiで記述されたInprocCOMサーバーがあります。私が呼び出す関数の1つは、特定のタイプのエラーをトラップすると、エラーメッセージダイアログボックスを表示します。問題は、データをまとめて処理しようとしていることです。使用しているデータソースにより、エラーダイアログが頻繁にポップアップ表示されます(前の質問の回答のおかげで、自動的に閉じて実行できました。完了すると、ダイアログボックスが表示され、誰かが[OK]を9923回押す必要があります)。メッセージボックスが閉じられるまで、プロセスはブロックされます。
質問:
エラーダイアログの内容をより適切にログに記録したいと思います。ただし、ダイアログボックスの本文テキストを取得する試みは失敗しました。
//Snip
private void StartWindowListener()
{
//Queue the watcher on the message pump if we are not watching.
if (_watcherRunning == false)
{
_watcherRunning = true;
_dummyForm.BeginInvoke(new Action(() =>
{
_watcherRunning = false;
//If we are not inside the com object don't enumerate.
if (_insideCom == false) return;
// Enumerate windows to find dialogs
EnumThreadWndProc callback = new EnumThreadWndProc(CheckWindow);
EnumThreadWindows(GetCurrentThreadId(), callback, IntPtr.Zero);
GC.KeepAlive(callback);
}));
}
}
private bool CheckWindow(IntPtr hWnd, IntPtr lp)
{
// Checks if hWnd is the expected dialog
StringBuilder sb = new StringBuilder(260);
GetClassName(hWnd, sb, sb.Capacity);
if (sb.ToString() == "TMessageForm")
{
//This returns the dialog box's title
GetWindowText(hWnd, sb, sb.Capacity);
//This returns IntPtr.Zero
var hDialogText = GetDlgItem(hWnd, 0xFFFF);
if (hDialogText != IntPtr.Zero)
GetWindowText(hDialogText, sb, sb.Capacity);
//This returns a empty string
GetDlgItemText(hWnd, 0xFFFF, sb, sb.Capacity);
//Only sees the OK button.
IntPtr hCtl = IntPtr.Zero;
HashSet<IntPtr> seen = new HashSet<IntPtr>();
while ((hCtl = GetNextDlgGroupItem(hWnd, hCtl, false)) != IntPtr.Zero)
{
//When we see the same control twice, break out of the loop.
if (seen.Add(hCtl) == false)
break;
GetClassName(hCtl, sb, sb.Capacity);
SendMessage(hCtl, WM_GETTEXT, sb.Capacity, sb)
//Close the dialog by sending WM_CLOSE to the window
SendMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}
//Snip...
}
return true;
}
//Snip...
// P/Invoke declarations
const int WM_CLOSE = 0x0010;
private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
[DllImport("user32.dll")]
private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
[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);
[DllImport("kernel32.dll")]
private static extern int GetCurrentThreadId();
テキストを追加する前にダイアログを中断している可能性があると思いました(上記のコードを中断すると、まだ完全にペイントされていません)。ただしApplication.DoEvents
、列挙を開始する前にStartWindowListenerを内部に配置すると、ダイアログボックスを完全にペイントできますが、上記のコードで投稿したのと同じ結果が得られます。
Ctrl-Cを実行すると、ダイアログボックスで正しく機能するため、ピンチで使用できますが、これを9923回繰り返す必要があるため、プログラムで使用することは避けたいと思います。
メッセージボックスからテキストを取得する方法は他にありますか?