PrintWindow send message WM_PAINT or WM_PRINT?
c++, gdi, winapi, windows
Solution
Simple answer: Yes, I reproduce the behavior you describe on both Windows 10 and Windows XP. When I call `PrintWindow`, the target window gets a `WM_PAINT` message, not a `WM_PRINT` message.
Not only can I reproduce it using breakpoints and trace output, but I can also confirm it by using the debugger to step through the implementation of `PrintWindow` (buried inside of the Windows operating system itself). Like virtually all User and GDI functions, it is a client-side stub that forwards to the server-side system function `NtUserPrintWindow`. From this point, execution follows through some more system functions and error checks, and ultimately loads the value 15 (which corresponds to the `WM_PAINT` message) into the `EDX` register, and then dispatches this message via an internal function called `DispatchClientMessage`.
This is essentially all that `PrintWindow` does—sends the specified window a `WM_PAINT` message, asking it to print into the specified device context. So yes, the MSDN documentation is making an erroneous claim. The implementation of `PrintWindow` does not send a `WM_PRINT` message.
Looking at the ReactOS source code (an open-source clone of the Windows operating system that aims to be binary API-compatible), you can see that it implements `PrintWindow` a bit differently, but still in a way that is morally equivalent. (Or, more precisely, it begins implementing `PrintWindow` in a way that is morally equivalent. Its implementation appears to be incomplete, and simply returns `FALSE`.) In its `NtUserPrintWindow` function, the parameters are verified, and then it calls down to an internal function, `IntPrintWindow`, which sets up the coordinates based on the specification of the `PW_CLIENTONLY` flag, and then—if it didn't return early—would force an update of the window and simply blit from the window's DC to the specified DC.
The Wine project (another open-source clone of the Windows APIs) does it differently. There, the `PrintWindow` function (implemented entirely user-side) simply sends the specified window a `WM_PRINT` message via `SendMessage`. This was implemented by Luke Benstead in December of 2009. My guess would be that Luke simply read the MSDN documentation and wrote code that followed its specification, rather than copying the actual behavior of Microsoft's OS.
Now, I had initially assumed that, rather than being completely wrong, MSDN was simply obsolete. The DWM, introduced with Windows Vista, prompted a number of changes in the way that various drawing APIs were implemented, and I assumed that the documentation for `PrintWindow` was still referring to how things worked in the legacy drawing model. (A consequence of documenting implementation details, rather than behavior.) In fact, though, testing on Windows XP disproved this assumption. XP behaves in exactly the same way as Windows 10, with `PrintWindow` sending a `WM_PAINT` message and never a `WM_PRINT` message. It is possible that the change was made at an even earlier time, and the MSDN documentation is even further out of date. For example, perhaps Windows 9x implemented `PrintWindow` in this way, but NT never did. I don't have access to such a system with a compiler at the moment, so I can't verify. If I remember, I'll update this answer later.
What's strange to me is that Raymond Chen described in passing the behavior of the `PrintWindow` function in a manner consistent with the MSDN documentation:
The `PrintWindow` function passes a custom device context as a parameter to the `WM_PRINT` message…
This was written some time around 2012, and he certainly has access to the Windows source code, so either I am missing something in my analysis, or Raymond also based his article on the official documentation instead of actually looking to see what the implementation does, since it doesn't really affect the main point of the article.
Speaking of which, the thing that I don't really understand about your question is why any of this matters. Sure, it's fun to study the way the OS actually works, but you shouldn't write code based on what you find when reverse-engineering. I can't imagine any reason why it would matter whether `PrintWindow` was implemented internally by sending a `WM_PAINT` message or a `WM_PRINT` message. In a sane version of either, the effect would be the same: you'd get the requested portion of the specified window drawn into the specified device context. Simple as that. In other words, App B neither needs to know nor care how `PrintWindow` is implemented.
A correctly-written App A (in other words, all Windows GUI applications) would have handlers for both the `WM_PAINT` and `WM_PRINTCLIENT` messages. `WM_PAINT` should be handled the obvious way, and `WM_PRINTCLIENT` should simply piggy-back off of this implementation—e.g.:
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(hWnd, &ps);
OnPaintContent(ps);
EndPaint(hWnd, &ps);
return 0;
}
case WM_PRINTCLIENT:
{
PAINTSTRUCT ps;
ps.hdc = reinterpret_cast<HDC>(wParam);
GetClientRect(hWnd, &ps.rcPaint);
OnPaintContent(ps);
return 0;
}
...
void PaintContent(const PAINTSTRUCT& ps)
{
// Paint the window's content here.
}
There is no reason for you to handle `WM_PRINT` at all, since that's handled by the default window procedure. Not only must this be so (logically), since the implementation of this message must handle painting the non-client area, which a window does not normally paint itself, but the MSDN documentation explicitly confirms under the "Remarks" section that `DefWindowProc` handles this message, sending the window the appropriate sub-messages, according to the specified flags, including `WM_ERASEBKGND` and `WM_PRINTCLIENT`.
Problem
According to msdn PrintWindow (retrieved date May 5th 2017) The application that owns the window referenced by hWnd processes the PrintWindow call and renders the image in the device context that is referenced by hdcBlt. The application receives a WM_PRINT message or, if the PW_PRINTCLIENT flag is specified, a WM_PRINTCLIENT message. For more information, see WM_PRINT and WM_PRINTCLIENT. MSDN never claim about the message WM_PAINT. But what I have tested prove the claim above about the WM_PRINT message wrong. App A: ``` LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_PAINT: DefWindowProc(hWnd, message, wParam, lParam); break; case WM_PRINT: OutputDebugStringA("WM_PRINT"); break; case WM_PRINTCLIENT: OutputDebugStringA("WM_PRINTCLIENT"); break; //other cases ... } return 0; } ``` App B (more details about App B) ``` HWND hwnd = FindWindow(NULL, lpString); //... //PrintWindow(hwnd, hdc, PW_CLIENTONLY); PrintWindow(hwnd, hdc, 0); ``` When I call the App B to capture the App A. According to msdn PrintWindow, case WM_PRINT should hit, but instead, case WM_PAINT is hit. According to this article If that's true then layered windows not implementing WM_PAINT can't be captured because UpdateWindow just sends WM_PAINT So at last, I just want to know if msdn is wrong or my code is wrong? PrintWindow send message WM_PAINT or WM_PRINT? If it does really send message WM_PRINT, how does message WM_PRINT works?