无法从另一个应用程序(窗口)获取文本
本文关键字:窗口 获取 取文本 应用程序 另一个 | 更新日期: 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);
}
}