.NET - 在特定坐标处捕获光标位图

时间:2013-08-11 00:51:59

标签: c# .net vb.net cursor interop

声明

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

背景

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

要求

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

问题

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

1 个答案:

答案 0 :(得分:1)

使用Hans Passant提供的信息实现了解决此问题细节的解决方案,因此所有信用都必须归他所有。

当前设置如下所示:

Environment definition

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

解决方案

  • 获取要测试的应用程序的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坐标序列化为一个长值:

    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 来获取位图:

    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 包含被探测应用程序设置的光标位图,但坐标始终指示“物理”位置。