1

免责声明

这个问题有点类似于 StackOverflow 上的另一个问题,C# - Capturing the Mouse cursor image - 但要求略有不同。

背景

  • 我正在编写一个可编写脚本的自动化客户端,它从 3 个旧版 Win32 系统中删除数据。
  • 当光标悬停在某些特定区域上时,其中两个系统可以通过光标位图的变化来指示已完成任务的存在。不提供其他提示(颜色变化、状态消息)。
  • 我自己的代码来自免责声明中提到的原始帖子。

要求

  • 虽然我能够通过以编程方式将光标移动到特定坐标并通过 CURSORINFO 捕获它来捕获光标位图,但其想法是允许交互式用户继续使用计算机。事实上,强制定位会破坏该过程。

问题

  • 有没有办法通过参数化位置捕获光标位图(例如,请求 CURSORINFO,就好像焦点在坐标 X、Y 的窗口 W 中一样)?
4

1 回答 1

1

使用Hans Passant提供的信息实施了满足此问题细节的解决方案,因此所有功劳都归于他。

当前设置如下图:

环境定义

它在有两个显示器的机器上运行。图片中未显示的是一个实际负责事件监控和数据抓取的小型应用程序 - 它以最小化和无人值守的方式运行。

解决方案

  • 获取要测试的应用程序的Window句柄(本例中我循环了Process.GetProcesses ()返回的所有进程:

        IntPtr _probeHwnd;
        var _procs = Process.GetProcesses();
    
        foreach (var item in _procs)
        {
            if (item.MainWindowTitle == "WinApp#1")
            {
                _probeHwnd= item.MainWindowHandle;
                break;
            }
        }
    
  • 使用目标应用程序的窗口句柄,我们现在可以制作特定的消息并通过SendMessage发送给它。

  • 为了将坐标传递给 SendMessage,我们需要将 X 和 Y 坐标序列化为单个 long 值:

    public int MakeLong(short lowPart, short highPart)
    {
        return (int)(((ushort)lowPart) | (uint)(highPart << 16)); 
    }
    
  • 知道了我们要探测的具体坐标(_probeX,_probeY),现在我们可以发出 WM_NCHITTEST 消息:

    SendMessage(_probeHwnd, WM_NCHITTEST, NULL, (LPARAM)MakeLong(_probeX, _probeY));
    
  • 我们需要GetCursorInfo来获取 Bitmap:

    Win32Stuff.CURSORINFO ci = new Win32Stuff.CURSORINFO();
    Win32Stuff.GetCursorInfo(ci);
    
  • 检查 GetCursorInfo 的返回标志是否指示光标正在显示(pco.flags == CURSOR_SHOWING):

  • 使用CopyIcon以获得光标位图的有效句柄:

    IntPtr hicon = default(IntPtr);
    hicon = Win32Stuff.CopyIcon(ci.hCursor);
    
  • 使用GetIconInfo从处理程序中提取信息:

    Win32Stuff.ICONINFO icInfo = default(Win32Stuff.ICONINFO);
    Win32Stuff.GetIconInfo(hicon, icInfo);
    
  • 使用System.Drawing.Icon类通过 Icon.FromHandle 获取可管理的副本,并传递CopyIcon返回的值;

    Icon ic = Icon.FromHandle(hicon);
    
  • 通过 Icon.ToBitmap 方法提取位图。

    Bitmap bmp = ic.ToBitmap();
    

限制

  • 此解决方案在两种不同的操作系统上进行了测试:Windows XP 和 Windows 8。它仅适用于 Windows XP。在 Windows 8 上,光标会闪烁并立即返回“正确”格式,捕获的 CURSORINFO 反映了这一点。
  • 测试点区域必须是可见的(即,应用程序不能被最小化,并且测试点不能在重叠窗口下。但是,被测试的窗口可能部分重叠 - 它不需要焦点。)
  • 当发出WM_NCHITTEST时,WebApp 上的当前物理光标将更改为被探测应用程序设置的任何光标位图。CURSORINFO包含被探测应用程序设置的光标位图,但坐标始终指示“物理”位置。
于 2013-08-16T17:28:16.073 回答