这是我之前的问题如何抑制 Inproc COM 服务器显示的对话框的延续。
背景:
回顾一下我的情况:我有一个来自第三方的用 Delphi 编写的 Inproc COM 服务器。如果捕获特定类型的错误,我调用的函数之一将显示错误消息对话框。问题是我正在尝试批量处理数据,而我正在使用的数据源导致该错误对话框弹出很多(感谢我之前的问题的答案,它现在自动关闭并且我能够运行它完成,它会显示对话框并要求有人按 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 次,我想避免以编程方式使用它。
有没有其他方法可以尝试从消息框中获取文本?