从用户单击关闭按钮(标题栏最右边)或者用鼠标或鍵盘选择系统菜单的“关闭”选项,直到窗口消失,应用程序结束。这期间到底发生了什么呢?这曾经是我百思不得其解的问题,我想也会有很多人和我一样会碰到这个问题。所以我要把我的一些学习心得写出来,与大家共享:
1、首先会产生一个WM_SYSCOMMAND消息,如果程序员没有对此消息进行拦截,则由缺省的窗口函数DefWindowProc进行处理,如果表达式(LOWORD(wParam)&0xFFF0)==SC_CLOSE 成立,DefWindowProc发出一个WM_CLOSE消息。
2、同样,如果程序员没有对WM_CLOSE消息进行拦截,则还是由DefWindowProc进行处理,这次,她只简单的调用DestroyWindow函数,DestroyWindow先把窗口破坏掉,使用户看不到窗口。但是窗口破坏后,应用程序并没有结束,于是DestroyWindow再接再励,送出了一个WM_DESTROY消息。
3、这一次,WM_DESTROY被载获了,通常是会有这样的句子:
case WM_DESTROY:
PostQuitMessage(0);
...
这里PostQuitMessage函数很简单的发送一个WM_QUIT消息来响应WM_DESTROY
4、WM_QUIT消息非常特殊,她使GetMessage函数返回0,从而结束了消息循环,
应用程序从此结束。
下面我给出完整的证明程序,请大家一试:
- #include <Windows.h>
- #include <TCHAR.h>
- LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
- int WINAPI WinMain(HINSTANCE hInstance,
- HINSTANCE hPrevInst,
- LPSTR lpszCmdLine,
- int nCmdShow)
- {
- HWND hwnd;
- MSG Msg;
- WNDCLASS wndclass;
- char lpszClassName[]="窗口";
- char lpszTitle[]="窗口示例";
- wndclass.style=CS_HREDRAW | CS_VREDRAW;
- wndclass.lpfnWndProc =WndProc;
- wndclass.cbWndExtra=0;
- wndclass.cbClsExtra =0;
- wndclass.hInstance=hInstance;
- wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
- wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
- wndclass.hbrBackground = (HBRUSH)(GetStockObject(WHITE_BRUSH));
- wndclass.lpszMenuName=NULL;
- wndclass.lpszClassName=lpszClassName;
- if(!RegisterClass(&wndclass))
- {
- MessageBeep(0);
- return FALSE;
- }
- hwnd=CreateWindow(lpszClassName,
- lpszTitle,
- WS_OVERLAPPEDWINDOW,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- NULL,
- NULL,
- hInstance,
- NULL);
- ShowWindow(hwnd,nCmdShow);
- UpdateWindow(hwnd);
- while(1)
- {
- GetMessage(&Msg,NULL,0,0);
- if(Msg.message==WM_QUIT)
- {
- MessageBox(NULL,_T("收到WM_QUIT,即将跳出消息循环"),_T("注意了"),MB_OK);
- break;
- }
- TranslateMessage(&Msg);
- DispatchMessage(&Msg);
- }
- MessageBox(NULL,_T("已经跳出消息循环,应用程序即将结束!"),_T("注意了"),MB_OK);
- return Msg.wParam;
- }
- LRESULT CALLBACK WndProc(
- HWND hwnd,
- UINT message,
- WPARAM wParam,
- LPARAM lParam)
- {
- switch(message)
- {
- case WM_CLOSE:
- MessageBox(NULL,_T("收到WM_CLOSE消息,即将调用 DestroyWindow(hwnd);"),_T("注意了"),MB_OK);
- DestroyWindow(hwnd);
- break;
- case WM_DESTROY:
- MessageBox(NULL,_T("已调用过DestroyWindow(hwnd),看不到窗口了吧;"),_T("注意了"),MB_OK);
- MessageBox(NULL,_T("以下处理WM_DESTROY"),_T("注意了"),MB_OK);
- PostQuitMessage(0);
- break;
- case WM_SYSCOMMAND:
- if((LOWORD(wParam)&0xFFF0)==SC_CLOSE)
- {
- MessageBox(NULL,_T("你关闭了窗口,即将发送WM_CLOSE消息!"),_T("注意了"),MB_OK);
- SendMessage(hwnd,WM_CLOSE,0,0);
- }
- //不要添加 break,否则不能响应其它WM_SYSCOMMAND消息
- default:
- return DefWindowProc(hwnd,message,wParam,lParam);
- }
- return(0);
- }
- --------------------------------------------------------------------------------
- 窗口破坏过程与Windows消息循环的补充,增加了对WM_NCDESTROY的处理
- /**
- * File Name : MessageTest.cpp
- * Version : 1.1
- * Project Name : MessageTest
- * Project Type : Win32
- * Author : netcoder
- * Addition : 此版本增加了对WM_NCDESTROY的处理, 感谢 lily311 的补充
- */
- #include <windows.h>
- #include <tchar.h>
- LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
- int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInst,LPSTR lpszCmdLine,int nCmdShow)
- {
- HWND hwnd;
- MSG Msg;
- WNDCLASS wndclass;
- char lpszClassName[]="窗口";
- char lpszTitle[]="窗口示例";
- wndclass.style=CS_HREDRAW | CS_VREDRAW;
- wndclass.lpfnWndProc =WndProc;
- wndclass.cbWndExtra=0;
- wndclass.cbClsExtra =0;
- wndclass.hInstance=hInstance;
- wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
- wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
- wndclass.hbrBackground = (HBRUSH)(GetStockObject(WHITE_BRUSH));
- wndclass.lpszMenuName=NULL;
- wndclass.lpszClassName=lpszClassName;
- if(!RegisterClass(&wndclass))
- {
- MessageBeep(0);
- return FALSE;
- }
- hwnd=CreateWindow(lpszClassName,
- lpszTitle,
- WS_OVERLAPPEDWINDOW,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- NULL,
- NULL,
- hInstance,
- NULL);
- ShowWindow(hwnd,nCmdShow);
- UpdateWindow(hwnd);
- while(1)
- {
- GetMessage(&Msg,NULL,0,0);
- if(Msg.message==WM_QUIT)
- {
- MessageBox(NULL,_T("收到WM_QUIT,即将跳出消息循环"),_T("注意了"),MB_OK);
- break;
- }
- TranslateMessage(&Msg);
- DispatchMessage(&Msg);
- }
- MessageBox(NULL,_T("已经跳出消息循环,应用程序即将结束!"),_T("注意了"),MB_OK);
- return Msg.wParam;
- }
- LRESULT CALLBACK WndProc(
- HWND hwnd,
- UINT message,
- WPARAM wParam,
- LPARAM lParam)
- {
- switch(message)
- {
- case WM_CLOSE:
- MessageBox(NULL,_T("收到WM_CLOSE消息,即将调用 DestroyWindow(hwnd);"),_T("注意了"),MB_OK);
- DestroyWindow(hwnd);
- break;
- case WM_DESTROY:
- MessageBox(NULL,_T("已收到WM_DESTROY,看不到窗口了吧!"),_T("注意了"),MB_OK);
- break;
- case WM_NCDESTROY:
- MessageBox(NULL,_T("收到WM_NCDESTROY!"),_T("注意了"),MB_OK);
- PostQuitMessage(0);
- break;
- case WM_SYSCOMMAND:
- if((LOWORD(wParam)&0xFFF0)==SC_CLOSE)
- {
- MessageBox(NULL,_T("你关闭了窗口,即将发送WM_CLOSE消息!"),_T("注意了"),MB_OK);
- SendMessage(hwnd,WM_CLOSE,0,0);
- }
- //不要添加 break,否则不能响应其它WM_SYSCOMMAND消息
- default:
- return DefWindowProc(hwnd,message,wParam,lParam);
- }
- return(0);