如何在窗口中捕获数据

4
我有一个桌面应用程序安装在我的计算机上。当我启动程序时,会弹出某种窗口,就像这个例子:enter image description here
因此,我想用C#编写一个应用程序,可以找到这个窗口并从中获取一些数据。
我应该使用哪些工具?我希望选择最简单的方法。
我需要捕获图像、文本框中的文本,并通过文本查找控件并单击它们。
5个回答

6
我建议您使用鲜为人知的UI Automation API来完成这项工作。
为此,首先要测试的是启动关联的UISpy工具。它将显示屏幕上所有可访问窗口的树形结构。它还能运行一些操作,比如按菜单、选择项目等。它使用的是所谓的UI自动化控制模式,它提供了一种分类和公开控件功能的方式,独立于控件类型或控件外观。
因此,如果您可以使用UI Spy自动化该应用程序,那么您也可以使用.NET代码做完全相同的事情(UISpy本身只是使用底层API)。
这是一个有趣的UI自动化编程教程文章:Microsoft UI Automation Library

2
您应该开始枚举该进程的所有窗口句柄:

https://dev59.com/rHE85IYBdhLWcg3w8IbK#2584672

对于每个句柄,获取文本和位置信息,使用位置信息可以在该位置上截取桌面屏幕以获取图像。据我所知,没有其他方法可以从运行应用程序的窗口中获取图像。
当您获得控件的屏幕位置后,使用以下链接模拟左键单击,搜索窗口以获取一些文本,然后单击控件内的某个点,这是将单击一个点的方法:

https://dev59.com/cWkv5IYBdhLWcg3wxjvQ#10355905

我组织了一个快速班级来收集那些用于处理的数据。
 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,他们甚至在tools中拥有某种间谍应用程序,请查看。

谢谢你的好回答。我从头开始...你知道哪个函数可以让我通过文本(比如按钮)来控制位置吗?有没有在user32.dll中的相关内容?我已经找到了我的窗口,现在需要找到控件。 - user194076
窗口是控件:) 在Windows API中,没有控件,通常控件由许多窗口构建。我认为几乎不可能创建通用方法来获取控件内容,如果要获取Winforms控件的内容,请参见http://mwinapi.sourceforge.net/ ,我会更新我的答案。 - Antonio Bakula

1

你想捕获什么类型的数据?

你可以尝试监听 Windows 消息或读取内存。


文本框\图片。我还需要点击一个按钮。我应该如何监听Windows消息? - user194076
请查看此帖子:https://dev59.com/82kw5IYBdhLWcg3wwdQS,并尝试使用spy++(http://technet.microsoft.com/en-us/library/dd460725.aspx)进行实验。 - animaonline

0

0

除了注入您想要检查的应用程序之外,没有其他方法。这就是UISpy实际运行的方式。这也是为什么应该使用管理员凭据运行UISpy的原因。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接