Windows是消息驱动的,理解消息机制及消息循环是特别重要。知道在什么情况下产生什么消息会让我们对程序有更好的控制。Windows给应用程序发消息,有些会加入应用程序的消息队列,也是就是队列消息。有些直接调用窗口消息处理程序,不会加入到消息队列,这部分为非队列消息。
下面分析一下一个应用程序从创建到结束产生的消息。
先给出测试用的程序,当然是一个非常经典的结构:
#include <windows.h> #include <tchar.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { MSG msg; TCHAR szClassName[] = _T("MainWClass"); WNDCLASSEX wndclass; wndclass.cbClsExtra = 0; wndclass.cbSize = sizeof(wndclass); wndclass.cbWndExtra = 0; wndclass.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH); wndclass.hCursor = ::LoadCursor(NULL, IDI_APPLICATION); wndclass.hIcon = ::LoadIcon(NULL, IDC_ARROW); wndclass.hIconSm = NULL; wndclass.hInstance = hInstance; wndclass.lpfnWndProc = WndProc; wndclass.lpszClassName = szClassName; wndclass.lpszMenuName = NULL; wndclass.style = CS_HREDRAW | CS_VREDRAW; if (::RegisterClassEx(&wndclass) == 0) { ::MessageBox(NULL, _T("RegisterClassEx Failed"), _T("Error"), MB_OK | MB_ICONHAND); return 0; } HWND hwnd = ::CreateWindow( szClassName, // lpClassName _T("My Window"), // lpWindowName WS_OVERLAPPEDWINDOW, // dwStyle CW_USEDEFAULT, // X CW_USEDEFAULT, // Y CW_USEDEFAULT, // nWidth CW_USEDEFAULT, // nHeight NULL, // hWndParent, NULL, // hMenu hInstance, // hInstance NULL // lpParam ); ::ShowWindow(hwnd, nShowCmd); ::UpdateWindow(hwnd); while (::GetMessage(&msg, NULL, 0, 0)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { TCHAR szText[] = _T("Simple Window!"); switch (message) { case WM_PAINT: { HDC hdc; PAINTSTRUCT ps; hdc = ::BeginPaint(hwnd, &ps); ::TextOut(hdc, 10, 10, szText, _tcslen(szText)); ::EndPaint(hwnd, &ps); } return 0; case WM_DESTROY: ::PostQuitMessage(0); return 0; } return ::DefWindowProc(hwnd, message, wParam, lParam); }
// 调用CreateWindow后产生第一条消息: CreateWindow() 0X0024 WM_GETMINMAXINFO "当窗口将要改变大小或位置时,由系统发送本消息给窗口,用户拖动一个可重置大小的窗口时便会发出本消息" 0X0081 WM_NCCREATE "当某窗口首次被创建时,本消息在WM_CREATE消息发送前发送" 0X0083 WM_NCCALCSIZE "当某窗口的客户区的大小和位置须被计算时发送本消息" 0X0001 WM_CREATE "新建一个窗口" CreateWindow() 返回 ShowWindow() 0X0018 WM_SHOWWINDOW "发送本消息给一个窗口,以便隐藏或显示该窗口" 0X0046 WM_WINDOWPOSCHANGING "本消息会发送给那些大小和位置(Z_Order)将被改变的窗口,以调用SetWindowPos函数或其它窗口管理函数" 0X001C WM_ACTIVATEAPP "窗口进程激活状态改动,正被激活的窗口属于不同的应用程序 " 0X0086 WM_NCACTIVATE "本消息发送给某窗口,在窗口的非客户区被激活时重绘窗口" 0X007F WM_GETICON "本消息发送给某个窗口,用于返回与某窗口有关联的大图标或小图标的句柄(一般收到多个,用于获取不同大小的图标)" 0X0006 WM_ACTIVATE "一个窗口被激活或失去激活状态" 0X0281 WM_IME_SETCONTEXT "应用程序的窗口激活时,系统将向应用程序发送WM_IME_SETCONTEXT消息,输入焦点转移到了某个窗口上,注:输入法相关" 0X0282 WM_IME_NOTIFY "可使用WM_IME_NOTIFY消息来通知关于IME窗口状态的常规改变,注:输入法相关,IME窗口发生了改变" 0X0007 WM_SETFOCUS "将焦点转向一个窗口" 0X0085 WM_NCPAINT "当窗口框架(非客户区)必须被被重绘时,应用程序发送本消息给该窗口" 0X0014 WM_ERASEBKGND "当一个窗口的背景必须被擦除时本消息会被触发(如:窗口大小改变时)" 0X0047 WM_WINDOWPOSCHANGED "本消息会发送给那些大小和位置(Z_Order)已被改变的窗口,以调用SetWindowPos函数或其它窗口管理函数" 0X0005 WM_SIZE "改变一个窗口的大小" 0X0003 WM_MOVE "移动一个窗口" ShowWindow() 返回 UpdateWindow() 0X000F WM_PAINT "窗口重绘" UpdateWindow() 返回 0X007F WM_GETICON "本消息发送给某个窗口,用于返回与某窗口有关联的大图标或小图标的句柄(一般收到多个,用于获取不同大小的图标)" // 进入消息循环 0X0113 WM_TIMER "发生了定时器事件" 0X0101 WM_KEYUP "当一个非系统按键被释放弹起时(<ALT>键没有被按下),会发送本消息给拥有键盘焦点的窗口" 0X0113 WM_TIMER "发生了定时器事件" 0X0104 WM_SYSKEYDOWN "当用户按住<ALT>键的同时又按下其它键时,发送本消息给拥有焦点的窗口", 0X0112 WM_SYSCOMMAND "当用户选择一条系统菜单命令、用户最大化或最小化或还原或关闭时,窗口会收到本消息" 0X0010 WM_CLOSE "用户关闭窗口时会发送本消息,紧接着会发送WM_DESTROY消息" 0X0046 WM_WINDOWPOSCHANGING "本消息会发送给那些大小和位置(Z_Order)将被改变的窗口,以调用SetWindowPos函数或其它窗口管理函数" 0X0047 WM_WINDOWPOSCHANGED "本消息会发送给那些大小和位置(Z_Order)已被改变的窗口,以调用SetWindowPos函数或其它窗口管理函数" 0X0086 WM_NCACTIVATE "本消息发送给某窗口,在窗口的非客户区被激活时重绘窗口" 0X0006 WM_ACTIVATE "一个窗口被激活或失去激活状态" 0X001C WM_ACTIVATEAPP "窗口进程激活状态改动,正被激活的窗口属于不同的应用程序 " 0X0008 WM_KILLFOCUS "使一个窗口失去焦点" 0X0281 WM_IME_SETCONTEXT "应用程序的窗口激活时,系统将向应用程序发送WM_IME_SETCONTEXT消息,输入焦点转移到了某个窗口上,注:输入法相关" 0X0282 WM_IME_NOTIFY "可使用WM_IME_NOTIFY消息来通知关于IME窗口状态的常规改变,注:输入法相关,IME窗口发生了改变" 0X0002 WM_DESTROY "销毁一个窗口" 0X0082 WM_NCDESTROY "本消息通知某窗口,非客户区正在销毁"
就是以上这些,可以看出上面的消息是使用系统快捷键来关闭的程序。