C# 如何在窗口中捕获数据

C# 如何在窗口中捕获数据,c#,windows,C#,Windows,我的机器上安装了一个桌面应用程序。当我启动一个程序时,某种窗口会打开。比如说,类似这样的事情(只是一个例子): 因此,我想用C语言编写一个应用程序,找到这个窗口并从中捕获一些数据 我应该看什么工具?我想走一条阻力最小的路 我需要从文本框中捕获图像和文本,还需要通过文本找到控件并单击它们。您要捕获的是什么类型的数据 您可以尝试侦听windows消息或读取内存。您应该开始枚举该进程的所有窗口句柄: public static class ProcessSpy { public sta

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

因此,我想用C语言编写一个应用程序,找到这个窗口并从中捕获一些数据

我应该看什么工具?我想走一条阻力最小的路


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

您要捕获的是什么类型的数据


您可以尝试侦听windows消息或读取内存。

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

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

然后,对于每个句柄,获取有关文本和位置的信息,使用位置信息,您可以在该位置拍摄桌面的屏幕截图以获取图像。当然,没有其他方法可以从运行应用程序的窗口获取图像

当您获得控件的屏幕位置,然后使用下面的链接模拟鼠标左键单击,搜索窗口中的一些文本,然后单击控件内的某个点时,以下是单击某个点的方法:

我使用quick类来收集流程中的数据:

 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);
    }
  }
公共静态类ProcessSpy
{
公共静态列表GetDataForProcess(字符串processName)
{
var result=新列表();
Process myProc=Process.GetProcessesByName(processName).FirstOrDefault();
如果(myProc!=null)
{
var myHandles=EnumerateProcessWindowHandles(myProc);
foreach(我的句柄中的IntPtr wndHandle)
{
添加(新的ProcessSpyData(wndHandle));
}
}
返回结果;
}
委托bool EnumThreadDelegate(IntPtr hWnd、IntPtr lParam);
[DllImport(“user32.dll”)]
静态外部bool EnumThreadWindows(int-dwThreadId、EnumThreadDelegate-lpfn、IntPtr-LPRAM);
静态IEnumerable枚举ProcessWindowHandles(进程prc)
{
var handles=newlist();
foreach(prc.Threads中的ProcessThread线程)
EnumThreadWindows(thread.Id,(hWnd,lParam)=>{handles.Add(hWnd);返回true;},IntPtr.Zero);
返回手柄;
}
}
公共类ProcessPydata
{
私有consuint WM_GETTEXT=0x000D;
[DllImport(“user32.dll”,CharSet=CharSet.Auto)]
静态外部IntPtr SendMessage(IntPtr hWnd、uint Msg、int wParam、StringBuilder LPRAM);
[DllImport(“user32.dll”)]
私有静态外部bool GetClientRect(IntPtr hWnd、out RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
私有结构矩形
{
int左、上、右、下;
公共矩形到矩形()
{
返回新矩形(左、上、右-左、下-上);
}
}
[DllImport(“user32.dll”)]
静态外部布尔客户端到屏幕(IntPtr hWnd,参考点lpPoint);
public IntPtr WindowHandle{get;private set;}
公共字符串WindowText{get;private set;}
公共矩形ClientRect{get;private set;}
公共矩形屏幕pos{get;private set;}
公共进程pydata(IntPtr windowHandle)
{
this.WindowHandle=WindowHandle;
GetWindowText();
getWindowsSize();
}
私有void GetWindowText()
{
StringBuilder消息=新的StringBuilder(1024);
SendMessage(this.WindowHandle,WM_GETTEXT,message.Capacity,message);
this.WindowText=message.ToString();
}
私有void getWindowsSize()
{
var nativeRect=new RECT();
GetClientRect(this.WindowHandle,out nativeRect);
this.ClientRect=nativeRect.ToRectangle();
点loc=此.ClientRect.Location;
ClientToScreen(this.WindowHandle,ref loc);
this.ScreenPos=新矩形(loc,this.ClientRect.Size);
}
}
这应该让你们开始了,但你们必须意识到,若应用程序使用的是非标准控件,那个么用这种方法就并没有办法从中获取文本,而对于图像,你们可能会在查看可执行资源时得到更好的结果

更新


获取各种控件类型(MFC、winforms、Delphi VCL等)的控件文本将是一项非常艰巨的任务,但对于winforms see Excellent,它们甚至有某种间谍应用程序,请看。

取决于您将来将要执行的此类任务的数量(或此任务的重要性)你可以尝试投资Ranorex Spy(Ranorex studio是ott)之类的东西


链接:

我建议你使用酷炫但鲜为人知的方法来完成这项工作

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

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


这里有一篇关于UI自动化编程的有趣的教程文章:

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

textboxs\pictures。我还需要点击一个按钮。我应该如何收听windows消息?请看这篇文章:并尝试使用spy++(),谢谢你的回答。我从顶部开始…你知道这个函数的名字吗?它可以让我通过文本(比如按钮)控制位置。user32.dll中有什么内容吗?我走到窗前。现在我需要找到控件。窗口是控件:)在windows api中没有控件,控件通常是从许多窗口构造的。在我看来,几乎不可能创建通用方法来获取控件内容,以获取Winfo的内容