Wn32编程中,在响应WM_PAINT消息时,很容易造成处理器使用率过高。造成处理器负载过高的原因是窗口时刻都在检查自己的Update Region,如果有则发出WM_PAINT,直到调用BeginPaint和EndPaint后才会将Update Region置空。如果在消息相应函数中没有加入BeginPaint,EndPaint 则 WM_PAINT 就会不断被发送,造成死循环。
如果不主动响应WM_PAINT,则该消息会进入DefWindowProc,它会调用那两个函数。
在MFC中也一样,一般在OnPaint中会出现CPaintDC dc(this) 该类的构造函数会调用BeginPaint,析构函数会调用EndPaint。也可能出现父类的OnPaint,如果把这些注释掉,运行后cpu占用率依旧会很高。
例如下面的一个Win32的例子,如果我们把WM_PAINT处理部分打开,就会造成负载过高。如果注释掉该代码,就没有问题。但是如果在里面添加BeginPaint以及EndPaint,那么就不会造成CPU负载过高这种问题。
#include <windows.h>
#include <aygshell.h>
#pragma comment(lib, "aygshell.lib")
#define IDC_MY_STATIC 100
#define IDC_MY_BUTTON 101
#define IDC_MY_EDIT 102
LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int _tWinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPTSTR lpszCmdLine, int nShowCmd)
{
WNDCLASS wc = {0};
HWND hWnd = NULL;
MSG msg = {0};
DEBUGMSG(TRUE, (TEXT("hInstance=%p, lpszCmdLine=%s, nShowCmd=%d\n"), hInstance, lpszCmdLine, nShowCmd));
// 1. 注册窗口类(指定一个函数指针)
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = TEXT("GWND");
if (0 == RegisterClass(&wc))
{
return -1;
}
// 2. 创建窗口
hWnd = CreateWindow(TEXT("GWND"), TEXT("掌中"), WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
if (!IsWindow(hWnd))
{
return -1;
}
// 3. 显示窗口
ShowWindow(hWnd, nShowCmd);
UpdateWindow(hWnd);
// 4. 消息循环
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HINSTANCE hTemp = NULL;
SHINITDLGINFO shidi = {0};
WORD wID = 0;
WORD wEvent = 0;
DEBUGMSG(TRUE, (TEXT("hWnd=%p, uMsg=%04X, wParam=%p, lParam=%p\n"), hWnd, uMsg, wParam, lParam));
switch (uMsg)
{
case WM_CREATE:
{
hTemp = GetModuleHandle(NULL);
DEBUGMSG(TRUE, (TEXT("hTemp=%p\n"), hTemp));
CreateWindow(TEXT("BUTTON"), TEXT("OPEN"), WS_CHILD | WS_VISIBLE, 10, 100, 30, 20, hWnd, (HMENU)IDC_MY_BUTTON, hTemp, NULL);
DEBUGMSG(TRUE, (TEXT("WM_CREATE\n")));
shidi.dwMask = SHIDIM_FLAGS;
shidi.hDlg = hWnd;
shidi.dwFlags = SHIDIF_CANCELBUTTON | SHIDIF_SIZEDLGFULLSCREEN;
SHInitDialog(&shidi);
}
break;
//case WM_PAINT:
// {
// DEBUGMSG(TRUE, (TEXT("WM_PAINT\n")));
// }
// break;
case WM_COMMAND:
{
DEBUGMSG(TRUE, (TEXT("WM_COMMAND\n")));
wID = LOWORD(wParam);
wEvent = HIWORD(wParam);
switch (wID)
{
case IDCANCEL:
{
DestroyWindow(hWnd);
}
break;
case IDC_MY_BUTTON:
{
MessageBox(hWnd, TEXT("HI"), TEXT("Tip"), MB_OK);
}
break;
}
}
break;
case WM_DESTROY:
{
DEBUGMSG(TRUE, (TEXT("WM_DESTROY\n")));
PostQuitMessage(0);
}
break;
case WM_KEYDOWN:
{
DEBUGMSG(TRUE, (TEXT("WM_KEYDOWN\n")));
}
break;
case WM_KEYUP:
{
DEBUGMSG(TRUE, (TEXT("WM_KEYUP\n")));
}
break;
case WM_CHAR:
{
DEBUGMSG(TRUE, (TEXT("WM_CHAR\n")));
}
break;
case WM_LBUTTONDOWN:
{
DEBUGMSG(TRUE, (TEXT("WM_LBUTTONDOWN\n")));
}
break;
case WM_LBUTTONUP:
{
DEBUGMSG(TRUE, (TEXT("WM_LBUTTONUP\n")));
}
break;
case WM_INITDIALOG:
{
DEBUGMSG(TRUE, (TEXT("WM_INITDIALOG\n")));
}
break;
case WM_SYSKEYDOWN:
{
DEBUGMSG(TRUE, (TEXT("WM_SYSKEYDOWN\n")));
}
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}