一 引言
? ? ? ? 本文主要介紹幾種windows常見的消息的處理,在《Win32 SDK基礎(chǔ)(8)—— Windows消息機制》中,我們介紹了WM_CREATE消息的處理,在窗口創(chuàng)建之前,我們利用消息處理函數(shù)彈出了一個MessageBox,本文在此基礎(chǔ)之上,介紹WM_DESTROY、WM_SYSCOMMAND、WM_QUIT、WM_SIZE等函數(shù)常見的Windows消息。首先,我們引入在《Win32 SDK基礎(chǔ)(8)—— Windows消息機制》文中的代碼,后續(xù)的實驗都在此代碼的基礎(chǔ)之上。
#include?"stdafx.h" #include?"MessageTs.h" HINSTANCE?g_hInstance?=?0;?? //窗口處理函數(shù)?? LRESULT?CALLBACK?WndProc(HWND?hWnd,?UINT?uMsg,?WPARAM?wParam,?LPARAM?lParam)?? {?? switch?(uMsg)?? {?? case?WM_DESTROY:?? PostQuitMessage(0);//可以使GetMessage返回0?? break;? case??WM_CREATE: MessageBox(NULL,"WM_CREATE消息被處理了","消息處理",MB_OK); default:?? break;?? }?? return?DefWindowProc(hWnd,?uMsg,?wParam,?lParam);?? }?? //注冊窗口類?? BOOL?Register(LPSTR?lpClassName,?WNDPROC?wndProc)?? {?? WNDCLASSEX?wce?=?{?0?};?? wce.cbSize?=?sizeof(wce);?? wce.cbClsExtra?=?0;?? wce.cbWndExtra?=?0;?? wce.hbrBackground?=?(HBRUSH)(COLOR_WINDOW?+?1);?? wce.hCursor?=?NULL;?? wce.hIcon?=?NULL;?? wce.hIconSm?=?NULL;?? wce.hInstance?=?g_hInstance;?? wce.lpfnWndProc?=?wndProc;?? wce.lpszClassName?=?lpClassName;?? wce.lpszMenuName?=?NULL;?? wce.style?=?CS_HREDRAW?|?CS_VREDRAW;?? ATOM?nAtom?=?RegisterClassEx(&wce);?? if?(nAtom?==?0)?? return?FALSE;?? return?true;?? }?? //創(chuàng)建主窗口?? HWND?CreateMain(LPSTR?lpClassName,?LPSTR?lpWndName)?? {?? HWND?hWnd?=?CreateWindowEx(0,?lpClassName,?lpWndName,?? WS_OVERLAPPEDWINDOW,?CW_USEDEFAULT,?CW_USEDEFAULT,?CW_USEDEFAULT,?CW_USEDEFAULT,?NULL,?NULL,?g_hInstance,?NULL);?? return?hWnd;?? }?? //顯示窗口?? void?Display(HWND?hWnd)?? {?? ShowWindow(hWnd,?SW_SHOW);?? UpdateWindow(hWnd);?? }?? //消息循環(huán)?? void?Message()?? {?? MSG?nMsg?=?{?0?};?? while?(GetMessage(&nMsg,?NULL,?0,?0))?? {?? TranslateMessage(&nMsg);?? DispatchMessage(&nMsg);?? }?? }?? int?APIENTRY?wWinMain(_In_?HINSTANCE?hInstance,?? _In_opt_?HINSTANCE?hPrevInstance,?? _In_?LPWSTR????lpCmdLine,?? _In_?int???????nCmdShow)?? {?? //?TODO:?Place?code?here.?? g_hInstance?=?hInstance;?? BOOL?nRet?=?Register("Main",?WndProc);?? if?(!nRet)?? {?? MessageBox(NULL,?"注冊失敗",?"Infor",?MB_OK);?? return?0;?? }?? HWND?hWnd?=?CreateMain("Main",?"window");?? Display(hWnd);?? Message();?? return?0;?? }
?二、WM_CREATE消息
? ? ? ? 我們還是要再介紹下wm_create消息。因為在上一文中我們只通過彈出messagebox驗證了wm_create消息的產(chǎn)生時機,卻沒有介紹它另外一個很重要的構(gòu)成——wparam和lparam參數(shù)。我們在函數(shù)時,往往可以通過這兩個參數(shù)攜帶一些信息。wm_create消息是我們在創(chuàng)建窗口時由系統(tǒng)自動發(fā)送的消息,同樣也會利用這兩個參數(shù)攜帶信息。lparam攜帶了我們創(chuàng)建窗口的createwindowex的12個參數(shù)信息,wparam沒有被使用,下面我們在處理wm_create消息時,在彈出的對話框上顯示窗口類和窗口名稱。
//窗口處理函數(shù)?? LRESULT?CALLBACK?WndProc(HWND?hWnd,?UINT?uMsg,?WPARAM?wParam,?LPARAM?lParam)?? {?? switch?(uMsg)?? {?? case?WM_DESTROY:?? PostQuitMessage(0);//可以使GetMessage返回0?? break;? case??WM_CREATE: { CREATESTRUCT?crt?=?*((CREATESTRUCT*)lParam); char?buf[256]?=?{0}; sprintf(buf,"創(chuàng)建的窗口類名稱是%s,窗口名稱是%s",crt.lpszClass,crt.lpszName); MessageBox(NULL,?buf,?"消息處理",?MB_OK); } default:?? break;?? }?? return?DefWindowProc(hWnd,?uMsg,?wParam,?lParam);?? }
? ? ? ? 運行程序,我們發(fā)現(xiàn)在窗口創(chuàng)建之前我們成功捕獲了窗口的注冊窗口類名稱和窗口名稱,并在對話框上顯示出來:
三、WM_DESTROY消息
? ? ? ? 這個消息在之前的文章中我們其實早已經(jīng)解除過。他是Windows窗口關(guān)閉時發(fā)送的一個消息,簡單點說就是,當你點擊Windows窗口的關(guān)閉函數(shù)時,會發(fā)出這個消息。我們在之前的代碼中,處理這個消息的操作是PostQuitMessage(0),這其實是我們發(fā)送了一個接下來要介紹的WM_QUIT消息用來結(jié)束程序的進程。WM_DESTORY消息的LPARAM和WPARAM都沒被使用,它一般被用來做一些窗口關(guān)閉前資源的回收和內(nèi)存的釋放工作等等,我們調(diào)用的PostQuitMessage(0)就是一個很常見的用法。
四、WM_QUIT消息
? ? ? ? 前面我們已經(jīng)介紹過,這是我們使用PostQuitMessage(0)發(fā)送的一個消息,用來結(jié)束程序進程,它的WMPARAM是PostQuitMessage中傳遞的參數(shù),LPARAM參數(shù)未被使用。通常情況下我們發(fā)送了WM_QUIT后,會引起消息循環(huán)中的GetMessage函數(shù)返回,從而使得進程函數(shù)。WM_QUIT消息是無法傳遞到我們自己的窗口處理函數(shù)中的。但是我們可以從側(cè)面驗證有這么一個消息:我們先在代碼中增加對WM_QUIT消息的處理。
LRESULT?CALLBACK?WndProc(HWND?hWnd,?UINT?uMsg,?WPARAM?wParam,?LPARAM?lParam)?? {?? switch?(uMsg)?? {?? case?WM_DESTROY:?? PostQuitMessage(0);//可以使GetMessage返回0?? break;? case??WM_CREATE: { CREATESTRUCT?crt?=?*((CREATESTRUCT*)lParam); char?buf[256]?=?{0}; sprintf(buf,"創(chuàng)建的窗口類名稱是%s,窗口名稱是%s",crt.lpszClass,crt.lpszName); MessageBox(NULL,?buf,?"消息處理",?MB_OK); } case?WM_QUIT: { int?param?=?(int)wParam; char?buf[256]; sprintf(buf,?"進程退出,退出碼:%d",?param); MessageBox(NULL,?buf,?"消息處理",?MB_OK); } default:?? break;?? }?? return?DefWindowProc(hWnd,?uMsg,?wParam,?lParam);?? }
? ? ? ? 運行程序,在關(guān)閉處理WM_CREATE消息的對話框后,發(fā)現(xiàn)彈出了我們驗證WM_QUIT消息的對話框。
? ? ? ?
? ? ? ? ?這是因為,彈出的處理WM_CREATE消息MessageBox也是一個窗口,但它屬于我們的進程。每個窗口都有一個消息循環(huán),但是消息函數(shù)一個進程卻只有一個,當MessageBox的窗口關(guān)閉時,它的窗口處理函數(shù)也調(diào)用PostQuitMessage(0)發(fā)送了一個WM_QUIT消息。它的消息循環(huán)中GetMessage接收到WM_QUIT消息后返回并退出。而這個消息又會被我們的消息循環(huán)捕獲到,但是由于它不是我們的窗口發(fā)出的消息,所以不會導(dǎo)致我們的GetMessage返回結(jié)束循環(huán),反而被傳給我們的窗口處理函數(shù)匯總進行處理,所以出現(xiàn)了上面截圖顯示的對話框。
五、WM_SYSCOMMAND消息
? ? ? ? 系統(tǒng)命令消息,當我們點擊最大化、最小化和關(guān)閉命令時會觸發(fā)這個消息(這么說來點擊關(guān)閉按鈕時會同時觸發(fā)WM_DESTROY和WM_SYSCOMMAND兩個消息哦)。它的wParam參數(shù)攜帶了具體的窗口操作:
關(guān)閉:SC_CLOSE
最大化:SC_MAXIMIZE
最小化:SC_MINIMIZE
? ? ? ? 這里只列舉了三種常見的WM_SYSCOMMAND攜帶的參數(shù)宏,其它的可以參照MSDN。WM_SYSCOMMAND的lParam攜帶的是產(chǎn)生該消息的鼠標的位置,位置的X和Y坐標分別被存放在lParam的低位和高位字中,我們用下面的代碼來驗證在窗口最大化時,我們鼠標的位置:
case?WM_SYSCOMMAND: { if?(wParam?==?SC_MAXIMIZE) { short?x?=?LOWORD(lParam); short?y?=?HIWORD(lParam); char?buf[256]; sprintf(buf,?"窗口最大化,x坐標:%d,y坐標:%d",?x,y); MessageBox(NULL,?buf,?"消息處理",?MB_OK); } }
? ? ?
? ? ? ? 當我們點擊窗口的最大化按鈕時,出現(xiàn)下面的提示:
六 WM_SIZE消息
? ? ? ? 每當我們調(diào)整窗口的大小時,都會觸發(fā)WM_SIZE消息。它的wParam參數(shù)攜帶的是該消息產(chǎn)生的原因:
? ? ? ??SIZE_RESTORED —— 重新調(diào)整窗口大小
? ? ? ??SIZE_MAXIMIZED —— 最大化顯示
? ? ? ? SIZE_ MINIMIZED —— 最小化顯示
? ? ? ? 其他參數(shù)宏詳見MSDN
? ? ? ? 它的lParam參數(shù)攜帶的是重新調(diào)整大小后的窗口的高和寬,其中低字節(jié)代表寬,高字節(jié)代表高,這里我們通過代碼驗證,當窗口最大化后窗口的高和寬:
case?WM_SIZE: { if?(wParam?==?SIZE_MAXIMIZED) { short?width?=?LOWORD(lParam); short?hight?=?HIWORD(lParam); char?buf[256]; sprintf(buf,?"窗口最大化,高度:%d,寬度:%d",?hight,?width); MessageBox(NULL,?buf,?"消息處理",?MB_OK); } }
? ? ? ? 運行程序,最大化時可以顯示最大化后的窗口高度和寬度: