C++ 打印窗口发送消息WM\U PAINT或WM\U PRINT?
根据msdn(检索日期2017年5月5日) 拥有hWnd引用的窗口的应用程序处理PrintWindow调用,并在hdcBlt引用的设备上下文中呈现图像。应用程序接收WM_PRINT消息,如果指定了PW_PRINTCLIENT标志,则接收WM_PRINTCLIENT消息。有关更多信息,请参阅WM_PRINT和WM_PRINTCLIENT MSDN从未声明WM_油漆的信息。 但我所做的测试证明了上述关于WM_打印消息的说法是错误的 应用程序A:C++ 打印窗口发送消息WM\U PAINT或WM\U PRINT?,c++,windows,winapi,gdi,C++,Windows,Winapi,Gdi,根据msdn(检索日期2017年5月5日) 拥有hWnd引用的窗口的应用程序处理PrintWindow调用,并在hdcBlt引用的设备上下文中呈现图像。应用程序接收WM_PRINT消息,如果指定了PW_PRINTCLIENT标志,则接收WM_PRINTCLIENT消息。有关更多信息,请参阅WM_PRINT和WM_PRINTCLIENT MSDN从未声明WM_油漆的信息。 但我所做的测试证明了上述关于WM_打印消息的说法是错误的 应用程序A: LRESULT CALLBACK WndProc(HW
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;
}
应用程序B(有关应用程序的更多详细信息)
当我调用应用程序B来捕获应用程序A时。根据msdn PrintWindow,case WM_PRINT应该命中,但是相反,case WM_PAINT命中
据
如果这是真的,那么无法捕获未实现WM_PAINT的分层窗口,因为UpdateWindow只发送WM_PAINT
最后,我只想知道msdn是错的还是我的代码错了?打印窗口发送消息WM\U PAINT或WM\U PRINT?如果它确实发送消息WM_PRINT,那么消息WM_PRINT是如何工作的 简单回答:是的,我重现了您在Windows 10和Windows XP上描述的行为。当我调用
PrintWindow
时,目标窗口会收到一条WM_-PAINT
消息,notaWM_-PRINT
消息
我不仅可以使用断点和跟踪输出复制它,还可以使用调试器逐步执行PrintWindow
(隐藏在Windows操作系统本身内部)的实现来确认它。与几乎所有用户和GDI函数一样,它是一个客户端存根,转发到服务器端系统函数NtUserPrintWindow
。从这一点开始,执行过程将完成更多的系统功能和错误检查,并最终将值15(对应于WM_PAINT
消息)加载到EDX
寄存器中,然后通过名为DispatchClientMessage
的内部函数发送该消息
这基本上就是PrintWindow
向指定窗口发送WM_PAINT
消息,要求它打印到指定的设备上下文中。因此,是的,MSDN文档提出了错误的主张。PrintWindow
的实现不会发送WM\u PRINT
消息
查看ReactOS源代码(Windows操作系统的开源克隆,旨在与二进制API兼容),您可以看到它实现的PrintWindow
略有不同,但在道德上仍然是等价的。(或者,更准确地说,它开始以道德上等价的方式实现PrintWindow
。它的实现似乎不完整,只返回FALSE
)在中,验证参数,然后调用内部函数,它根据PW_CLIENTONLY
标志的规范设置坐标,如果它没有提前返回,将强制更新窗口,并简单地从窗口的DC到指定的DC
Wine项目(Windows API的另一个开源克隆)的做法有所不同。在那里,(完全由用户端实现)只需通过SendMessage
发送指定的窗口aWM\u PRINT
消息。这是我的。我猜Luke只是简单地阅读MSDN文档并编写符合其规范的代码,而不是复制微软操作系统的实际行为
现在,我最初认为MSDN已经过时,而不是完全错误。随Windows Vista引入的DWM促使各种图形API的实现方式发生了许多变化,我认为PrintWindow
的文档仍然是指传统图形模型中的工作方式。(记录实现细节而不是行为的结果)但事实上,在Windows XP上的测试推翻了这一假设。XP的运行方式与Windows 10完全相同,PrintWindow
发送WM\u-PAINT
消息,而从不发送WM\u-PRINT
消息。有可能是在更早的时候进行了更改,MSDN文档甚至更为过时。例如,也许Windows9x以这种方式实现了PrintWindow
,但NT从未实现过。我目前没有使用编译器访问这样的系统,因此无法验证。如果我记得的话,我会在以后更新这个答案
我感到奇怪的是,PrintWindow
函数的行为与MSDN文档一致:
PrintWindow
函数将自定义设备上下文作为参数传递给WM_Print
消息
这是在2012年左右写的,他当然可以访问Windows源代码,所以要么我的分析中遗漏了一些东西,要么Raymond也根据官方文档撰写了他的文章,而不是实际查看实现的功能,因为它实际上并不影响文章的要点
说到这里,关于你的问题,我真的不明白的是为什么这些都很重要。当然,研究操作系统的实际工作方式很有趣,但你不应该根据逆向工程时发现的情况编写代码。我无法想象为什么PrintWindow
是通过发送WM\u-PAINT
消息还是WM\u-PRINT
消息在内部实现的。在这两种方法的健全版本中,效果都是一样的:将指定窗口的请求部分绘制到指定的设备上下文中。就这么简单。换句话说,应用程序B既不需要知道也不需要关心PrintWindow
是如何实现的
正确编写的应用程序A(在其他w中)
HWND hwnd = FindWindow(NULL, lpString);
//...
//PrintWindow(hwnd, hdc, PW_CLIENTONLY);
PrintWindow(hwnd, hdc, 0);
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.
}