当使用Print Screen
+ Alt
键组合手动捕获窗口时,得到以下信息:
但是如果我尝试使用Windows API以编程方式进行操作,则会得到以下信息:
为什么会出现差异?如何以编程方式获得第一个?
这是我的代码:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool PrintWindow(IntPtr hWnd, IntPtr hdcBlt, int nFlags);
public Bitmap PrintWindow()
{
Bitmap bmp = new Bitmap(windowRect.Width, windowRect.Height, PixelFormat.Format32bppArgb);
Graphics gfxBmp = Graphics.FromImage(bmp);
IntPtr hdcBitmap = gfxBmp.GetHdc();
bool success = PrintWindow(windowHandle, hdcBitmap, 0);
gfxBmp.ReleaseHdc(hdcBitmap);
if (!success)
{
Console.WriteLine("Error copying image");
Console.WriteLine(getLastError());
}
gfxBmp.Dispose();
return bmp;
}
更新:
使用BitBlt可以做到这一点。
这是code from CodeProject仍会返回黑屏图像:
public Image CaptureWindow(IntPtr handle)
{
// get te hDC of the target window
IntPtr hdcSrc = User32.GetWindowDC(handle);
// get the size
User32.RECT windowRect = new User32.RECT();
User32.GetWindowRect(handle,ref windowRect);
int width = windowRect.right - windowRect.left;
int height = windowRect.bottom - windowRect.top;
// create a device context we can copy to
IntPtr hdcDest = GDI32.CreateCompatibleDC(hdcSrc);
// create a bitmap we can copy it to,
// using GetDeviceCaps to get the width/height
IntPtr hBitmap = GDI32.CreateCompatibleBitmap(hdcSrc,width,height);
// select the bitmap object
IntPtr hOld = GDI32.SelectObject(hdcDest,hBitmap);
// bitblt over
GDI32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt);
// restore selection
GDI32.SelectObject(hdcDest,hOld);
// clean up
GDI32.DeleteDC(hdcDest);
User32.ReleaseDC(handle,hdcSrc);
// get a .NET image object for it
Image img = Image.FromHbitmap(hBitmap);
// free up the Bitmap object
GDI32.DeleteObject(hBitmap);
img.Save("SampleImage.png");
return img;
}
我尝试了
CopyPixelOperation
的许多组合(在131,000个中的大约15,000个位置),但是仍然无法正常工作。使用Windows 8,AMD Radeon HD 6870。
更新2
窗口似乎是透明的,从而使窗口的蓝色渗出。当我将窗口颜色更改为黑色时(使用Windows个性化对话框),我得到的东西大致类似于第二个窗口。边界仍然不见了。
我还没有找到解决方案,但这是对问题的洞察力。
最佳答案
PrintWindow不起作用的原因是因为它取决于应用程序对WM_PRINT消息的正确处理。许多应用程序都带有WM_PRINT标记,因此无法正确实现或测试它。因此,除非您仅在已知且经过测试的应用程序上使用它,否则依赖它是一个坏主意。
如果要捕获屏幕上显示的窗口,只需从“桌面”窗口句柄(GetDesktopWindow())中将其blt,然后仅blt包括该窗口的rect即可。
透明度是抓窗的问题。无法捕获现代Windows OS的窗口,因为没有图像文件类型支持像模糊基础图像这样的奇特效果。但是,可以将简单的透明度捕获到PNG文件中。
假设窗口看起来像在屏幕上看到的那样时要格外小心。根据下面的内容,这可能不是正确的。复制下面的所有内容可能也不是一个好主意,因为它可能未经许可而无法显示在图像中,例如在商务演示文稿中的Excel屏幕快照下显示的显式背景图像:)。
如果从桌面启动,则复制在屏幕上看到的内容,包括所有覆盖的窗口和基础窗口(透明的地方)。与PrintWindow一样,通常只捕获窗口是“干净的”,但是您可能希望将其合成在您选择的背景上,例如白色或蓝色。如果您想从屏幕上跳开,可以使用一些方法暂时隐藏覆盖目标的窗口,但是EnumWindows等的工作量很大。
在Windows中,正确地抓取Windows并非易事,而且许多抓屏应用程序之间的竞争也因其处理此问题的能力而异。同样,在Windows中,有几种方法可以使窗口区域透明,也可以将它们一起使用。
此外,在Vista +中,还有DWM thumbnail API,它允许您获取在窗口上绘制的应用程序窗口的副本。有关演示和源,请参见ShareX(以前称为zScreen)。
最后,您可以查看Open Broadcaster Software的源代码,它使用Direct3D进行屏幕抓取。
关于windows - PrintWindow位图不同于PrintScreen键位图,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16351012/