Can't get text from another application (window)

故事扮演 提交于 2020-01-25 12:39:49

问题


I am trying to extract text from another application. This application may for now be whatever simple, I just want it to work (for now).

The code I use:

public static class ModApi
{
    [DllImport("user32.dll", EntryPoint = "SendMessageTimeout", SetLastError =     true, CharSet = CharSet.Unicode)]
    public static extern uint SendMessageTimeoutText(IntPtr hWnd, int Msg, int countOfChars, StringBuilder text, uint flags, uint uTimeoutj, uint result);

    public static string GetText(IntPtr hwnd)
    {
        var text = new StringBuilder(1024);

        if (SendMessageTimeoutText(hwnd, 0xd, 1024, text, 0x2, 5000, 0) != 0)
        {
            return text.ToString();
        }

        MessageBox.Show(text.ToString());
        return "";
    }
}

I call this code using:

IntPtr MytestHandle = new IntPtr(0x00788600);
HandleRef hrefHWndTarget = new HandleRef(null, MytestHandle);

where 0x00788600 is an example of one of the applications I'm running (I'm 100% sure that this is the main window handle).

I need to have the text from one textbox inside the "other" application, but when I use my code it returns an empty string every time

Suggestions?


回答1:


I can't see any mistakes with your code. I suggest checking whether your handle is correct or not.

However, in order to get the text of the TextBox, you will have to use the handle of the actual control. The MainWindowHandle will only return the form caption.

I created a dummy application "WindowsFormsApplication1" with some controls in it and used the following code to get all the texts:

[Flags]
internal enum SendMessageTimeoutFlags : uint
{
    SMTO_NORMAL = 0x0,
    SMTO_BLOCK = 0x1,
    SMTO_ABORTIFHUNG = 0x2,
    SMTO_NOTIMEOUTIFNOTHUNG = 0x8,
    SMTO_ERRORONEXIT = 0x20
}

// Specific import for WM_GETTEXTLENGTH
[DllImport("user32.dll", EntryPoint = "SendMessageTimeout", CharSet = CharSet.Auto)]
internal static extern int SendMessageTimeout(
    IntPtr hwnd,
    uint Msg,              // Use WM_GETTEXTLENGTH
    int wParam,
    int lParam,
    SendMessageTimeoutFlags flags,
    uint uTimeout,
    out int lpdwResult);

// Specific import for WM_GETTEXT
[DllImport("user32.dll", EntryPoint = "SendMessageTimeout", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern uint SendMessageTimeoutText(
    IntPtr hWnd,
    uint Msg,              // Use WM_GETTEXT
    int countOfChars,
    StringBuilder text,
    SendMessageTimeoutFlags flags,
    uint uTImeoutj,
    out IntPtr result);

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

// callback to enumerate child windows
private delegate bool EnumWindowProc(IntPtr hwnd, IntPtr parameter);

private static bool EnumChildWindowsCallback(IntPtr handle, IntPtr pointer)
{
    // this method will be called foreach child window
    // create a GCHandle from pointer
    var gcHandle = GCHandle.FromIntPtr(pointer);

    // cast pointer as list
    var list = gcHandle.Target as List<IntPtr>;

    if (list == null)
        throw new InvalidCastException("Invalid cast of GCHandle as List<IntPtr>");

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

    return true;
}

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 the children
        EnumChildWindows(parent, EnumChildWindowsCallback, GCHandle.ToIntPtr(listHandle));
    }
    finally
    {
        // free unmanaged list handle
        if (listHandle.IsAllocated)
            listHandle.Free();
    }

    return result;
}

internal static string GetText(IntPtr hwnd)
{
    const uint WM_GETTEXTLENGTH = 0x000E;
    const uint WM_GETTEXT = 0x000D;
    int length;
    IntPtr p;

    var result = SendMessageTimeout(hwnd, WM_GETTEXTLENGTH, 0, 0, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 5, out length);

    if (result != 1 || length <= 0)
        return string.Empty;

    var sb = new StringBuilder(length + 1);

    return SendMessageTimeoutText(hwnd, WM_GETTEXT, sb.Capacity, sb, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 5, out p) != 0 ?
            sb.ToString() : 
            string.Empty;
}

public static void Main(string[] args)
{
    var p = Process.GetProcessesByName("WindowsFormsApplication1").First();            

    Console.WriteLine(GetText(p.MainWindowHandle));    // main window handle of form, returns "Form1"
    Console.WriteLine(GetText(new IntPtr(0x70BA0)));   // actual textbox handle, used Winspector, returns "quertz"

    // iterate through dynamic handles of children
    foreach (var hwnd in GetChildWindows(p.MainWindowHandle))
        Console.WriteLine($"{hwnd}:{GetText(hwnd)}");

    Console.ReadLine();
}     



回答2:


To save a lot of code you can use the Autoit Library.

Install the nuget package called AutoItX.Dotnet

using AutoIt;

class Program
{
    static void Main(string[] args)
    {
        var text = AutoItX.ControlGetText("Untitled - Notepad", "", "[CLASSNN:Edit1]");

        //In your case, since you are dealing with handles, you can use:
        var windowHandle = new IntPtr(0x00788600);
        var controlHandle = new IntPtr(0x00000000);
        var text2 = AutoItX.ControlGetText(windowHandle, controlHandle);
    }
}


来源:https://stackoverflow.com/questions/39008433/cant-get-text-from-another-application-window

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!