无法从另一个应用程序(窗口)获取文本

本文关键字:窗口 获取 取文本 应用程序 另一个 | 更新日期: 2023-09-27 18:02:56

我正在尝试从另一个应用程序提取文本。这个应用程序现在可能很简单,我只是想让它工作(目前)。

我使用的代码:

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 "";
    }
}

我使用以下方式调用这段代码:

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

其中0x00788600是我正在运行的应用程序之一的示例(我100%确定这是主窗口句柄)。

我需要在"other"应用程序中有一个文本框中的文本,但是当我使用我的代码时,每次

都返回一个空字符串

建议吗?

无法从另一个应用程序(窗口)获取文本

我看不出你的代码有任何错误。我建议您检查一下您的句柄是否正确。

然而,为了获得TextBox的文本,您将不得不使用实际控件的句柄。MainWindowHandle将只返回表单标题。

我创建了一个虚拟应用程序"WindowsFormsApplication1",其中包含一些控件,并使用以下代码获取所有文本:

[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();
}     

为了节省大量的代码,你可以使用Autoit Library

安装名为AutoItX.Dotnet的nuget包

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