充分利用未使用的标签控制对话框中的文本? [英] Getting the text from a dialog box that does not use a label control?

查看:267
本文介绍了充分利用未使用的标签控制对话框中的文本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我刚才的问题的延续的如何剿对话框中的INPROC COM服务器显示

This is a continuation of my previous question How to supress a dialog box an Inproc COM Server displays.

我的情况回顾一下:我有一个第三方Delphi编写的一个进程内COM服务器。其中一个我称之为如果它捕获特定类型的错误会显示一个错误消息对话框的功能。这个问题是我想处理大量的数据,我使用的数据源导致该错误对话框弹出很多(感谢我以前的问题的答案,现在自动关闭,我可以运行它完成后,它会显示的对话框,并要求别人按确定9923倍)。该工艺块,直到消息对话框关闭

A recap of my situation: I have a Inproc COM Server written in Delphi 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 (thanks to the answer of my previous question it now auto closes and I was able to run it to completion, it would have shown the dialog box and required someone to press OK 9923 times). The process blocks till the message box is closed.

我想有错误对话框说什么更好的记录。然而,任何企图得到得到对话框失败的正文文本。

I would like to have better logging of what the error dialog said. However any attempt to get get the body text of the dialog box has failed.

//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开始之前枚举允许对话框完全绘制,但我仍然得到相同的结果,因为我贴有上面的代码。

I thought I may have been interrupting the dialog before it gets to add the text to it (it is not fully painted yet when I break in the above code). However putting a Application.DoEvents inside StartWindowListener before it starts the enumeration allows the dialog box to fully paint but I still get the same results as I posted with the above code.

做一个按Ctrl-C正常工作的对话框,所以我可以使用,在紧要关头,但是,我不得不重复这个9923倍,我想避免使用编程。

Doing a Ctrl-C works correctly on the dialog box so I could use that in a pinch, but being that I have to repeat this 9923 times I would like to avoid using that programmatically.

有没有其他的方法,我可以尝试从消息框中的文本?

Is there any other methods I can try to get the text from the Message box?

推荐答案

感谢的 Sertac的评论我发现在Delphi的消息框文本不窗口对象,它们画在用DrawText的方法。我用 EasyHook 拦截的Windows API调用,我现在能抢我关心的文字。

Thanks to Sertac's comment I found out that the text in Delphi's message boxes are not window objects, they are drawn on with the 'DrawText' methods. I used EasyHook to intercept the Windows API calls and I am now able to grab the text I care about.

////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);

这篇关于充分利用未使用的标签控制对话框中的文本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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