




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、windows 消息隊(duì)列一節(jié)詳細(xì)描述消息和消息隊(duì)列以及如何在你程序中使用他們。關(guān)于消息和消息隊(duì)列與傳統(tǒng)的應(yīng)用程序不同,Microsoft Windows 應(yīng)用程序并不顯式地用一個(gè)函數(shù)的調(diào)用(如c運(yùn)行庫)來獲取輸入,而是,等待windows系統(tǒng)把輸入傳給它們。windows系統(tǒng)把應(yīng)用程序的所有輸入傳給應(yīng)用程序的窗口,每個(gè)窗口都有一個(gè)稱之為窗口過程的函數(shù).當(dāng)窗口有輸入時(shí) windows系統(tǒng)要調(diào)用它,窗口過程處理輸入并把控制返回windows系統(tǒng)。有關(guān)窗口過程,參見 窗口過程這一章講述消息及消息隊(duì)列,并說明在應(yīng)用程序中如何使用它們。消息windows系統(tǒng)以消息的形式把輸入傳給窗口過程,消息是由win
2、dows系統(tǒng)或應(yīng)用程序產(chǎn)生的. windows系統(tǒng)對(duì)每一個(gè)輸入事件都要產(chǎn)生消息,例如,用戶按鍵盤、移動(dòng)鼠標(biāo)或單擊一個(gè)滾動(dòng)條控制框。windows系統(tǒng)為了響應(yīng)應(yīng)用程序給系統(tǒng)帶來的變化也會(huì)產(chǎn)生消息,比如應(yīng)用程序改變了系統(tǒng)字體資源池或是改變了一個(gè)窗門的大小。應(yīng)用程序可通過產(chǎn)生消息指導(dǎo)它自己的 窗口來完成某個(gè)任務(wù),或是與其它應(yīng)用程序的窗口進(jìn)行通信。windows系統(tǒng)把消息發(fā)送給窗口過程.窗口過程有四個(gè)參數(shù):窗口句柄、消息標(biāo)識(shí)以及兩個(gè)叫做消息參數(shù)的32位值。窗口句柄決定消息將發(fā)送到哪 一個(gè)窗口,windows系統(tǒng)則用它來確定向哪一個(gè)窗口過程發(fā)送消息。消息標(biāo)識(shí)是一個(gè)命名的常量,由它來標(biāo)明消息的目的。如果窗
3、口過程接收到一條消息,它就通過消息標(biāo)識(shí)來決定如何處理這 條消息。例如,消息標(biāo)識(shí) WM_PAINT通知窗口過程,窗口的客戶區(qū)被改變了,需要重畫。消息參數(shù)指定窗口過程在處理消息時(shí)所用的數(shù)據(jù)或數(shù)據(jù)的位置,消息的意圖及數(shù)值取決了消息本身。消息參數(shù)可以是一個(gè)整 數(shù)、緊縮的位標(biāo)志、一個(gè)含有附加數(shù)據(jù)結(jié)構(gòu)的指針等等。如果消息不使用消息參數(shù),一般就都設(shè)置成NULL、窗口過程必須檢查消息標(biāo)識(shí)以確定如何解釋消息參數(shù)。消息路由windows系統(tǒng)用兩種方式向窗口過程發(fā)送消息:把消息投遞到一個(gè)先進(jìn)先出的消息隊(duì)列中,它是一個(gè)系統(tǒng)定義的內(nèi)存塊用于 臨時(shí)存儲(chǔ)消息;或是把消息直接發(fā)給窗口過程。投遞到消息隊(duì)列中的消息叫排隊(duì)消息,它
4、們主要是用戶通過鼠標(biāo)或鍵盤的輸入結(jié)果.如WM_MOUSEMOVE,WM_LBUTTONDOWN, WM_KEYDOWN, and WM_CHAR 消息。其它的排隊(duì)消息包括定時(shí)器、繪制和退出消息: WM_TIMER, WM_PAINT, and WM_QUIT 。所有直接發(fā)送到窗口過程的其它消息稱之為非隊(duì)列消息。排隊(duì)消息windows系統(tǒng)在同一時(shí)間可顯示多個(gè)窗口,要發(fā)送鼠標(biāo)和鍵盤輸入到相應(yīng)的窗口,windows系統(tǒng)要用到消息隊(duì)列,它要管理一個(gè)系統(tǒng)消息隊(duì)列和任意數(shù)目線程消息隊(duì)列,每一個(gè)隊(duì)列對(duì)應(yīng)于一個(gè)線程。不管什么時(shí)候,只要用戶移動(dòng)鼠標(biāo)或是敲鍵盤.鼠標(biāo)或鍵盤的設(shè)備驅(qū)動(dòng)器都要把輸入轉(zhuǎn)換成消息,并把它們
5、放到系統(tǒng)消息隊(duì) 列中去。windows從系統(tǒng)隊(duì)列中每次移走一條消息,確定目的窗口,再把它們投遞到創(chuàng)建目的窗口的線程的消息隊(duì)列中,線 程消息隊(duì)列接收所有由該線程創(chuàng)建的窗口的鼠標(biāo)和鍵盤消息。線程從它的隊(duì)列中移走消息并指導(dǎo)windows系統(tǒng)將它們發(fā)送到相應(yīng)的窗口過程進(jìn)行處理。有關(guān)線程,參見進(jìn)程和線程WM_PAINT消息有點(diǎn)特別,windows系統(tǒng)總是把這條消息放在消息隊(duì)列的最后,這樣可保證窗口按先進(jìn)先出次序接收它的 輸入消息,WM_PAINT消息被保持在隊(duì)列中,只有在隊(duì)列中沒有其它消息時(shí)才發(fā)送到窗口過程。同一個(gè)窗口的多個(gè) WM_PAINT消息被合并成一個(gè) WM_PAINT消息,把客戶區(qū)所有無效部分合
6、并成一個(gè)區(qū)域.合并 WM_PAINT消息節(jié)約了窗 口必須重畫客戶區(qū)內(nèi)容的時(shí)間。系統(tǒng)向線程消息隊(duì)列投遞消息是通過填充一個(gè)MSG結(jié)構(gòu),再把它復(fù)制到消息隊(duì)列中,MSG結(jié)構(gòu)中的信息包括接收消息的窗口句柄、消息標(biāo)識(shí)、兩個(gè)消息參數(shù)、消息時(shí)間以及鼠標(biāo)的位置,線程可把消息投遞到它自己的消息隊(duì)列中或是通過函數(shù) PostMessage 和PostThreadMessage把消息投遞到其它線程的隊(duì)列中去。應(yīng)用程序可通過函數(shù) GetMessage從它的隊(duì)列中移走一條消息,應(yīng)用程序還可用函數(shù) PeekMessage 來檢查隊(duì)列中的某個(gè)消 息但并不移走它,這個(gè)函數(shù)用有關(guān)這條消息的信息填充MSG結(jié)構(gòu)。把一條消息從它的隊(duì)列中
7、移走后.應(yīng)用程序可用函數(shù) DispatchMessage 指導(dǎo)windows系統(tǒng)把這條消息發(fā)送到窗口過程進(jìn)行處理。DispatchMessage利用前面調(diào)用函數(shù) GetMessage 或PeekMessage 時(shí)填充的 MSG結(jié)構(gòu)的指針,把窗口句柄、消息標(biāo)識(shí)及兩個(gè)消息參數(shù)傳給窗口過程,但它并不傳送時(shí)間或鼠標(biāo)光標(biāo)的位置.應(yīng)用程序可以在處理一條消息時(shí),通過調(diào)用函 數(shù) GetMessageTime 和 GetMessagePos 來獲取這些信息。一個(gè)線程可以用函數(shù) WaitMessage當(dāng)他沒有其他消息在其隊(duì)列里時(shí),產(chǎn)生對(duì)其他線程的控制。此函數(shù)將終止線程,直到一 個(gè)新消息被放入該線程的消息隊(duì)列里,然
8、后返回。你可以調(diào)用函數(shù) SetMessageExtraInfo 來設(shè)置當(dāng)前線程消息隊(duì)列的附加信息。是和當(dāng)前線程的消息隊(duì)列聯(lián)系的32位值。用戶可以用函數(shù)GetMessageExtraInfo 來獲得附加信息,該信息將會(huì)保留到下次調(diào)用函數(shù)GetMessage 或PeekMessage 之前。非隊(duì)列消息非隊(duì)列消息是直接發(fā)送到目標(biāo)窗口過程的,而不通過系統(tǒng)消息隊(duì)列和線程消息隊(duì)列。windows系統(tǒng)一般通過發(fā)送非隊(duì)列消息把影響某窗口的事件通知窗口。例如,如果用戶激活一個(gè)新的應(yīng)用程序窗口.windows系統(tǒng)就會(huì)向該窗口發(fā)送一系列的消息,包括:WM_ACTIVATE , WM_SETFOCUS 和 WM_SE
9、TCURSOR ,這些消息分別通知窗口:它被激活了;將通過這個(gè)窗 口進(jìn)行鍵盤輸入;鼠標(biāo)已移到這個(gè)窗口邊框的里面了。非隊(duì)列消息也有可能發(fā)生在應(yīng)用程序調(diào)用一個(gè)windows系統(tǒng)函數(shù)時(shí),例如,在應(yīng)用程序用函數(shù) SetWindowPos 來移動(dòng)一個(gè)窗口之后,windows系統(tǒng)發(fā)送一條WM_WINDOWPOSCHANGED 消 息。應(yīng)用程序是調(diào)用函數(shù) SendMessage、SendNotifyMessage 或 SendDlgItemMessage 發(fā)送消息的。消息處理應(yīng)用程序必須刪除和處理投遞到它的線程消息隊(duì)列中的消息,單一線程的應(yīng)用程序一般是在它的WinMain函數(shù)中使用一個(gè)消息循環(huán)來刪除消息,并
10、把消息發(fā)送到相應(yīng)的窗口過程進(jìn)行處理。具有多重線程的應(yīng)用程序在創(chuàng)建窗口的每一個(gè)線程中使用一 個(gè)消息循環(huán),下一節(jié)將講述消息循環(huán)是如何工作的,另外還解釋了窗口過程的一般規(guī)則。消息循環(huán)一個(gè)簡單的消息循環(huán)含有一個(gè)對(duì)下列函數(shù)的調(diào)用:GetMessage, TranslateMessage 和DispatchMessage。函數(shù)GetMessage從隊(duì)列中檢取一條消息并把它復(fù)制到一個(gè)MSG結(jié)構(gòu)中.GetMessage應(yīng)返回TRUE,但如果它得到的是 WM_QUIT消息,它就返回FALSE并結(jié)束循環(huán)。在單一線程的應(yīng)用程序中,結(jié)束消息循環(huán)通常是關(guān)閉應(yīng)用程序的第一步。一般在應(yīng)用程序主 窗口的窗口過程中響應(yīng) WM_
11、DESTROY 消息時(shí),應(yīng)用程序通過函數(shù) PostQuitMessage 關(guān)閉它自己的消息循環(huán)。如果在GetMessage中指定窗口句柄,那么從隊(duì)列中檢取的只是指定窗口的消息。GetMessage 也能過濾隊(duì)列中的消息,這種情況下檢取的只是指定范圍內(nèi)的消息。有關(guān)過濾消息,參見 消息過濾”。如果某個(gè)線程想接收鍵盤的字符輸入,那么線程消息循環(huán)中必須含有TranslateMessage 。 Windows系統(tǒng)在用戶每按一次鍵時(shí)會(huì)產(chǎn)生一個(gè)虛鍵消息(WM_KEYDOWN 和WM_KEYUP),虛鍵消息含有一個(gè)標(biāo)識(shí)哪一個(gè)鍵被按過的虛鍵碼,但不是它的字 符值,要得到這個(gè)值,消息循環(huán)中必須含有Translat
12、eMessage ,由它來把虛鍵消息翻譯成字符消息(WM_CHAR),再把它放回到應(yīng)用程序的消息隊(duì)列中去.這樣字符消息才能在消息循環(huán)的下一輪循環(huán)中被發(fā)送到窗口過程。函數(shù)DispatchMessage 把消息發(fā)送到與 MSG結(jié)構(gòu)中指定的窗口句柄相應(yīng)的窗口過程,如果窗口句柄是HWND_TOPMOST ,DispatchMessage就把消息發(fā)送到系統(tǒng)中所有頂層窗口的窗口過程。如果窗口句柄是 NULL ,對(duì)于這條消息DispatchMessage 則什么也不做。應(yīng)用程序的主線程在初始化應(yīng)用程序并且至少創(chuàng)建了一個(gè)窗口之后就開始了消息循環(huán),一旦開始,消息循環(huán)就連續(xù)不斷地從 線程的消息隊(duì)列中校取消息并把它
13、們分發(fā)到相應(yīng)的窗口,函數(shù) GetMessage從消息隊(duì)列中檢取到 WM_QUIT消息時(shí),消息循 環(huán)就結(jié)束了。一個(gè)消息隊(duì)列只需要有一個(gè)消息循環(huán),而不管應(yīng)用程序有多少個(gè)窗口,因?yàn)殛?duì)列中的每一條消息是一個(gè)MSG結(jié)構(gòu),其中含有接收消息的窗口句柄,DispatchMessage總能把消息發(fā)送到相應(yīng)的窗口。應(yīng)用程序可以有多種方法修改它的消息循環(huán),例如,它可以從隊(duì)列中檢取消息但并不發(fā)送到任何窗口,這對(duì)那些投遞不指定窗口的消息的應(yīng)用程序是很有用的,(這些消息是提供給應(yīng)用程序的,而不是某個(gè)窗口,因?yàn)樗鼈兒?NULL窗口句柄)。應(yīng)用程序也能指導(dǎo) GetMessage來搜索隊(duì)列中一個(gè)特定的消息,而不管其它消息,這
14、對(duì)那些有時(shí)不按消息隊(duì)列先進(jìn)先出次序檢 取消息的應(yīng)用程序來說是很有用的。使用鍵盤加速鍵的應(yīng)用程序必須能夠把鍵盤消息轉(zhuǎn)換成命令消息,要這樣做,應(yīng)用程序的消息循環(huán)必須調(diào)用函數(shù)TranslateAccelerator 有關(guān)加速鍵,參見鍵盤加速鍵”。窗口過程窗口過程是一個(gè)函數(shù),用來接收和處理所有發(fā)送到該窗口的消息,每個(gè)窗口類都有一個(gè)窗口過程,同一窗口類所創(chuàng)建的窗口 共用同一個(gè)窗口過程來響應(yīng)消息。系統(tǒng)通過把消息數(shù)據(jù)作為過程的參數(shù)來向窗口過程發(fā)送消息,再由窗口過程完成與消息相應(yīng)的活動(dòng)。它需要檢查消息的標(biāo)識(shí),在處理消息時(shí)要使用由消息參數(shù)指定的這個(gè)信息。窗口過程一般不會(huì)忽略 一條消息,如果它不處理某條消息,它就
15、必須把這條消息傳回系統(tǒng)進(jìn)行默認(rèn)處理,窗口過程是調(diào)用函 數(shù)DefWindowProc 來完成的,由它完成一個(gè)默認(rèn)的操作并返回消息結(jié)果。絕大多數(shù)窗口過程只處理幾種類型的消息,其它 的則通過調(diào)用DefWindowProc 傳給了系統(tǒng)。因?yàn)榇翱谶^程是由所有屬于同類窗口共享的,所以它能處理幾個(gè)不同窗口的消息,要識(shí)別受消息影響的某個(gè)窗口,窗口過程 可以檢查消息所帶的窗口句柄。有關(guān)窗口過程,參見 窗口過程傳遞和發(fā)送消息任何應(yīng)用程序都能投遞和發(fā)送消息,就跟系統(tǒng)一樣,應(yīng)用程序投遞一條消息是通過把它復(fù)制到消息隊(duì)列,發(fā)送消息則是通過 把消息數(shù)據(jù)作為窗門過程的參數(shù)。要投遞消息,應(yīng)用程序需要用到函數(shù)PostMessag
16、e ,要發(fā)送消息,程序使用函數(shù)SendMessage, BroadcastSystemMessage, SendMessageCallback, SendMessageTimeout, SendNotifyMessage或SendDlgltemMessage 。應(yīng)用程序通常投遞一條消息來通知某個(gè)窗口去完成一個(gè)任務(wù)。PostMessage 為消息創(chuàng)建一個(gè)MSG結(jié)構(gòu)并把消息拷到消息隊(duì)列中,最后由應(yīng)用程序的消息循環(huán)檢取這條消息再把它發(fā)送到相應(yīng)的窗口過程。應(yīng)用程序一般是通過發(fā)送一條消息通知窗口過程立即完成某項(xiàng)任務(wù),函數(shù)SendMessage 把消息發(fā)送到與給定窗口相應(yīng)的窗口過程,這個(gè)函數(shù)要等待窗口過程
17、完成處理井返回消息的結(jié)果。父窗口與子窗口之間也是通過發(fā)送消息來進(jìn)行相互間的通信,例如,某個(gè)父窗口有一個(gè)編輯控制框作為它的子窗口,就可通過向它發(fā)送消息設(shè)置控制框的正文,這個(gè)控制框則通過向父窗 口發(fā)送消息來把用戶對(duì)正文的改變通知其父窗口。函數(shù)SendMessageCallback也能發(fā)送消息到指定窗口的窗口過程里,但是,這函數(shù)是立即返回,當(dāng)窗口過程函數(shù)處理完消息后,系統(tǒng)調(diào)用指定的回調(diào)函數(shù),有關(guān)更多回調(diào)函數(shù)信息,參考函數(shù)SendAsyncProc 。有時(shí),應(yīng)用程序也有可能要求向系統(tǒng)中的所有頂層窗口發(fā)送或投遞一條消息,例如,如果應(yīng)用程序改變了系統(tǒng)的時(shí)間,它必 須通過發(fā)送WM_TIMECHANGE 消息
18、來通知所有頂層窗口,應(yīng)用程序向所有頂層窗口發(fā)送或投遞一條消息是調(diào)用函數(shù) SendMessage 或 PostMessage ,并在 hwnd 參數(shù)中指定 HWND_TOPMOST 。你同樣通過函數(shù) BroadcastSystemMessage 指定參數(shù)lpdwRecipients 的值為BSM_APPLICATIONS來廣播消息給所有程序應(yīng)用程序能夠投遞一條消息而不指定窗口,在調(diào)用 PostMessage 時(shí)應(yīng)用程序提供NULL窗口句柄,這條消息就被投遞到與 當(dāng)前線程相應(yīng)的隊(duì)列中。因?yàn)闆]有指定窗口句柄,應(yīng)用程序就必須在處理消息循環(huán)中的這條消息,這也是一種創(chuàng)建消息的方 法.此類消息適用于整個(gè)應(yīng)用
19、程序,而不只是指某個(gè)窗口。使用函數(shù)InSendMessage 窗口過程能夠確定它所處理的消息是從另一個(gè)線程發(fā)來的,這種能力在需要根據(jù)消息源進(jìn)行消息 處理時(shí)是很有用的。經(jīng)常出現(xiàn)的一個(gè)編程錯(cuò)誤是假設(shè)函數(shù)PostMessage 總能成功地投遞一條消息,這在消息隊(duì)列是滿的時(shí)候是不對(duì)的,應(yīng)用程序應(yīng)該檢查函數(shù)PostMessage 的返回值以確認(rèn)消息是否已經(jīng)被投遞,否則要重新投遞這條消息。消息種類這部分將兩種類型 windows消息;系統(tǒng)定義的消息,程序定義的消息系統(tǒng)消息系統(tǒng)使用系統(tǒng)定義的消息來控制應(yīng)用程序的操作,并給應(yīng)用程序提供輸入或其他信息進(jìn)行處理。系統(tǒng)在與應(yīng)用程序進(jìn)行通信 是時(shí)是發(fā)送系統(tǒng)消息的。應(yīng)用
20、程序也能發(fā)送或投遞系統(tǒng)消息,應(yīng)用程序通常用這些消息來控制預(yù)注冊(cè)類創(chuàng)建的控制窗口的操 作。每條系統(tǒng)消息都有一個(gè)唯一的消息標(biāo)識(shí),對(duì)應(yīng)于一個(gè)符號(hào)常量(在Windows系統(tǒng)頭文件中定義),它表明了消息的目的,例如,常量 WM_PAINT 要求窗口繪制它的內(nèi)容。符號(hào)常量指定了系統(tǒng)消息所屬的類別,常量的前綴標(biāo)識(shí)能夠解釋和處理消息的畝口的類型。下表列出了前綴及相應(yīng)的消息類 別:前綴消息類ABM Application desktop toolbarBM Button controlCB Combo box controlCDM Common dialog boxDBT DeviceDL Drag list
21、boxDM Default push button controlEM Edit controlHDM Header controlLB List box controlLVM List view controlPBM Progress barPSM Property sheetSB Status bar windowSBM Scroll bar controlSTM Static controlTB ToolbarTBM TrackbarTCM Tab controlTTM Tooltip controlTVM Tree-view controlUDM Up-down controlWM G
22、eneral window通用窗口消息覆蓋了 一個(gè)較大范圍的信息和請(qǐng)求,包括鼠標(biāo)和鍵盤輸入消息、菜單和對(duì)話框輸入消息、窗口創(chuàng)建和管理消息 及動(dòng)態(tài)數(shù)據(jù)交換消息(DDL) o應(yīng)用程序定義消息應(yīng)用程序可創(chuàng)建用在它自己的窗口中的消息,或是與其它進(jìn)程中的窗口進(jìn)行通信的消息。如果應(yīng)用程序創(chuàng)建了它自己的消息,接收它們的窗口過程必須能夠?qū)ο⑦M(jìn)行翻譯,并提供相應(yīng)的處理。windows系統(tǒng)保留用于系統(tǒng)定義的消息的標(biāo)識(shí)值的范圍從0x0000到0x03FF(等于 WM_USER 1)和0x8000到0xBFFF應(yīng)用程序不能把這些值用于私有消息。從0x0400( WM_USER的值)到0x7FFF之間的值是可用于應(yīng)用
23、程序定義的用于它自己的消息標(biāo)識(shí),而從 0xC000到0xFFFF 之間的值是應(yīng)用程序?yàn)榱伺c其它應(yīng)用程序中的窗口進(jìn)行通信所定義的消息標(biāo)識(shí)。應(yīng)用程序用函數(shù) RegisterWindowMessage注冊(cè)一條消息時(shí),windows系統(tǒng)返回的消息標(biāo)識(shí)在 0xC000到0xFFFF之間,這個(gè)函數(shù)所返回的消息標(biāo)識(shí)應(yīng)保證在整個(gè)系統(tǒng)中是唯一的。如果應(yīng)用程序要?jiǎng)?chuàng)建與其它應(yīng)用程序中的窗口進(jìn)行通信的消息,則使用RegisterWindowMessage來對(duì)它進(jìn)行注冊(cè),這個(gè)函數(shù)可防止由于其它的應(yīng)用程序基于不同的目的使用了相同的消息標(biāo)識(shí)所產(chǎn)生的沖突。消息過濾應(yīng)用程序可使用函數(shù) GetMessage或PeekMessag
24、e來指定一個(gè)消息過濾器,從消息隊(duì)列中檢取指定的消息忽略其它的消息),這是一個(gè)消息標(biāo)識(shí)的范圍(由第一個(gè)和最后一個(gè)標(biāo)識(shí)指定)、一個(gè)窗口句柄或者兩者都是GetMessage 和PeekMessage利用消息過濾器有選擇地檢取隊(duì)列中的某條消息。如果某個(gè)應(yīng)用程序必須檢索消息隊(duì)列中的排在后面的消息,消息過濾則是 很有用的。過濾消息的應(yīng)用程序必須保證滿足消息過濾器的消息是能被投遞的,例如,如果某個(gè)應(yīng)用程序的過濾器用于一個(gè)并不接收鍵 盤輸入的窗口中的 WM_CHAR消息,函數(shù)GetMessage 就不能返回,這樣就會(huì) 掛起”這個(gè)應(yīng)用程序。要過濾鍵盤、鼠標(biāo)和 DDE消息,應(yīng)用程序可以便用下列常量WM_KEYFI
25、RST 和WM_KEYLAST, WM_MOUSEFIRST 和WM_MOUSELAST messages, 和 WM_DDE_FIRST 和 WM_DDE_LAST消息死鎖調(diào)用函數(shù)SendMessage 的線程向另一個(gè)線程發(fā)送一條消息,要等待接收消息的窗口過程返回,如果接收消息的線程在處理 消息時(shí)放棄了控制,發(fā)送消息的線程就不能繼續(xù)執(zhí)行下去,因?yàn)樗却齋endMessage 返回,這種情況就叫做死鎖。接收消息的線程無須直接地放棄控制,調(diào)用下列函數(shù)其個(gè)的一個(gè)就能讓線程放棄控制。DialogBoxDialogBoxIndirectDialogBoxIndirectParamDialogBoxP
26、aramGetMessageMessageBoxPeekMessage窗口過程可以確定它所接收的消息是不是另一個(gè)線程通過調(diào)用函數(shù)InSendMessage 發(fā)來的。在處理一條消息時(shí)調(diào)用前面所列出的任一個(gè)函數(shù)之前,窗口過程應(yīng)首先調(diào)用InSendMessage ,如果函數(shù)返回TRUE ,窗口過程就必須在調(diào)用任何能使線程放棄控制的函數(shù)之前調(diào)用函數(shù) ReplyMessage 。使用消息和消息隊(duì)列這節(jié)描述如何完成下面的工作創(chuàng)建消息循環(huán)檢查消息隊(duì)列 投遞消息發(fā)送消息創(chuàng)建消息循環(huán)windows系統(tǒng)為每一個(gè)線程自動(dòng)創(chuàng)建消息隊(duì)列,如果線程創(chuàng)建了一個(gè)或多個(gè)窗口,就必須提供從線程消息隊(duì)列中檢取消息, 并把它們發(fā)送至
27、相應(yīng)窗口過程的消息循環(huán)。因?yàn)閣indows系統(tǒng)指導(dǎo)向應(yīng)用程序中的某個(gè)窗口發(fā)送消息,線程就必須在啟動(dòng)它的消息循環(huán)之前至少要?jiǎng)?chuàng)建一個(gè)窗口,絕大多數(shù)windows應(yīng)用程序含有一個(gè)創(chuàng)建窗口的線程。一個(gè)典型的應(yīng)用程序是在函數(shù)WinMain中注冊(cè)它主窗口的窗口類。創(chuàng)建和顯示主窗口.然后啟動(dòng)消息循環(huán)。函數(shù)GetMessage 和DispatchMessage用來創(chuàng)建消息循環(huán),如果應(yīng)用程序必須從用戶得到字符輸入,那么在消息循環(huán)中應(yīng)包含函數(shù) TranslateMessage , TranslateMessage把虛鍵消轉(zhuǎn)換成字符消息。下面的范例說明了一個(gè)簡單的windows應(yīng)用程序的WinMain函數(shù)中的消息循
28、環(huán)HINSTANCE hinst;HWND hwndMain;int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR IpszCmdLine, int nCmdShow)(MSG msg;WNDCLASS wc;UNREFERENCED_PARAMETER(IpszCmdLine);/ Register the window class for the main window.if (!hPrevInstance)(wc.style = 0;wc.IpfnWndProc = (WNDPROC) WndProc;
29、wc.cbClsExtra = 0;wc.cbWndExtra = 0;wc.hInstance = hInstance;wc.hIcon = LoadIcon(HINSTANCE) NULL, IDI_APPLICATION);wc.hCursor = LoadCursor(HINSTANCE) NULL, IDC_ARROW);wc.hbrBackground = GetStockObject(WHITE_BRUSH);wc.lpszMenuName = "MainMenu"wc.lpszClassName = "MainWndClass”;if (!Regi
30、sterClass(&wc)return FALSE;hinst = hInstance; / save instance handle/ Create the main window.hwndMain = CreateWindow("MainWndClass", "Sample", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT, (HWND) NULL, (HMENU) NULL, hinst, (LPVOID) NULL);/ If
31、 the main window cannot be created, terminate/ the application.if (!hwndMain)return FALSE;/ Show the window and paint its contents.ShowWindow(hwndMain, nCmdShow);UpdateWindow(hwndMain);/ Start the message loop.while (GetMessage(&msg, (HWND) NULL, 0, 0)TranslateMessage(&msg);DispatchMessage(&
32、amp;msg);)/ Return the exit code to Windows.return msg.wParam;)函數(shù) GetMessage,TranslateMessage 以及DispatchMessage 把MSG 結(jié)構(gòu)的指針當(dāng)作一個(gè)參數(shù)。如果有消息,GetMessage 把它復(fù)制到 MSG結(jié)構(gòu)中,如果這個(gè)消息是一條虛鍵消息(如 WM_KEYDOWN 或 WM_SYSKEYDOWN ),TranslateMessage產(chǎn)生一個(gè)字符消息(WM_CHAR 或WM_SYSCHAR ),并把它放到消息隊(duì)列中去。DispatchMessage 也使用MSG結(jié)構(gòu)的成員用作窗口過程的參數(shù).
33、但要等到窗口過程完成處理后才返回。如果某個(gè)線程支持加速鍵,那么它的消息循環(huán)必須含有函數(shù)TranslateAccelerator 。這個(gè)函數(shù)檢查與線程加速鍵表中的一個(gè)入口相匹配的組合鍵,如果它找到一個(gè)匹配值.TranslateAccelerator就把組合鍵翻譯成一條 WM_COMMAND 消息,并把它發(fā)送到窗口過程。如果某個(gè)線程使用模式對(duì)話框,消息循環(huán)中必須含有函數(shù)IsDialogMessage以便于對(duì)話框能夠接收鍵盤輸入。有關(guān)對(duì)話框,參見對(duì)話框下面的范例說明了一個(gè)使用加速鍵的線程的消息循環(huán),其中顯示了一個(gè)模式對(duì)話框。如果 TranslateAccelerator 或 IsDialogMess
34、age 返回 TRUE (指示消息已被處理),就不再調(diào)用 TranslateMessage 和 DispatchMessage 原因是TranslateAccelerator 或IsDialogMessage完成所有對(duì)消息的翻譯和發(fā)送工作。HWND hwndMain;HWND hwndDlgModeless = NULL;MSG msg;HACCEL haccel;/ Perform initialization and create a main window.while (GetMessage(&msg, (HWND) NULL, 0, 0)if (hwndDlgModeless
35、= (HWND) NULL |!IsDialogMessage(hwndDlgModeless, &msg) &&!TranslateAccelerator(hwndMain, haccel,&msg)TranslateMessage(&msg);DispatchMessage(&msg);檢消息隊(duì)列有時(shí),應(yīng)用程序需要在線程消息循環(huán)的外面檢查線程消息隊(duì)列的內(nèi)容,例如,如果某個(gè)應(yīng)用程序的窗口過程進(jìn)行一個(gè)較長的 繪畫操作,就可能允許用戶中斷這個(gè)操作。除非應(yīng)用程序在處理鼠標(biāo)和鍵盤消息的操作過程中不停地檢查消息隊(duì)列,否則在 操作結(jié)束之前就不再會(huì)響應(yīng)用戶的
36、輸入.原因是線程消息循環(huán)中的函數(shù)DispatchMessage在窗口過程處理完消息之前是不會(huì)返回的。對(duì)于一個(gè)較長時(shí)間的操作,可使用函數(shù)PeekMessage 來檢查消息隊(duì)列,PeekMessage 與函數(shù)GetMessage 是很相似的,都可用來檢查消息隊(duì)列中與過濾器標(biāo)準(zhǔn)相匹配的消息,再把這個(gè)消息復(fù)制到一個(gè)MSG結(jié)構(gòu)中。它們之間主要的不同就是GetMessage要等待隊(duì)列中出現(xiàn)一條與過濾器標(biāo)準(zhǔn)相匹配的消息,而PeekMessage會(huì)立即返回,不管隊(duì)列中是否有某條消息。下面的范例說明了如何使用PeekMessage在一個(gè)長操作期間,檢查消息隊(duì)列中的一條單擊鼠標(biāo)或鍵盤輸入消息。HWND hwnd;
37、BOOL fDone;MSG msg;/ Begin the operation and continue until it is complete/ or until the user clicks the mouse or presses a key.fDone = FALSE;while (!fDone)(fDone = DoLengthyOperation(); / application-defined function/ Remove any messages that may be in the queue. If the/ queue contains any mouse or
38、 keyboard/ messages, end the operation.while (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE)(switch(msg.message)(case WM_LBUTTONDOWN:case WM_RBUTTONDOWN:case WM_KEYDOWN:/ Perform any required cleanup.fDone = TRUE;其它的函數(shù)如GetQueueStatus 和GetInputState 也能用來檢查線程消息隊(duì)列中的內(nèi)容,GetQueueStatus 返回一組標(biāo)志,用來指明隊(duì)列中消息的類型,這
39、是一個(gè)最快的辦法來確定隊(duì)列中是否有消息,如果隊(duì)列中臺(tái)有鼠標(biāo)或鍵盤消息,GetInputState就返回TRUE,這兩個(gè)函數(shù)都能用來確定隊(duì)列中是否有需要處理的消息。投遞消息使用函數(shù)PostMessage 把一條消息投遞到消息隊(duì)列中,PostMessage 在線程消息隊(duì)列的最后放置消息并立即返回,它不等待線程處理這條消息。函數(shù)的參數(shù)包括窗口句柄、消息標(biāo)識(shí)相兩個(gè)消息參數(shù),windows系統(tǒng)把這些參數(shù)復(fù)制到一個(gè) MSG結(jié)構(gòu)中,填充結(jié)構(gòu)的time和pt成員,再把這個(gè)結(jié)構(gòu)放到消息隊(duì)列中。windows系統(tǒng)用函數(shù)PostMessage 所帶的窗口句柄來決定哪一個(gè)線程消息隊(duì)列接收消息.如果句柄是HWND_TO
40、PMOST , windows系統(tǒng)就把這條消息投遞到所有頂層窗口的線程消息隊(duì)列中。函數(shù)PostThreadMessage可用來向一個(gè)指定的線程消息隊(duì)列投遞消息,PostThreadMessage 與PostMessage 也很相似.只是它的第一個(gè)參數(shù)是線程標(biāo)識(shí)而不是窗口句柄,可通過調(diào)用函數(shù)GetCurrentThreadId檢取這個(gè)線程標(biāo)識(shí)。函數(shù)PostQuitMessage用來退出消息循環(huán),PostQuitMessage向當(dāng)前正在執(zhí)行的線程發(fā)送 WM_QUIT消息,如果線程消息循環(huán)接收到WM_QUIT消息,就結(jié)束消息循環(huán)并把控制返回給windows系統(tǒng)。應(yīng)用程序通常調(diào)用 PostQuitMe
41、ssage 響應(yīng)WM_DESTROY 消息,用法如下case WM_DESTROY:/ Perform cleanup tasks.PostQuitMessage(0);break;發(fā)送消息函數(shù)SendMessage 是用來直接向一個(gè)窗口過程發(fā)送消息,SendMessage 調(diào)用一個(gè)窗口過程,并等待過程對(duì)消息的處理和返回結(jié)果。一條消息可以被發(fā)往系統(tǒng)中的任何一個(gè)窗口,而僅要求有一個(gè)窗口句柄,windows系統(tǒng)用這個(gè)句柄決定哪一個(gè)窗口過程應(yīng)該接收這條消息。如果窗口過程在處理由另一個(gè)線程發(fā)來的消息時(shí)放棄控制,就會(huì)出現(xiàn)消息死鎖(有關(guān)消息死鎖,參見 消息死鎖”。)在處理一個(gè)可能是發(fā)自另一個(gè)線程的消息之前
42、,窗口過程應(yīng)首先調(diào)用函數(shù)InSendMessage ,如果這個(gè)函數(shù)返回TRUE,那么窗口過程就應(yīng)在調(diào)用任何可以使線程放棄控制的函數(shù)之前調(diào)用ReplyMessage ,做法如下:case WM_USER + 5:if (InSendMessage()ReplyMessage(TRUE);DialogBox(hInst, "MyDialogBox”, hwndMain, (DLGPROC) MyDlgProc);break;有一些消息可以發(fā)給對(duì)話框中的控制框,這些控制框消息設(shè)置控制框的外觀、特性和內(nèi)容或是檢取有關(guān)控制框的信息。例如, CB_ADDSTRING 消息可以向組合框添加字串,BM_SETCHECK消息能夠設(shè)置復(fù)選框或單選按鈕的選擇狀態(tài)。使用函數(shù)SendDlgItemMessage向一個(gè)控制框發(fā)送一條消息,要指定控制框的標(biāo)識(shí),含有這個(gè)控制框的對(duì)話框窗口的句柄。下面的范例用在
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 醫(yī)藥公司勞動(dòng)合同范本
- 醫(yī)院收費(fèi)合同范本
- 農(nóng)體產(chǎn)品加工合同范本
- 醫(yī)院制氧機(jī)采購合同范本
- 絲接頭采購合同范本
- 公司買賣合同范本
- 買賣小商鋪合同范本
- 企業(yè)房產(chǎn)轉(zhuǎn)讓合同范本
- 單位考察合同范本
- 信息化合同范本
- 地理-廣東省上進(jìn)聯(lián)考領(lǐng)航高中聯(lián)盟2025屆高三下學(xué)期開學(xué)考試題和答案
- GB/T 20032-2024項(xiàng)目風(fēng)險(xiǎn)管理應(yīng)用指南
- 新建鐵路專用線工程可行性研究報(bào)告
- 護(hù)膚基礎(chǔ)知識(shí)
- 博鰲亞洲論壇:創(chuàng)新報(bào)告2024
- 2025年全國青少年禁毒知識(shí)競賽題庫及答案(401一516) - 副本
- 小學(xué)生網(wǎng)絡(luò)安全教育
- 2025年高三歷史高考第二輪復(fù)習(xí)知識(shí)梳理中國史部分復(fù)習(xí)提綱
- 2025山東能源集團(tuán)中級(jí)人才庫選拔高頻重點(diǎn)提升(共500題)附帶答案詳解
- 2025年蒙鹽集團(tuán)招聘筆試參考題庫含答案解析
- 精神科醫(yī)療質(zhì)控課件
評(píng)論
0/150
提交評(píng)論