我的机器上安装了一个桌面应用程序。当我启动一个程序时,某种窗口会打开。比方说,这样的事情(只是例子):
所以,我想用 C# 编写一个应用程序,它会找到这个窗口并从中捕获一些数据。
我应该看什么工具?我想走一条阻力最小的路。
我需要从文本框中捕获图像、文本,还需要通过文本找到控件并单击它们。
我建议你使用很酷但鲜为人知的UI 自动化 API来完成这项工作。
为此,首先要测试的是启动相关的UISpy工具。它将在屏幕上显示所有可访问窗口的树。它还能够运行一些操作,例如按下菜单、选择项目等。这是使用所谓的UI 自动化控件模式,它提供了一种独立于控件类型或外观的对控件的功能进行分类和公开的方法控制。
因此,如果您可以使用 UI Spy 自动化此应用程序,您也可以使用 .NET 代码执行完全相同的操作(UISpy 本身只是使用底层 API)。
这是一篇关于 UI 自动化编程的有趣教程文章:Microsoft UI 自动化库
您应该开始枚举该进程的所有窗口的句柄:
https://stackoverflow.com/a/2584672/351383
然后对于每个句柄获取有关文本和位置的信息,通过位置信息,您可以在该位置截取桌面的屏幕截图以获取图像 AFAIK 没有其他方法可以从正在运行的应用程序窗口获取图像。
当您获得控件的屏幕位置时,然后使用下面的链接模拟鼠标左键单击,在窗口中搜索一些文本,然后单击控件内的某个点,这是单击一个点的方法:
https://stackoverflow.com/a/10355905/351383
我整理了快速课程来收集流程数据:
public static class ProcessSpy
{
public static List<ProcessSpyData> GetDataForProcess(string processName)
{
var result = new List<ProcessSpyData>();
Process myProc = Process.GetProcessesByName(processName).FirstOrDefault();
if (myProc != null)
{
var myHandles = EnumerateProcessWindowHandles(myProc);
foreach (IntPtr wndHandle in myHandles)
{
result.Add(new ProcessSpyData(wndHandle));
}
}
return result;
}
delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")]
static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);
static IEnumerable<IntPtr> EnumerateProcessWindowHandles(Process prc)
{
var handles = new List<IntPtr>();
foreach (ProcessThread thread in prc.Threads)
EnumThreadWindows(thread.Id, (hWnd, lParam) => { handles.Add(hWnd); return true; }, IntPtr.Zero);
return handles;
}
}
public class ProcessSpyData
{
private const uint WM_GETTEXT = 0x000D;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam);
[DllImport("user32.dll")]
private static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
int left, top, right, bottom;
public Rectangle ToRectangle()
{
return new Rectangle(left, top, right - left, bottom - top);
}
}
[DllImport("user32.dll")]
static extern bool ClientToScreen(IntPtr hWnd, ref Point lpPoint);
public IntPtr WindowHandle { get; private set; }
public string WindowText { get; private set; }
public Rectangle ClientRect { get; private set; }
public Rectangle ScreenPos { get; private set; }
public ProcessSpyData(IntPtr windowHandle)
{
this.WindowHandle = windowHandle;
GetWindowText();
GetWindowSize();
}
private void GetWindowText()
{
StringBuilder message = new StringBuilder(1024);
SendMessage(this.WindowHandle, WM_GETTEXT, message.Capacity, message);
this.WindowText = message.ToString();
}
private void GetWindowSize()
{
var nativeRect = new RECT();
GetClientRect(this.WindowHandle, out nativeRect);
this.ClientRect = nativeRect.ToRectangle();
Point loc = this.ClientRect.Location;
ClientToScreen(this.WindowHandle, ref loc);
this.ScreenPos = new Rectangle(loc, this.ClientRect.Size);
}
}
这应该可以帮助您入门,但是您必须注意,如果应用程序使用非标准控件,则无法使用此方法从中获取文本,对于图像,查看可执行资源可能会获得更好的结果。
更新
获取各种控件类型(MFC、winforms、Delphi VCL 等)的控件文本将是一项非常艰巨的任务,但是对于 winforms,请参阅出色的Managed Windows API ,他们甚至在工具中有某种间谍应用程序,看看那个。
您要捕获什么样的数据?
您可以尝试收听 Windows 消息或读取内存。
除了注入您要检查的应用程序之外,别无他法。这就是 UISpy 实际运行的方式。这也是为什么 UISpy 应该使用管理凭据运行的原因。
根据您将来要执行多少此类任务(或这项任务的重要性),您可以尝试投资像 Ranorex Spy(Ranorex 工作室是 ott)这样的东西。