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