我想要截取一个应用程序的屏幕截图,并且希望矩形框中不属于应用程序区域的部分是透明的。例如,在标准的Windows应用程序中,我想要将圆角设置为透明。
我编写了一个快速的测试应用程序,它可以在XP上运行(或在关闭aero的vista/windows 7上运行)。
当我在XP上运行这个测试应用程序(或在关闭Aero的Vista/Windows 7上),我会得到像这样的东西,这非常好,因为我可以从中提取一个异或掩码,稍后可以与BitBlt一起使用。
这里的问题是,在启用Aero的Vista或Windows 7上,窗口上不一定有区域,实际上大多数情况下都没有。有人能帮我想出在这些平台上构建类似于这样的遮罩的方法吗?
以下是我已经尝试过的一些方法...
1. 使用PrintWindow函数:这个方法行不通,因为它返回的是一个关掉Aero的窗口的屏幕截图,而带有Aero的窗口形状与之不同。
2. 使用Desktop Window Manager API获取全尺寸缩略图:这个方法也行不通,因为它直接绘制到屏幕上,从我所了解的内容来看,你无法直接从这个API中获取屏幕截图。是的,我可以打开一个粉色背景的窗口,显示缩略图,拍张屏幕截图,然后隐藏这个临时窗口,但这是一个可怕的用户体验和完全的hack,我不想把我的名字放在上面。
我编写了一个快速的测试应用程序,它可以在XP上运行(或在关闭aero的vista/windows 7上运行)。
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
// Just find a window to test with
IntPtr hwnd = FindWindowByCaption(IntPtr.Zero, "Calculator");
WINDOWINFO info = new WINDOWINFO();
info.cbSize = (uint)Marshal.SizeOf(info);
GetWindowInfo(hwnd, ref info);
Rectangle r = Rectangle.FromLTRB(info.rcWindow.Left, info.rcWindow.Top, info.rcWindow.Right, info.rcWindow.Bottom);
IntPtr hrgn = CreateRectRgn(info.rcWindow.Left, info.rcWindow.Top, info.rcWindow.Right, info.rcWindow.Bottom);
GetWindowRgn(hwnd, hrgn);
// fill a rectangle which would be where I would probably
// write some mask color
g.FillRectangle(Brushes.Red, r);
// fill the region over the top, all I am trying to do here
// is show the contrast between the applications region and
// the rectangle that the region would be placed in
Region region = Region.FromHrgn(hrgn);
region.Translate(info.rcWindow.Left, info.rcWindow.Top);
g.FillRegion(Brushes.Blue, region);
}
当我在XP上运行这个测试应用程序(或在关闭Aero的Vista/Windows 7上),我会得到像这样的东西,这非常好,因为我可以从中提取一个异或掩码,稍后可以与BitBlt一起使用。
这里的问题是,在启用Aero的Vista或Windows 7上,窗口上不一定有区域,实际上大多数情况下都没有。有人能帮我想出在这些平台上构建类似于这样的遮罩的方法吗?
以下是我已经尝试过的一些方法...
1. 使用PrintWindow函数:这个方法行不通,因为它返回的是一个关掉Aero的窗口的屏幕截图,而带有Aero的窗口形状与之不同。
2. 使用Desktop Window Manager API获取全尺寸缩略图:这个方法也行不通,因为它直接绘制到屏幕上,从我所了解的内容来看,你无法直接从这个API中获取屏幕截图。是的,我可以打开一个粉色背景的窗口,显示缩略图,拍张屏幕截图,然后隐藏这个临时窗口,但这是一个可怕的用户体验和完全的hack,我不想把我的名字放在上面。
3. 使用 Graphics.CopyFromScreen 或其他类似的 pinvoke: 这不起作用,因为我不能假设我需要信息的窗口在屏幕的顶部。
目前,我能想到的最好的解决方案是,在 Windows 7 和 Vista 上特殊处理 Aero,手动擦掉角落,通过硬编码一些我绘制的图形路径,但这个解决方案会很糟糕,因为任何执行自定义皮肤的应用程序都会中断。
你能想到另一个或更好的解决方案吗?
如果你在这里,感谢你抽出时间阅读这篇文章,我非常感激你能提供任何帮助或指导!
GetWindowRgn()
获取窗口的区域。如果你改用GetWindowDC()
(它获取包括标题栏在内的窗口 DC),然后使用SelectObject()
或GetObject()
来检索区域,会发生什么?这样做有什么不同吗?还有GetClipRgn()
可能返回不同的形状。 - Malvineous