从不使用标签控件的对话框中获取文本?

这是我之前的问题的延续如何压缩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 seen = new HashSet(); 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次,我想避免以编程方式使用它。

有没有其他方法可以尝试从消息框中获取文本?

感谢Sertac的评论,我发现Delphi消息框中的文本不是窗口对象,它们是用’DrawText’方法绘制的。 我使用EasyHook来拦截Windows API调用,现在我可以获取我关心的文本。

 ////It appears that DrawText always calls DrawTextEx so it is getting intercepted twice. //// Only need to hook DrawTextEx static EasyHook.LocalHook _drawTextExAHook; //Snip... public override void Run() { //Snip... IntPtr drawTextExAPtr = EasyHook.LocalHook.GetProcAddress("user32", "DrawTextExA"); _drawTextExAHook = EasyHook.LocalHook.Create(drawTextExAPtr, new DrawTextExDelegate(DrawTextEx_Hooked), null); //The COM stuff must be run in a STA Thread so we can intercept the message boxes that it throws up. var staThread = new Thread(() => { try { var threadID = new[] { GetCurrentThreadId() }; //Enable the hook on the current thread. _drawTextExAHook.ThreadACL.SetInclusiveACL(threadID); //Tell the dummy form to start ComThread _dummyForm = new DummyForm(ComThread); Application.Run(_dummyForm); } finally { if(_drawTextExAHook != null) _drawTextExAHook.Dispose(); } }); staThread.SetApartmentState(ApartmentState.STA); staThread.Name = "Com Thread"; staThread.Start(); //Wait for the Com Thread to finish. staThread.Join(); } //Snip... private delegate int DrawTextExDelegate(IntPtr hdc, string lpchText, int cchText, ref Rect lprc, uint dwDTFormat, ref DRAWTEXTPARAMS lpDTParams); private int DrawTextEx_Hooked(IntPtr hdc, string lpchText, int cchText, ref Rect lprc, uint dwDTFormat, ref DRAWTEXTPARAMS lpDTParams) { LogErrorText(lpchText); return DrawTextEx(hdc, lpchText, cchText, ref lprc, dwDTFormat, ref lpDTParams); } [DllImport("user32.dll")] static extern int DrawTextEx(IntPtr hdc, string lpchText, int cchText, ref Rect lprc, uint dwDTFormat, ref DRAWTEXTPARAMS lpDTParams);