получение текста, введенного в текстовое поле других приложений, с помощью С#

Я хочу получить текст, который находится в текстовом поле другого приложения. Это может быть текстовое поле клиента gtalk или мыльный экран пользовательского интерфейса.

Основываясь на моем исследовании, большинство форумов предлагали winapi как концепцию, которую я должен использовать для достижения этой цели. У меня не было хороших примеров для реализации этого.


person Bharath    schedule 12.07.2013    source источник
comment
Получение текста из окон отличается в зависимости от того, из чего вы пытаетесь получить текст. Получить весь текст из приложения winforms, например, можно через Windows API, используя EnumChildWindows и GetWindowCaption/GetWindowText. Принимая во внимание, что получение текста с веб-страницы или приложения, написанного в другом наборе инструментов с графическим интерфейсом, — это совсем другая история. Я не знаю универсального текстового граббера.   -  person Francis MacDonald    schedule 12.07.2013


Ответы (3)


Вот пример того, как получить весь текст из окна по его заголовку.

Пожалуйста, смотрите комментарии для объяснения того, как это работает.

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;
    }
}
person Francis MacDonald    schedule 12.07.2013
comment
Привет, сэр, Ваше решение так здорово. Как получить текст по типу в любой программе, не только в блокноте? - person Mr Neo; 20.08.2015

Ты прав. Вам нужно будет использовать 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.

Надеюсь, это поможет.

person James R.    schedule 12.07.2013
comment
Спасибо за ваш ответ Джеймс. Я использовал окно поиска, чтобы получить дескриптор. я дал класс и окно приложения, которое было найдено с помощью SPY ++. У меня есть текстовое поле на этом экране приложения. Но я не получаю дескриптор этого текстового поля в Spy++. - person Bharath; 12.07.2013
comment
не могли бы вы пояснить мне, что делает GetWindowText? - person Bharath; 12.07.2013
comment
Возможно, текстовое поле не является стандартным текстовым полем Windows. В противном случае он должен иметь дескриптор окна. Вам может не повезти :( - person James R.; 12.07.2013
comment
GetWindowText - person James R.; 12.07.2013

Одним из вариантов может быть использование TestStack.White, среды автоматизации пользовательского интерфейса. Он основан на проекте white, а исходная документация находится здесь.

person devdigital    schedule 12.07.2013