6

I am using Microsoft Visual Studio 2010 and Windows 7 Professional. This is my code to copy window image to clipboard:

void PrintWindowEx( HWND hWnd )
{
    HDC hDCMem = CreateCompatibleDC(NULL);
    RECT rect;

    GetWindowRect(hWnd, &rect);

    HBITMAP hBmp = NULL;

    HDC hDC = GetDC(hWnd);

    hBmp = CreateCompatibleBitmap(hDC, rect.right - rect.left, rect.bottom - rect.top);

    HGDIOBJ hOld = SelectObject(hDCMem, hBmp);
    PrintWindow(hWnd, hDCMem, 0);

    SelectObject(hDCMem, hOld);
    DeleteObject(hDCMem);

    OpenClipboard(hWnd);

    EmptyClipboard(); 
    SetClipboardData(CF_BITMAP, hBmp);
    CloseClipboard();

    ReleaseDC(hWnd, hDC);
}

It works fine with all windows except Google Chrome main window. I thought that it was because Chrome uses direct rendering, so I have disabled hardware acceleration in chrome://settings. Still does not work. Then I realized that working with messages can be limited due to restrictions in Chrome Sandbox, so I started Chrome with --no-sandbox command line option. Still does not work.

How can I get this to work? For Chrome and any other windows like Chrome. BitBlt() is not acceptable because window some parts of the window may be overlapped by another windows, window can be on other desktop, etc. Is there any working solution? Maybe with DLL loading to another process or something like that.

UPD: It does redraw after RedrawWindow(); so I can take screenshot (some parts - left part (width ~20px) and right part are not copied). So, does it support WM_PRINT or not? How can I take full screenshot of the window?

cls
  • 501
  • 1
  • 5
  • 18
  • 1
    It works sometimes. Sometimes it gives black rectangle; sometimes actual screenshot is copied. I added `--disable-gpu` to the command line, but it still works only sometimes. How can I deal with it? – cls Jul 14 '15 at 00:18

2 Answers2

31

I was stuck for ages on this, then found that I can pass a parameter of PW_RENDERFULLCONTENT as the last parameter to PrintWindow. Googling that shows it's new in Windows 8.1 so presumably doesn't work on 7. It may be worth trying it though, Winuser.h defines it as

#if(_WIN32_WINNT >= 0x0603)
#define PW_RENDERFULLCONTENT    0x00000002
#endif /* _WIN32_WINNT >= 0x0603 */
Geoff
  • 311
  • 3
  • 2
  • 1
    Thanks, this allows hardware acceleration and capture. – GeoffCoope Nov 15 '16 at 12:03
  • 3
    It took me 3h of coding several different approaches to find this answer. BitBlt() was returning a black image as well. Great job, dude. – karlphillip Jul 07 '17 at 22:25
  • 2
    You saved my day! Took nearly 2 hours searching, fixing. However, in MS API page https://learn.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-printwindow I can not find any info about this flag. – Lê Quang Duy Feb 13 '19 at 07:54
  • Old answer but I'd give you a raise. – Andrei Damian Jun 29 '19 at 23:23
  • Hi, @GeoffCoope ! Can you tell me, why I have a black spaces from top and left? Image misplaced :( Screenshot: https://www.dropbox.com/s/8ifwihax76bpqvn/black_spaces.jpg?dl=0 – РСИТ _ Nov 24 '19 at 09:10
  • @Geoff , can you see my previous comment and tell me, why I have this problem? – РСИТ _ Nov 24 '19 at 09:11
  • PrintWindow worked for me without this switch, either way, i'm trying to get PrintWindow to work with right-click menu / 3-dot menu at the top, and it doesn't show it, is it separated on another window ? – SomeNickName Jan 24 '23 at 23:38
4

PrintWindow works by sending a WM_PRINT or WM_PRINTCLIENT to the target window. While DefWindowProc handles WM_PRINT for standard window classes, custom window classes must handle WM_PRINT in order for PrintWindow to produce the desired result. If Chrome doesn't handle WM_PRINT or WM_PRINTCLIENT, there's nothing you can do.

When targeting Windows Vista and above you can use the DWM Thumbnail API to force a window to render its contents into a target window provided by the client.

IInspectable
  • 46,945
  • 8
  • 85
  • 181
  • OK, I will take a look at DWM Thumbnail API. But I have another question. If I can hook window messages in the code of DLL injected into chrome.exe, can I force custom window printing when I get this message? – cls Jun 21 '15 at 15:05
  • @deselect: If the target window doesn't handle `WM_PRINT`, then there's nothing you can do. How would you force a window to repaint itself, when it doesn't implement the functionality required to do so? Hooking doesn't buy you anything. – IInspectable Jun 21 '15 at 15:29
  • OK. As I understand DWM Thumbnail API, I can create relationship between windows with `DwmRegisterThumbnail` and display thumbnail on my window with `DwmUpdateThumbnailProperties`. If I set the destination rect in thumbnail properties to the size of the original window, can I get copy of original window "as is" in high quality? – cls Jun 21 '15 at 15:52
  • 2
    I can confirm Geoff's answer works for taking screenshots of Google Chrome. – karlphillip Jul 07 '17 at 22:27