5
votes

I'm trying to take a screenshot of a Chrome window. It looks like this:

Chrome window

When I use PrintWindow to get the screenshot, I can see a flicker on the window titlebar/Chrome tab area. The captured screenshot contains a strange rendering of a titlebar in Windows Basic style (even though my machine runs the Aero theme):

Captured image

I've noticed that some other apps also exhibit a similar behavior where they flicker on-screen but the titlebar artifact is not visible in the captured screenshot. Apps that do this include Office 2010, IE 10, and the Trillian tabbed chat window — in other words, windows that extend the non-client area seem to have this issue.

The code that reproduces this is simple:

void Screenshot(HWND hWnd) {

    RECT rc;
    GetClientRect(hWnd, &rc);

    HDC hdcScreen = GetDC(NULL);
    HDC hdc = CreateCompatibleDC(hdcScreen);
    HBITMAP hbmp = CreateCompatibleBitmap(hdcScreen, 
        rc.right - rc.left, rc.bottom - rc.top);
    SelectObject(hdc, hbmp);

    //Print to memory hdc
    PrintWindow(hWnd, hdc, PW_CLIENTONLY);

}

Why am I seeing flickering and strange visual artifacts? What can I do to stop it?

2
Using your code, I can't reproduce. Windows Seven 64. Using 32b or 64b builds. Using PW_CLIENTONLY or 0. Target: Chrome Main Window, or Excel 2010 Main Window. No Flicker, "almost" good PNG (using GDIPLUS)manuell
@manuell: What's interesting is that from my actual application, the flicker happens every time I call PrintWindow (which is shortly after the window gets focus). In a barebones test app where I do while (1) { Screenshot(hWnd); Sleep(100); }, the flicker is intermittent.josh3736
Apps process "focus" and "activity" windows message way long /before/ actual paint occurs, imho. I bet that your request comes too soon. Try to delay more. Difficult to help without context. Screenshots taken with the good old BitBblt do not flicker, and consume less resources, but give sometime funny results when windows are just "minimizing" or "restoring"manuell
@manuell: I've tried delaying the call to no avail. Regardless, calling the screenshot function from a test harness in a loop results in flicker even when not switching windows.josh3736
And why don't you just BitBlt?manuell

2 Answers

1
votes

If Aero is enabled, use BitBlt instead.

This comment in the chromium desktop capture source code was especially helpful:

// When desktop composition (Aero) is enabled each window is rendered to a
// private buffer allowing BitBlt() to get the window content even if the
// window is occluded. PrintWindow() is slower but lets rendering the window
// contents to an off-screen device context when Aero is not available.
1
votes

For those, who have the same problem, do this:

const uint PW_RENDERFULLCONTENT = 0x00000002;
PrintWindow(hWnd, hDC, PW_RENDERFULLCONTENT);