達(dá)內(nèi)VC++編程實(shí)例中的一部分源碼,涉及WIN32編程的C++例子源碼,其中之一的筆記節(jié)選:
一 Win32消息機(jī)制 1 消息機(jī)制 過程驅(qū)動:程序是按照我們預(yù)先定義好的順序 執(zhí)行,每執(zhí)行一步,下一步都已經(jīng)按照預(yù)定 的順序繼續(xù)執(zhí)行,直到程序結(jié)束。 事件驅(qū)動:程序的執(zhí)行順序是無序的。某個時間 點(diǎn)所執(zhí)行的代碼,是由外界通知。由于我們 無法決定用戶執(zhí)行順序,所以代碼的執(zhí)行也是 無序。 Win32的消息機(jī)制 - 事件驅(qū)動 2 Win32消息程序 2.1 Win32窗口注冊 2.2 Win32窗口創(chuàng)建 2.3 WIn32消息循環(huán) 2.3.1 GetMessage BOOL GetMessage( LPMSG lpMsg,//存放獲取到的消息數(shù)據(jù) HWND hWnd,//獲取消息的窗口句柄 UINT wMsgFilterMin,//消息過濾的起始消息 UINT wMsgFilterMax //消息過濾的終止消息 ); 返回值BOOL:成功獲取消息,返回TRUE,但是 當(dāng)獲取到WM_QUIT消息時,返回FALSE。 可以使用PostQuitMessage向窗口發(fā)送WM_QUIT消息 MSG - 由系統(tǒng)填寫關(guān)于消息的參數(shù) hWnd- GetMessage會根據(jù)hWnd值,接收由hWnd 指定的窗口的消息。 wMsgFilterMin,wMsgFilterMax - 消息過濾器, 要求GetMessage接收指定范圍的消息。 2.3.2 TranslateMessage 就是將鍵盤消息轉(zhuǎn)換成字符消息。 1 首先檢查是否是鍵盤按鍵消息 2 如果發(fā)現(xiàn)是按鍵消息,將根據(jù)按鍵,產(chǎn)生 一個字符消息,在下一個GetMessage執(zhí)行 時,會收到這個消息。 3 如果未發(fā)現(xiàn)按鍵消息,不做任何處理。 2.3.3 DispatchMessage 根據(jù)消息數(shù)據(jù)內(nèi)窗口句柄,找到這個窗口 的窗口處理函數(shù), 調(diào)用處理函數(shù),進(jìn)行消息 處理。 如果MSG中,HWND窗口句柄為空, DispatchMessage不做任何處理。 2.4 Win32基本消息 2.4.1 WM_DESTROY 窗口銷毀時的消息,可以做退出或善后處理。 2.4.2 WM_CREATE 窗口創(chuàng)建消息,是在窗口創(chuàng)建后, 窗口處理函數(shù)收到第一條消息。 可以在這個消息內(nèi)做數(shù)據(jù)初始化/創(chuàng)建子窗口等。 WPARAM wParam - 不使用 LPARAM lParam - CREATESTRUCT指針 2.4.3 WM_SIZE 當(dāng)窗口大小發(fā)生變化時,會收到這個消息。 可以在這個消息中調(diào)整窗口布局。 wParam - SIZE發(fā)生變化時的標(biāo)識 LOWORD(lParam); - 客戶區(qū)的寬 HIWORD(lParam); - 客戶區(qū)的高 2.4.4 WM_SYSCOMMAND 系統(tǒng)命令消息,當(dāng)點(diǎn)擊系統(tǒng)菜單和按鈕時, 會收到。 可以在這個消息中,提示用戶保存數(shù)據(jù)等。 wParam - 系統(tǒng)命令類型 LOWORD(lParam) - 屏幕X坐標(biāo) HIWORD(lParam) - 屏幕Y坐標(biāo) 2.4.5 WM_PAINT 繪圖消息 2.4.6 鍵盤消息 2.4.7 鼠標(biāo)消息 2.4.8 WM_TIMER定時器消息 2.5 消息結(jié)構(gòu) MSG - 消息結(jié)構(gòu) typedef struct tagMSG { // msg HWND hwnd; //消息的窗口句柄 UINT message;//消息標(biāo)示 WPARAM wParam; //消息的參數(shù),32位 LPARAM lParam; //消息的參數(shù),32位 DWORD time;//消息產(chǎn)生的時間 POINT pt; //消息產(chǎn)生時,鼠標(biāo)的位置 } MSG; 2.6 消息的獲取和發(fā)送 2.6.1 獲取GetMessage/PeekMessage GetMessage 獲取消息,阻塞函數(shù) PeekMessage 獲取消息,非阻塞函數(shù) 2.6.2 發(fā)送SendMessage/PostMessage SendMessage 發(fā)送消息并等候消息 處理結(jié)束才返回。 PostMessage 發(fā)送消息后立即返回, 不關(guān)心消息處理的結(jié)果。 LRESULT SendMessage/PostMessage( HWND hWnd, //處理消息窗口 UINT Msg, //消息的ID WPARAM wParam, //消息的參數(shù) LPARAM lParam );//消息的參數(shù) 3 消息組成和分類 3.1 消息組成 窗口句柄/消息ID/消息參數(shù)(WPARAM.LPARAM) 3.2 消息分類 3.2.1 系統(tǒng)消息 - 由系統(tǒng)定義和使用的消息 例如:WM_CREATE/WM_SIZE 消息ID范圍為: 0 - 0x03FF(WM_USER-1) 3.2.2 用戶定義消息 - 應(yīng)用程序可以自己定義 和使用的消息, WM_USER(0x0400) 從WM_USER的ID開始,到0x7FFF,是用戶可以 定義使用的消息. 3.2.3 其他消息范圍 WM_APP(0x8000)-0xBFFF:應(yīng)用程序訪問窗口 的消息ID 0xC000-0xFFFF: 應(yīng)用程序訪問消息,使用 字符串注冊系統(tǒng)產(chǎn)生相應(yīng)消息ID 3.2.4 用戶定義消息的使用 1)定義自定義消息ID: #define WM_FIRSTMSG (WM_USER+1) 2)在窗口處理函數(shù)中,響應(yīng)消息 switch( nMsg ) { case WM_FIRSTMSG: //處理函數(shù) break; } 3)SendMessage/PostMessage發(fā)送消息 SendMessage( hWnd, WM_FIRSTMSG, 0, 0 ); 4 消息隊(duì)列 4.1 消息隊(duì)列 - 用于存儲消息的內(nèi)存空間, 消息在隊(duì)列中是先入先出. 4.2 消息隊(duì)列的分類 4.2.1 系統(tǒng)消息隊(duì)列 - 由系統(tǒng)維護(hù)的消息 隊(duì)列. 4.2.2 應(yīng)用程序消息隊(duì)列(線程消息對列) - 屬于每個線程的各自擁有的消息隊(duì)列. 5 消息和消息隊(duì)列 5.1 根據(jù)消息和消息隊(duì)列關(guān)系,將消息分成兩種: 隊(duì)列消息 - 可以存放在消息隊(duì)列中的消息. 非隊(duì)列消息 - 發(fā)送時不進(jìn)入消息隊(duì)列. 5.2 隊(duì)列消息 首先存放到消息隊(duì)列當(dāng)中,然后由GetMessage /PeekMessage取出,然后進(jìn)行處理. 例如: 鼠標(biāo)消息/鍵盤消息/WM_PAINT/WM_QUIT WM_TIMER消息 5.3 非隊(duì)列消息 消息發(fā)送直接發(fā)送給指定的窗口,查找窗口的 處理函數(shù),返回處理結(jié)果. 6 消息的獲取 6.1 消息循環(huán) 6.1.1 GetMesssage從對列中獲取消息, 判斷是否是WM_QUIT消息,如果發(fā)現(xiàn)是 WM_QUIT消息,消息循環(huán)結(jié)束,否則繼續(xù) 下一步. 6.1.2 TranslateMessage 翻譯按鍵消息, 如果發(fā)現(xiàn)有按鍵消息,產(chǎn)生字符消息放入 消息對列, 繼續(xù)下一步 6.1.3 DispatchMessage 找到消息所發(fā)窗口 的處理函數(shù),處理消息.處理完成后, 返回6.1.1. 6.2 GetMesssage和PeekMessage 6.2.1 從線程消息隊(duì)列中獲取消息,如果找到 消息,就返回消息,進(jìn)行消息處理. 如果未 找到消息,執(zhí)行6.2.2 6.2.2 查找系統(tǒng)消息隊(duì)列.通過向系統(tǒng)消息隊(duì) 列查詢,如果找到消息,獲取消息并返回,進(jìn)行 消息處理.如果未找到消息,執(zhí)行6.2.3 6.2.3 檢查窗口需要重新繪制的范圍,如果 發(fā)現(xiàn)存在重新繪制的范圍,會產(chǎn)生WM_PAINT消息. 然后進(jìn)行消息處理, 如果未找,執(zhí)行6.2.4 6.2.4 檢查WM_TIMER定時器消息,如果發(fā)現(xiàn) 存在已經(jīng)到時的定時器,會產(chǎn)生WM_TIMER消息. 進(jìn)行消息處理. 如果未找,執(zhí)行6.2.5 6.2.5 執(zhí)行內(nèi)存管理工作. 6.2.6 根據(jù)函數(shù)不同,處理結(jié)果不同: GetMesssage - 阻塞,等候下一條消息 PeekMessage - 讓出控制權(quán),交給后面的代碼執(zhí)行. 7 消息發(fā)送 7.1 消息發(fā)送分兩種 發(fā)送(Send)消息 - 直接發(fā)送給指定的窗口,并 等候結(jié)果. 投遞(Post)消息 - 發(fā)送到消息隊(duì)列當(dāng)中,立刻 返回,由消息循環(huán)處理. 7.2 PostMessage和SendMessage PostMessage產(chǎn)生隊(duì)列消息,由于發(fā)送后不等候 消息處理結(jié)果,所以不能確定消息是否被處理 成功. SendMessage產(chǎn)生非隊(duì)列消息,可以確定消息是否 成功. 二 WM_PAINT消息 1 WM_PAINT的產(chǎn)生 由于窗口的互相覆蓋等,產(chǎn)生需要繪制 的區(qū)域,那么會產(chǎn)生WM_PAINT消息. 一般情況下,不直接發(fā)送WM_PAINT消息,通過API 聲明需要繪制區(qū)域,來產(chǎn)生WM_PAINT消息. 例如,可以使用InvalidateRect聲明一個需要重新 繪制的區(qū)域. 2 WM_PAINT的注意點(diǎn) 2.1 如果一個消息隊(duì)列中,有多個WM_PAINT消息, 只有最后一個WM_PAINT消息會被處理. 2.2 WM_PAINT消息處理中,要清空需要被繪制的 區(qū)域. BeginPaint 3 WM_PAINT的使用 3.1 WM_PAINT開始時,必須調(diào)用BeginPaint 3.2 繪制圖形 3.3 WM_PAINT處理后,必須調(diào)用EndPaint 三 鍵盤消息 1 鍵盤消息 按鍵消息 WM_KEYDOWN 當(dāng)鍵被按下時產(chǎn)生 WM_KEYUP 當(dāng)鍵被釋放時產(chǎn)生 WM_SYSKEYDOWN 當(dāng)系統(tǒng)鍵被按下時產(chǎn)生 ALT/F10 WM_SYSKEYUP 當(dāng)系統(tǒng)鍵釋放時產(chǎn)生 字符消息 WM_CHAR 當(dāng)有字符鍵被按下時產(chǎn)生 TranslateMessage會將WM_KEYDOWN消息中, 可以顯示的按鍵,轉(zhuǎn)換成WM_CHAR的消息 2 消息參數(shù) WPARAM - 虛擬鍵碼 LPARAM - 相關(guān)的按鍵信息. 3 消息的使用 3.1 當(dāng)有按鍵消息時,首先進(jìn)入系統(tǒng)消息隊(duì)列, 然后別程序的消息循環(huán)獲取. 3.2 消息的處理 4 鍵盤消息的順序 對于可顯示字符: …… |
|