views:

37

answers:

1

I am attempting to take a screenshot of a window using C# .NET by calling Windows API. I came up with the following code:

    public void ScreenshotWindow(IntPtr windowHandle) {
        Rect Rect = new Rect();

        GetWindowRect(windowHandle, out Rect);
        int width = Rect.right - Rect.left;
        int height = Rect.bottom - Rect.top;

        IntPtr windowDeviceContext = GetWindowDC(windowHandle);
        IntPtr destDeviceContext = CreateCompatibleDC(windowDeviceContext);
        IntPtr bitmapHandle = CreateCompatibleBitmap(windowDeviceContext, width, height);
        IntPtr oldObject = SelectObject(destDeviceContext, bitmapHandle);
        BitBlt(destDeviceContext, 0, 0, width, height, windowDeviceContext, 0, 0, CAPTUREBLT | SRCCOPY);
        SelectObject(destDeviceContext, oldObject);
        DeleteDC(destDeviceContext);
        ReleaseDC(windowHandle, destDeviceContext);

        Image screenshot = Image.FromHbitmap(bitmapHandle);
        DeleteObject(bitmapHandle);

        screenshot.Save("C:\\Screenshots\\" + windowHandle.ToString() + ".png", System.Drawing.Imaging.ImageFormat.Png);
    }

It is a common series of Windows API calls to obtain window screenshot.

Note that I am not looking for alternative ways of obtaining screenshots. I would like to to compare speed of this (fixed) approach and the speed of .NET Graphics.CopyFromScreen() method.

The problem is, when I attempt to take a screenshot of a maximized window running Windows 7, the titlebar and the border (and sometimes other parts of the window) are black.

I think this is caused either by the fact the window is layered or because the title bar of the window is managed by the window itself and therefore the pixel information cannot be accessed (as I have read somewhere).

Does anyone have an idea how to fix this behaviour?

+1  A: 

You're calling all kinds of APIs you should be staying a long distance away from, because taking a screenshot is comfortably covered in the .NET framework. It's much simpler than you might think:

var screen = Screen.PrimaryScreen;

using (var bitmap = new Bitmap(screen.Bounds.Width, screen.Bounds.Height))
using (var graphics = Graphics.FromImage(bitmap))
{
    graphics.CopyFromScreen(new Point(screen.Bounds.Left, screen.Bounds.Top), new Point(0, 0), screen.Bounds.Size);
    bitmap.Save("Test.png", ImageFormat.Png);
}
ErikHeemskerk
Thanks for answering. But I am afraid I forgot to specify that I wanted to solve the task entirely by using Windows API only. I wanted to measure the speed of each approach. Sorry about that.
David