123*_*ing 4 c++ windows winapi gdi
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;
}
Run Code Online (Sandbox Code Playgroud)
App B (more details about App B)
HWND hwnd = FindWindow(NULL, lpString);
//...
//PrintWindow(hwnd, hdc, PW_CLIENTONLY);
PrintWindow(hwnd, hdc, 0);
Run Code Online (Sandbox Code Playgroud)
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?
简单回答:是的,我在 Windows 10 和 Windows XP 上重现了您描述的行为。当我调用 时PrintWindow,目标窗口会收到一条WM_PAINT消息,而不是一条WM_PRINT消息。
我不仅可以使用断点和跟踪输出来重现它,而且我还可以通过使用调试器逐步完成PrintWindow(埋在 Windows 操作系统本身内部)的实现来确认它。像几乎所有的 User 和 GDI 函数一样,它是一个客户端存根,转发到服务器端系统函数NtUserPrintWindow。从这一点开始,执行会执行更多的系统函数和错误检查,最终将值 15(对应于WM_PAINT消息)加载到EDX寄存器中,然后通过名为 的内部函数调度此消息DispatchClientMessage。
这基本上就是PrintWindow所做的一切——向指定的窗口发送一条WM_PAINT消息,要求它打印到指定的设备上下文中。所以是的,MSDN 文档做出了错误的声明。的实施PrintWindow并没有发送WM_PRINT消息。
查看 ReactOS 源代码(Windows 操作系统的开源克隆,旨在与二进制 API 兼容),您可以看到它的实现方式PrintWindow略有不同,但在道德上仍然是等效的。(或者,更准确地说,它开始实施PrintWindow的方式,在道德上是等价的。它的实现似乎是不完整的,只是返回FALSE。)在它的NtUserPrintWindow功能,参数验证,然后调用到内部功能,IntPrintWindow,这根据PW_CLIENTONLY标志的规范设置坐标,然后——如果它没有提前返回——将强制更新窗口并简单地从窗口的 DC 到指定的 DC。
Wine 项目(Windows API 的另一个开源克隆)的做法有所不同。在那里,该PrintWindow函数(完全在用户端实现)只是WM_PRINT通过SendMessage. 这是由 Luke Benstead 在 2009 年 12 月实施的。我的猜测是 Luke 只是阅读 MSDN 文档并编写遵循其规范的代码,而不是复制 Microsoft 操作系统的实际行为。
现在,我最初认为 MSDN 已经过时了,而不是完全错误。Windows Vista 中引入的 DWM 促使各种绘图 API 的实现方式发生了许多变化,我认为 的文档PrintWindow仍然指的是旧绘图模型中的工作方式。(记录实现细节的结果,而不是行为。)但事实上,在 Windows XP 上的测试反驳了这个假设。XP 的行为方式与 Windows 10 完全相同,PrintWindow发送WM_PAINT消息而不是WM_PRINT消息。更改可能是在更早的时间进行的,而且 MSDN 文档甚至已经过时了。例如,也许 Windows 9x 实现了PrintWindow以这种方式,但NT从未这样做过。我目前无法使用编译器访问这样的系统,因此无法验证。如果我记得,我稍后会更新这个答案。
令我感到奇怪的是,Raymond ChenPrintWindow以与 MSDN 文档一致的方式在传递函数的行为时进行了描述:
该
PrintWindow函数将自定义设备上下文作为参数传递给WM_PRINT消息......
这是在 2012 年左右写的,他当然可以访问 Windows 源代码,所以要么我在分析中遗漏了一些东西,要么 Raymond的文章也基于官方文档,而不是实际查看实现的作用,因为它并没有真正影响文章的主要观点。
说到这里,我不太明白你的问题是为什么这些很重要。当然,研究操作系统的实际工作方式很有趣,但是您不应该根据逆向工程时发现的内容编写代码。我无法想象有任何理由为什么PrintWindow通过发送WM_PAINT消息或WM_PRINT消息在内部实现是否重要。在任何一个健全的版本中,效果都是相同的:您将获得指定窗口的请求部分绘制到指定的设备上下文中。就那么简单。换句话说,App B 既不需要知道也不关心PrintWindow是如何实现的。
正确编写的应用程序 A(换言之,所有 Windows GUI 应用程序)将具有WM_PAINT和WM_PRINTCLIENT消息的处理程序。WM_PAINT应该以明显的方式处理,并且WM_PRINTCLIENT应该简单地利用这个实现——例如:
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;
}
Run Code Online (Sandbox Code Playgroud)
...
void PaintContent(const PAINTSTRUCT& ps)
{
// Paint the window's content here.
}
Run Code Online (Sandbox Code Playgroud)
您根本没有理由进行处理WM_PRINT,因为这是由默认窗口过程处理的。不仅必须如此(逻辑上),因为此消息的实现必须处理非客户区的绘制,窗口通常不会自行绘制该区域,而且MSDN 文档在DefWindowProc处理此消息的“备注”部分下明确确认,根据指定的标志,包括WM_ERASEBKGND和,向窗口发送适当的子消息WM_PRINTCLIENT。
| 归档时间: |
|
| 查看次数: |
1941 次 |
| 最近记录: |