当使用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/

10-11 23:07
查看更多