以下内容摘自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)
我是否错误地解释了文档?
基本上,是的.您发现了关于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 ++实用程序要容易得多.
可能发生的情况是使用(将立即调用回调并等待其处理)MoveWindow发送,但通过(将消息放入队列中,因此将在调用时在睡眠后处理)。WM_ERASEBKGNDSendMessageWndProcWM_PAINTPostMessageDispatchMessage
我不知道这是否只是一个测试,或者您在使用MoveWindow它阻止消息队列后确实正在处理某些内容。如果是这样,那么您应该考虑将该工作移至另一个线程!
希望能帮助到你。