Windows消息循環(huán)
??1?#include2?#include3?#include?"resource.h" ??4? ??5?#define?MAX_LOADSTRING?100 ??6?TCHAR?szTitle[MAX_LOADSTRING]?=?_T("標(biāo)題欄");?????//?標(biāo)題欄文本 ??7?TCHAR?szWindowClass[MAX_LOADSTRING]?=?_T("MyClass");???//?主窗口類(lèi)名 ??8? ??9? ?10?ATOM?ToRegisterClass(HINSTANCE?hInstance,?int?nShowCmd);//注冊(cè)窗口類(lèi) ?11?HWND?ToCreateWindow(LPCTSTR?lpClassName,LPCTSTR?lpWindowName,DWORD?dwStyle,int?x,?int?y,?int?nWidth,int?nHeight,?HWND?hWndParent,HMENU?hMenu,HINSTANCE?hInstance,LPVOID?lpParam);//創(chuàng)建窗口 ?12?BOOL?ToShowWindow(HWND?hWnd,?int?nCmdShow);//顯示窗口 ?13?BOOL?ToUpdateWindow(HWND?hWnd);//更新窗口 ?14?WPARAM?ToRecycleMessage(MSG?msg);//消息循環(huán) ?15?LRESULT?CALLBACK?ToWndProc(HWND?hWnd,UINT?message,?WPARAM?wParam,?LPARAM?lParam);//窗口過(guò)程 ?16? ?17??//——————————————————————————進(jìn)入WinMain函數(shù)———————————————————————————— ?18?int?WINAPI?WinMain(?HINSTANCE?hInstance,?HINSTANCE?hPrevInstance,?LPSTR?lpCmdLine,?int?nShowCmd?) ?19?{ ?20??//————————————————————————————第一步:設(shè)計(jì)并注冊(cè)窗口類(lèi)———————————————————————————— ?21??ToRegisterClass(hInstance,?nShowCmd);//當(dāng)前實(shí)例句柄,窗口顯示方式 ?22? ?23??//————————————————————————————第二步:創(chuàng)建窗口———————————————————————————— ?24??HWND?hWnd?=?ToCreateWindow(szWindowClass,?szTitle,?WS_OVERLAPPEDWINDOW,?CW_USEDEFAULT,?0,?CW_USEDEFAULT,?0,?NULL,?NULL,?hInstance,?NULL); ?25?? ?26??//————————————————————————————第三步:顯示窗口———————————————————————————— ?27??ToShowWindow(hWnd,?nShowCmd); ?28? ?29??//————————————————————————————第四步:更新窗口———————————————————————————— ?30??ToUpdateWindow(hWnd); ?31? ?32??//————————————————————————————第五步:消息循環(huán)———————————————————————————— ?33??MSG?msg; ?34??return?ToRecycleMessage(&msg);//MSG結(jié)構(gòu)的wParam成員的值是傳遞給PostQuitMessage函數(shù)參數(shù),通常是0。 ?35?} ?36? ?37?ATOM?ToRegisterClass(HINSTANCE?hInstance,?int?nShowCmd) ?38?{ ?39??WNDCLASS?lpWndClass; ?40??lpWndClass.cbClsExtra?=?0;//窗口類(lèi)無(wú)擴(kuò)展 ?41??lpWndClass.cbWndExtra?=?0;//窗口實(shí)例無(wú)擴(kuò)展 ?42??lpWndClass.hbrBackground?=?(HBRUSH)GetStockObject(WHITE_BRUSH);//背景 ?43??lpWndClass.hCursor?=?LoadCursor(NULL,?IDC_ARROW);//鼠標(biāo) ?44??lpWndClass.hIcon?=?LoadIcon(hInstance,MAKEINTRESOURCE(IDB_PNG1));//圖標(biāo) ?45??lpWndClass.hInstance?=?hInstance; ?46??lpWndClass.lpfnWndProc?=?ToWndProc;//窗口函數(shù) ?47??lpWndClass.lpszClassName?=?szWindowClass;//窗口類(lèi)名 ?48??lpWndClass.lpszMenuName?=?NULL;//菜單名 ?49??lpWndClass.style?=?CS_HREDRAW?|?CS_VREDRAW;//風(fēng)格 ?50??return?RegisterClass(&lpWndClass); ?51?} ?52? ?53?HWND?ToCreateWindow(LPCTSTR?lpClassName,LPCTSTR?lpWindowName,DWORD?dwStyle,int?x,?int?y,?int?nWidth,int?nHeight,?HWND?hWndParent,HMENU?hMenu,HINSTANCE?hInstance,LPVOID?lpParam) ?54?{ ?55??return?CreateWindow(lpClassName,?lpWindowName,?dwStyle,?x,?y,?nWidth,?nHeight,?hWndParent,?hMenu,?hInstance,?lpParam); ?56?} ?57? ?58?BOOL?ToShowWindow(HWND?hWnd,?int?nCmdShow) ?59?{ ?60??return?ShowWindow(hWnd,?nCmdShow); ?61?} ?62? ?63?BOOL?ToUpdateWindow(HWND?hWnd) ?64?{ ?65??return?UpdateWindow(hWnd);//???調(diào)用UpdateWindow函數(shù)會(huì)通過(guò)發(fā)送給窗口消息處理函數(shù)WndProc一個(gè)WM_PAINT消息,通過(guò)這個(gè)消息完成重繪顯示區(qū)域的工作。 ?66?} ?67? ?68?WPARAM?ToRecycleMessage(MSG?*msg) ?69?{ ?70??int?nRet; ?71??while(nRet?=?GetMessage(msg,?NULL,?0,?0)?!=?0)//收到WM_QUIT消息則跳出消息循環(huán) ?72??{ ?73???if?(nRet?==?-1) ?74???{ ?75????return; ?76???} ?77???TranslateMessage(msg);//翻譯消息 ?78???DispatchMessage(msg);//分發(fā)消息 ?79??} ?80??return?msg->wParam; ?81?} ?82? ?83?//窗口過(guò)程函數(shù):處理窗口消息 ?84?LRESULT?CALLBACK?ToWndProc(HWND?hWnd,UINT?uMsg,?WPARAM?wParam,?LPARAM?lParam) ?85?{ ?86??DWORD?dwNum?=?0; ?87??wchar_t?*?pwSrc; ?88??RECT?rect; ?89??PAINTSTRUCT?ps;//創(chuàng)建繪制對(duì)象結(jié)構(gòu) ?90??HDC?hdc?=?NULL;//創(chuàng)建設(shè)備描述句柄對(duì)象 ?91??static?HWND?hwndButton[3]?=?{NULL,NULL,NULL}; ?92??switch(uMsg) ?93??{ ?94??case?WM_COMMAND://處理按鈕等發(fā)出的消息 ?95???break; ?96??case?WM_CHAR://處理鍵盤(pán)發(fā)出的消息 ?97???break; ?98??case?WM_CLOSE://關(guān)閉窗口消息 ?99???if?(IDYES?==?MessageBox(hWnd,?_T("結(jié)束?"),?_T("提示"),?MB_YESNO)) 100???{ 101????DestroyWindow(hWnd); 102???} 103???break; 104??case?WM_DESTROY://處理WM_DESTROY消息必須調(diào)用PostQuitMessage函數(shù),該函數(shù)向消息隊(duì)列中發(fā)送WM_QUIT消息,讓程序退出消息循環(huán)。 105???PostQuitMessage(0); 106???break; 107??default: 108???return?DefWindowProc(hWnd,?uMsg,?wParam,?lParam);//默認(rèn)的窗口處理函數(shù) 109???break; 110??} 111??return?0; 112?} 113? 114
?
?1?HWND?CreateWindow(?????? ?2? ?3?????LPCTSTR?lpClassName,//注冊(cè)的窗口類(lèi)型名稱。 ?4?????LPCTSTR?lpWindowName,//窗口名稱 ?5?????DWORD?dwStyle,//窗口類(lèi)型 ?6?????int?x,//窗口左上角位置 ?7?????int?y,//窗口左上角位置 ?8?????int?nWidth,//窗口的寬度 ?9?????int?nHeight,//窗口的高度 10?????HWND?hWndParent,//父窗口 11?????HMENU?hMenu,//窗口菜單 12?????HINSTANCE?hInstance,//應(yīng)用程序?qū)嵗浔?13?????LPVOID?lpParam//傳送給窗口的自定義參數(shù) 14?);
?
?1?BOOL?GetMessage(????????? ?2?????LPMSG?lpMsg,//從線程消息隊(duì)列里獲取到的消息指針 ?3?????HWND?hWnd,//想獲取那個(gè)窗口的消息,當(dāng)設(shè)置為NULL時(shí)是獲取所有窗口的消息。 ?4?????UINT?wMsgFilterMin,//獲取消息的ID編號(hào)最小值,如果小于這個(gè)值就不獲取回來(lái)。 ?5? ?6?????UINT?wMsgFilterMax//獲取消息的ID編號(hào)最大值,如果大于這個(gè)值就不獲取回來(lái)。 ?7?); ?8? ?9?//一般情況下最后兩個(gè)參數(shù)都設(shè)置為0,表示所有消息 10? 11??????函數(shù)返回值可能是0,大于0,或者等于-1。如果成功獲取一條非WM_QUIT消息時(shí),就返回大于0的值;如果獲取WM_QUIT消息時(shí),就返回值0值。如果出錯(cuò)就返回-1的值。
?
nCmd:窗口顯示方式,參數(shù)如下:
?1?SW_FORCEMINIMIZE 是強(qiáng)制窗口最小化,主要使用在非窗口主線程的其它線程來(lái)操作。 ?2?SW_HIDE 是顯示窗口為隱藏狀態(tài)。 ?3?SW_MAXIMIZE 是顯示窗口為最大化。 ?4?SW_MINIMIZE 是顯示窗口為最小化。 ?5?SW_RESTORE 是從任務(wù)里恢復(fù)窗口顯示。 ?6?SW_SHOW 是激活窗口為當(dāng)前窗口,并且顯示為當(dāng)前的大小和位置。 ?7?SW_SHOWDEFAULT 是創(chuàng)建進(jìn)程時(shí)顯示窗口的值。 ?8?SW_SHOWMAXIMIZED 是激活窗口為當(dāng)前窗口,并且顯示最大化。 ?9?SW_SHOWMINIMIZED 是激活窗口為當(dāng)前窗口,并且顯示最小化。 10?SW_SHOWMINNOACTIVE 是顯示窗口為最小化,但不激活它作為當(dāng)前窗口。 11?SW_SHOWNA 是顯示為當(dāng)前的大小和位置,但不激活它作為當(dāng)前窗口。 12?SW_SHOWNOACTIVATE 是顯示當(dāng)前窗口,但不激活它作為當(dāng)前窗口。 13?SW_SHOWNORMAL 是顯示當(dāng)前窗口,但窗口是最小化或最大化時(shí)會(huì)恢復(fù)窗口為原來(lái)的大小和位置。
?
?
TranslateMessage:
? 用來(lái)把虛擬鍵消息轉(zhuǎn)換為字符消息。由于Windows對(duì)所有鍵盤(pán)編碼都是采用虛擬鍵的定義,這樣當(dāng)按鍵按下時(shí),并不得字符消息,需要鍵盤(pán)映射轉(zhuǎn)換為字符的消息。
TranslateMessage函數(shù)用于將虛擬鍵消息轉(zhuǎn)換為字符消息。字符消息被投遞到調(diào)用線程的消息隊(duì)列中,當(dāng)下一次調(diào)用GetMessage函數(shù)時(shí)被取出。當(dāng)我們敲擊鍵盤(pán)上的某個(gè)字符鍵時(shí),系統(tǒng)將產(chǎn)生WM_KEYDOWN和WM_KEYUP消息。這兩個(gè)消息的附加參數(shù)(wParam和lParam)包含的是虛擬鍵代碼和掃描碼等信息,而我們?cè)诔绦蛑型枰玫侥硞€(gè)字符的ASCII碼,TranslateMessage這個(gè)函數(shù)就可以將WM_KEYDOWN和WM_ KEYUP消息的組合轉(zhuǎn)換為一條WM_CHAR消息(該消息的wParam附加參數(shù)包含了字符的ASCII碼),并將轉(zhuǎn)換后的新消息投遞到調(diào)用線程的消息隊(duì)列中。注意,TranslateMessage函數(shù)并不會(huì)修改原有的消息,它只是產(chǎn)生新的消息并投遞到消息隊(duì)列中。
也就是說(shuō)TranslateMessage會(huì)發(fā)現(xiàn)消息里是否有字符鍵的消息,如果有字符鍵的消息,就會(huì)產(chǎn)生WM_CHAR消息,如果沒(méi)有就會(huì)產(chǎn)生什么消息。
?
?
PostQuitMessage:
nExitCode是退出標(biāo)識(shí)碼,它被放到WM_QUIT消息的參數(shù)wParam里。
VOID PostQuitMessage(int nExitCode);
當(dāng)點(diǎn)擊窗口右上角的關(guān)閉時(shí),Windows就會(huì)把窗口從系統(tǒng)里刪除,這時(shí)就會(huì)發(fā)出消息WM_DESTROY給窗口消息處理函數(shù)WindowProc,WindowProc收到這條消息后,最需要做的一件事情就是調(diào)用PostQuitMessage發(fā)出退出消息,讓消息循環(huán)結(jié)束。