達(dá)內(nèi)VC++編程實(shí)例中的一部分源碼,涉及WIN32編程的C++例子源碼,其中之一的筆記節(jié)選:
一 Win32消息機(jī)制 1 消息機(jī)制 過(guò)程驅(qū)動(dòng):程序是按照我們預(yù)先定義好的順序 執(zhí)行,每執(zhí)行一步,下一步都已經(jīng)按照預(yù)定 的順序繼續(xù)執(zhí)行,直到程序結(jié)束。 事件驅(qū)動(dòng):程序的執(zhí)行順序是無(wú)序的。某個(gè)時(shí)間 點(diǎn)所執(zhí)行的代碼,是由外界通知。由于我們 無(wú)法決定用戶執(zhí)行順序,所以代碼的執(zhí)行也是 無(wú)序。 Win32的消息機(jī)制 - 事件驅(qū)動(dòng) 2 Win32消息程序 2.1 Win32窗口注冊(cè) 2.2 Win32窗口創(chuàng)建 2.3 WIn32消息循環(huán) 2.3.1 GetMessage BOOL GetMessage( LPMSG lpMsg,//存放獲取到的消息數(shù)據(jù) HWND hWnd,//獲取消息的窗口句柄 UINT wMsgFilterMin,//消息過(guò)濾的起始消息 UINT wMsgFilterMax //消息過(guò)濾的終止消息 ); 返回值BOOL:成功獲取消息,返回TRUE,但是 當(dāng)獲取到WM_QUIT消息時(shí),返回FALSE。 可以使用PostQuitMessage向窗口發(fā)送WM_QUIT消息 MSG - 由系統(tǒng)填寫關(guān)于消息的參數(shù) hWnd- GetMessage會(huì)根據(jù)hWnd值,接收由hWnd 指定的窗口的消息。 wMsgFilterMin,wMsgFilterMax - 消息過(guò)濾器, 要求GetMessage接收指定范圍的消息。 2.3.2 TranslateMessage 就是將鍵盤消息轉(zhuǎn)換成字符消息。 1 首先檢查是否是鍵盤按鍵消息 2 如果發(fā)現(xiàn)是按鍵消息,將根據(jù)按鍵,產(chǎn)生 一個(gè)字符消息,在下一個(gè)GetMessage執(zhí)行 時(shí),會(huì)收到這個(gè)消息。 3 如果未發(fā)現(xiàn)按鍵消息,不做任何處理。 2.3.3 DispatchMessage 根據(jù)消息數(shù)據(jù)內(nèi)窗口句柄,找到這個(gè)窗口 的窗口處理函數(shù), 調(diào)用處理函數(shù),進(jìn)行消息 處理。 如果MSG中,HWND窗口句柄為空, DispatchMessage不做任何處理。 2.4 Win32基本消息 2.4.1 WM_DESTROY 窗口銷毀時(shí)的消息,可以做退出或善后處理。 2.4.2 WM_CREATE 窗口創(chuàng)建消息,是在窗口創(chuàng)建后, 窗口處理函數(shù)收到第一條消息。 可以在這個(gè)消息內(nèi)做數(shù)據(jù)初始化/創(chuàng)建子窗口等。 WPARAM wParam - 不使用 LPARAM lParam - CREATESTRUCT指針 2.4.3 WM_SIZE 當(dāng)窗口大小發(fā)生變化時(shí),會(huì)收到這個(gè)消息。 可以在這個(gè)消息中調(diào)整窗口布局。 wParam - SIZE發(fā)生變化時(shí)的標(biāo)識(shí) LOWORD(lParam); - 客戶區(qū)的寬 HIWORD(lParam); - 客戶區(qū)的高 2.4.4 WM_SYSCOMMAND 系統(tǒng)命令消息,當(dāng)點(diǎn)擊系統(tǒng)菜單和按鈕時(shí), 會(huì)收到。 可以在這個(gè)消息中,提示用戶保存數(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定時(shí)器消息 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)生的時(shí)間 POINT pt; //消息產(chǎn)生時(shí),鼠標(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開(kāi)始,到0x7FFF,是用戶可以 定義使用的消息. 3.2.3 其他消息范圍 WM_APP(0x8000)-0xBFFF:應(yīng)用程序訪問(wèn)窗口 的消息ID 0xC000-0xFFFF: 應(yīng)用程序訪問(wèn)消息,使用 字符串注冊(cè)系統(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ì)列 - 用于存儲(chǔ)消息的內(nèi)存空間, 消息在隊(duì)列中是先入先出. 4.2 消息隊(duì)列的分類 4.2.1 系統(tǒng)消息隊(duì)列 - 由系統(tǒng)維護(hù)的消息 隊(duì)列. 4.2.2 應(yīng)用程序消息隊(duì)列(線程消息對(duì)列) - 屬于每個(gè)線程的各自擁有的消息隊(duì)列. 5 消息和消息隊(duì)列 5.1 根據(jù)消息和消息隊(duì)列關(guān)系,將消息分成兩種: 隊(duì)列消息 - 可以存放在消息隊(duì)列中的消息. 非隊(duì)列消息 - 發(fā)送時(shí)不進(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從對(duì)列中獲取消息, 判斷是否是WM_QUIT消息,如果發(fā)現(xiàn)是 WM_QUIT消息,消息循環(huán)結(jié)束,否則繼續(xù) 下一步. 6.1.2 TranslateMessage 翻譯按鍵消息, 如果發(fā)現(xiàn)有按鍵消息,產(chǎn)生字符消息放入 消息對(duì)列, 繼續(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ì)列.通過(guò)向系統(tǒng)消息隊(duì) 列查詢,如果找到消息,獲取消息并返回,進(jìn)行 消息處理.如果未找到消息,執(zhí)行6.2.3 6.2.3 檢查窗口需要重新繪制的范圍,如果 發(fā)現(xiàn)存在重新繪制的范圍,會(huì)產(chǎn)生WM_PAINT消息. 然后進(jìn)行消息處理, 如果未找,執(zhí)行6.2.4 6.2.4 檢查WM_TIMER定時(shí)器消息,如果發(fā)現(xiàn) 存在已經(jīng)到時(shí)的定時(shí)器,會(huì)產(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ū)域,那么會(huì)產(chǎn)生WM_PAINT消息. 一般情況下,不直接發(fā)送WM_PAINT消息,通過(guò)API 聲明需要繪制區(qū)域,來(lái)產(chǎn)生WM_PAINT消息. 例如,可以使用InvalidateRect聲明一個(gè)需要重新 繪制的區(qū)域. 2 WM_PAINT的注意點(diǎn) 2.1 如果一個(gè)消息隊(duì)列中,有多個(gè)WM_PAINT消息, 只有最后一個(gè)WM_PAINT消息會(huì)被處理. 2.2 WM_PAINT消息處理中,要清空需要被繪制的 區(qū)域. BeginPaint 3 WM_PAINT的使用 3.1 WM_PAINT開(kāi)始時(shí),必須調(diào)用BeginPaint 3.2 繪制圖形 3.3 WM_PAINT處理后,必須調(diào)用EndPaint 三 鍵盤消息 1 鍵盤消息 按鍵消息 WM_KEYDOWN 當(dāng)鍵被按下時(shí)產(chǎn)生 WM_KEYUP 當(dāng)鍵被釋放時(shí)產(chǎn)生 WM_SYSKEYDOWN 當(dāng)系統(tǒng)鍵被按下時(shí)產(chǎn)生 ALT/F10 WM_SYSKEYUP 當(dāng)系統(tǒng)鍵釋放時(shí)產(chǎn)生 字符消息 WM_CHAR 當(dāng)有字符鍵被按下時(shí)產(chǎn)生 TranslateMessage會(huì)將WM_KEYDOWN消息中, 可以顯示的按鍵,轉(zhuǎn)換成WM_CHAR的消息 2 消息參數(shù) WPARAM - 虛擬鍵碼 LPARAM - 相關(guān)的按鍵信息. 3 消息的使用 3.1 當(dāng)有按鍵消息時(shí),首先進(jìn)入系統(tǒng)消息隊(duì)列, 然后別程序的消息循環(huán)獲取. 3.2 消息的處理 4 鍵盤消息的順序 對(duì)于可顯示字符: …… |
|
來(lái)自: 看風(fēng)景D人 > 《win32編程》