【问题标题】:getting text entered in textbox of other applications using c#使用 c# 获取在其他应用程序的文本框中输入的文本
【发布时间】:2013-07-11 00:10:43
【问题描述】:

我想获取其他应用程序的文本框中的文本。它可能是 gtalk 客户端的文本框或肥皂 UI 屏幕。

根据我的研究,大多数论坛都建议我使用 winapi 来实现这一目标。我没有得到任何好的例子来实现它。

【问题讨论】:

  • 从 Windows 获取文本会有所不同,具体取决于您尝试从中获取文本的内容。例如,可以通过 Windows API 使用 EnumChildWindows 和 GetWindowCaption/GetWindowText 从 winforms 应用程序获取所有文本。然而,从网页或用另一个 GUI 工具包编写的应用程序获取文本是另一回事。我知道没有通用的文​​本抓取器。

标签: c# .net api winapi winforms-interop


【解决方案1】:

这是一个如何通过窗口标题从窗口中获取所有文本的示例。

请参阅 cmets 了解其工作原理。

public class GetWindowTextExample
{
    // Example usage.
    public static void Main()
    {
        var allText = GetAllTextFromWindowByTitle("Untitled - Notepad");
        Console.WriteLine(allText);
        Console.ReadLine();
    }

    // Delegate we use to call methods when enumerating child windows.
    private delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);

    [DllImport("user32")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i);

    [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
    private static extern IntPtr FindWindowByCaption(IntPtr zeroOnly, string lpWindowName);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, [Out] StringBuilder lParam);

    // Callback method used to collect a list of child windows we need to capture text from.
    private static bool EnumChildWindowsCallback(IntPtr handle, IntPtr pointer)
    {
        // Creates a managed GCHandle object from the pointer representing a handle to the list created in GetChildWindows.
        var gcHandle = GCHandle.FromIntPtr(pointer);

        // Casts the handle back back to a List<IntPtr>
        var list = gcHandle.Target as List<IntPtr>;

        if (list == null)
        {
            throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
        }

        // Adds the handle to the list.
        list.Add(handle);

        return true;
    }

    // Returns an IEnumerable<IntPtr> containing the handles of all child windows of the parent window.
    private static IEnumerable<IntPtr> GetChildWindows(IntPtr parent)
    {
        // Create list to store child window handles.
        var result = new List<IntPtr>();

        // Allocate list handle to pass to EnumChildWindows.
        var listHandle = GCHandle.Alloc(result);

        try
        {
            // Enumerates though all the child windows of the parent represented by IntPtr parent, executing EnumChildWindowsCallback for each. 
            EnumChildWindows(parent, EnumChildWindowsCallback, GCHandle.ToIntPtr(listHandle));
        }
        finally
        {
            // Free the list handle.
            if (listHandle.IsAllocated)
                listHandle.Free();
        }

        // Return the list of child window handles.
        return result;
    }

    // Gets text text from a control by it's handle.
    private static string GetText(IntPtr handle)
    {
        const uint WM_GETTEXTLENGTH = 0x000E;
        const uint WM_GETTEXT = 0x000D;

        // Gets the text length.
        var length = (int)SendMessage(handle, WM_GETTEXTLENGTH, IntPtr.Zero, null);

        // Init the string builder to hold the text.
        var sb = new StringBuilder(length + 1);

        // Writes the text from the handle into the StringBuilder
        SendMessage(handle, WM_GETTEXT, (IntPtr)sb.Capacity, sb);

        // Return the text as a string.
        return sb.ToString();
    }

    // Wraps everything together. Will accept a window title and return all text in the window that matches that window title.
    private static string GetAllTextFromWindowByTitle(string windowTitle)
    {
        var sb = new StringBuilder();

        try
        {
            // Find the main window's handle by the title.
            var windowHWnd = FindWindowByCaption(IntPtr.Zero, windowTitle);

            // Loop though the child windows, and execute the EnumChildWindowsCallback method
            var childWindows = GetChildWindows(windowHWnd);

            // For each child handle, run GetText
            foreach (var childWindowText in childWindows.Select(GetText))
            {
                // Append the text to the string builder.
                sb.Append(childWindowText);
            }

            // Return the windows full text.
            return sb.ToString();
        }
        catch (Exception e)
        {
            Console.Write(e.Message);
        }

        return string.Empty;
    }
}

【讨论】:

  • 您好,先生,您的解决方案太好了。如何在任何程序中按类型获取文本,而不仅仅是记事本?
【解决方案2】:

一种选择是使用TestStack.White,这是一个 UI 自动化框架。基于project white,原始文档为here

【讨论】:

    【解决方案3】:

    你是对的。您将需要使用 Windows API。例如:

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
    

    但首先,您可能需要使用 FindWindow 或 FindWindowEx(?) 从桌面递归到窗口层次结构中文本框所在的位置,以获得正确的窗口句柄。

    看起来http://www.pinvoke.net/ 有一个很好的 Win API 数据库。

    希望对您有所帮助。

    【讨论】:

    • 感谢您的回复詹姆斯。我使用查找窗口来获取句柄。我给出了使用 SPY++ 找到的应用程序的类和窗口。我在该应用程序屏幕中有文本框。但我没有在 Spy++ 中得到那个文本框句柄。
    • 你能解释一下 GetWindowText 的作用吗?
    • 也许文本框不是标准的 Windows“文本框”。否则,它应该有一个窗口句柄。你可能不走运:(
    猜你喜欢
    • 2016-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多