【问题标题】:How to capture data in a window如何在窗口中捕获数据
【发布时间】:2012-05-07 19:59:42
【问题描述】:

我的机器上安装了一个桌面应用程序。当我启动一个程序时,某种窗口会打开。比方说,像这样(只是示例):

所以,我想用 C# 编写一个应用程序,它会找到这个窗口并从中捕获一些数据。

我应该查看哪些工具?我想走一条阻力最小的路。

我需要从文本框中捕获图像、文本,还需要通过文本找到控件并单击它们。

【问题讨论】:

    标签: c# windows


    【解决方案1】:

    我建议你使用很酷但鲜为人知的UI Automation API 来完成这项工作。

    为此,首先要测试的是启动相关的UISpy 工具。它将在屏幕上显示所有可访问窗口的树。它还能够运行一些操作,例如按下菜单、选择项目等。这是使用所谓的UI Automation Control Patterns,它提供了一种独立于控件类型或控件外观来分类和公开控件功能的方法.

    因此,如果您可以使用 UI Spy 自动化此应用程序,您也可以使用 .NET 代码执行完全相同的操作(UISpy 本身只是使用底层 API)。

    这是一篇关于 UI 自动化编程的有趣教程文章:The Microsoft UI Automation Library

    【讨论】:

      【解决方案2】:

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

      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,他们甚至在 tools 中有某种间谍应用程序,看看那个。

      【讨论】:

      • 感谢您的精彩回答。我从顶部开始......你知道可以让我通过文本位置控制的函数的名称是什么(比如说按钮)。 user32.dll 里面有什么东西吗?我走到我的窗前。现在我需要找到控件。
      • 窗口是控件 :) 在 windows api 中没有控件,控件通常由许多窗口构成。 IMO几乎不可能创建通用方法来获取控件内容,要获取Winforms控件的内容请参见mwinapi.sourceforge.net,我会更新我的答案
      【解决方案3】:

      您要捕获什么样的数据?

      你可以试试听windows消息或者读内存。

      【讨论】:

      【解决方案4】:

      根据您将来要完成多少此类任务(或者这项任务的重要性),您可以尝试投资像 Ranorex Spy(Ranorex 工作室是 ott)这样的东西。

      链接:http://www.ranorex.com/product/tools/ranorex-spy.html

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-10-22
          • 2011-02-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多