调用MoveWindow()并将bRepaint设置为TRUE

8 c winapi

以下内容摘自MoveWindow()文档的备注部分:

如果bRepaint参数为TRUE,则系统在移动窗口后立即将WM_PAINT消息发送到窗口过程(即,MoveWindow函数调用UpdateWindow函数).

所以我假设当我MoveWindow()使用bRepaintset 调用时TRUE,将立即调用窗口过程并传递WM_PAINT消息,但这是我的测试显示的内容:

  • MoveWindow()被调用时,窗口过程是直接调用,WM_ERASEBKGND消息传递给它,而不是 WM_PAINT消息.
  • 该区域仍然无效,因此当我返回到消息循环并且消息队列中没有消息时,将发送一条WM_PAINT消息.

我是否错误地解释了文档?

注意:我说的MoveWindow()是在父窗口对象上调用该方法.


编辑:

这是我的测试代码:

/* Left mouse click on the window to call MoveWindow() */

#include <Windows.h>

HWND hEdit;

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
    case WM_LBUTTONDOWN:
        MoveWindow(hWnd, 200, 200, 700, 700, TRUE);

        // Do not go back to message loop immediately
        Sleep(3000);
        break;
    case WM_ERASEBKGND:
        {
            SendMessage(hEdit, WM_CHAR, (WPARAM)'e', 0);
        }
        break;
    case WM_PAINT:
        {
            SendMessage(hEdit, WM_CHAR, (WPARAM)'p', 0);

            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);

            EndPaint(hWnd, &ps);
        }
        break;
    case WM_CLOSE:
        DestroyWindow(hWnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc;
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = 0;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "WinClass";
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    RegisterClassEx(&wc);

    HWND hWnd = CreateWindowEx(0, "WinClass", "", WS_OVERLAPPEDWINDOW, 261, 172, 594, 384, NULL, NULL, hInstance, NULL);
    hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL, 0, 0, 400, 21, hWnd, NULL, hInstance, NULL);

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    MSG msg;
    while(GetMessage(&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}
Run Code Online (Sandbox Code Playgroud)

Han*_*ant 6

我是否错误地解释了文档?

基本上,是的.您发现了关于winapi函数的MSDN文档的一些事实,这一点非常非常重要.它不是一本教程.它假定您对winapi如何工作有基本的了解,这是您从阅读Petzold的"Programming Windows"一书中获得的知识.

那本书可以教你Windows绘画周期总是包含WM_ERASEBKGND.因此,首先绘制背景,然后使用WM_PAINT在其上绘制任何内容.

在MSDN文档中跳过此类实现细节的几个原因.首先,它有很多,包括一切只是让你很难通过文章.接下来,实际为WM_ERASEBKGND编写消息处理程序是很常见的.您通常只是将其传递给DefWindowProc().使用您选择的WNDCLASSEX.hbrBackground,99%的时间足以完成工作.注意你的窗户是如何搞砸的,因为这是你没有做的事情.既然你写了一个消息处理程序,现在你的工作就是处理它.容易做,只需自己调用DefWindowProc().

最后,MSDN文档省略了细节,因为将它们固定下来使得很难改进Windows的工作方式.您可以从测试程序中看到另一个实现细节.通常,使用bPaint = TRUE调用MoveWindow根本不会绘制任何内容.首次单击后,通过使用标题栏拖动窗口来轻松查看窗口.注意如何再次单击使窗口跳回,但既没有WM_ERASEBKGND也没有WM_PAINT.

这是工作中的优化,使Windows更好地工作.并没有在MSDN文章中提到过.如果窗口没有移出屏幕并返回,并且窗口的大小没有改变,则可以采用快捷方式.它只是将视频帧缓冲区中的像素从旧位置复制到新位置.比让应用程序重新绘制所有内容更有效.如果您在启用Aero的情况下运行,那么它甚至会更加优化,它根本不需要复制像素.

最后但并非最不重要的是,虽然编写这样的代码来反向工程Windows是非常有教育意义和推荐的,但您不必这样做.使用Spy ++实用程序要容易得多.


cdo*_*nts 2

可能发生的情况是使用(将立即调用回调并等待其处理)MoveWindow发送,但通过(将消息放入队列中,因此将在调用时在睡眠后处理)。WM_ERASEBKGNDSendMessageWndProcWM_PAINTPostMessageDispatchMessage

我不知道这是否只是一个测试,或者您在使用MoveWindow它阻止消息队列后确实正在处理某些内容。如果是这样,那么您应该考虑将该工作移至另一个线程!

希望能帮助到你。