C++ 打印窗口发送消息WM\U PAINT或WM\U PRINT?

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

根据msdn(检索日期2017年5月5日)

拥有hWnd引用的窗口的应用程序处理PrintWindow调用,并在hdcBlt引用的设备上下文中呈现图像。应用程序接收WM_PRINT消息,如果指定了PW_PRINTCLIENT标志,则接收WM_PRINTCLIENT消息。有关更多信息,请参阅WM_PRINT和WM_PRINTCLIENT

MSDN从未声明WM_油漆的信息。 但我所做的测试证明了上述关于WM_打印消息的说法是错误的

应用程序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;
}
应用程序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
消息,nota
WM_-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
发送指定的窗口a
WM\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文档一致:

Print­Window
函数将自定义设备上下文作为参数传递给
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.
}