王光輝
(成都理工大學信息科學與技術學院,四川成都610059)
Windows操作系統(tǒng)是基于消息響應機制的被動式系統(tǒng)。Windows應用程序是消息驅動[1]程序,又稱事件驅動程序。事件驅動意味著操作系統(tǒng)的每一部分之間以及操作系統(tǒng)與應用程序之間是通過“消息”進行通信聯(lián)系的。由此可見,消息機制在Windows應用編程[2]的重要性。
消息是指Windows發(fā)出的一個通知[3],告訴應用程序某個事情發(fā)生了。例如,單擊鼠標、改變窗口大小、按下鍵盤上的一個鍵都會使Windows發(fā)送一個消息給應用程序。它可以由硬件、Windows、應用程序共同產(chǎn)生。消息通常分為以下四種:
(1)標準消息:除了WM_COMMAND,所有的以WM開頭的消息都是標準消息。如窗口、鼠標移動、窗口大小改變等。程序啟動或退出甚至每一段固定的時間都會產(chǎn)生標準Windows消息。
(2)命令消息:來自于菜單、加速鍵、工具欄按鈕的消息,這類消息都以WM_COMMAND形式呈現(xiàn)。
(3)通知消息:由控件產(chǎn)生的消息。按鍵和鼠標的單擊列表框都會產(chǎn)生這類消息[4],這類消息的目的是為了向父窗口(通常是對話框)通知事件的發(fā)生,它也是以WM_COMMAND形式呈現(xiàn)的。
(4)用戶自定義的消息。
在Windows程序中,消息本身是作為一個記錄傳遞給應用程序的,這個記錄中包含了消息的類型以及其它信息,由MSG結構體表示。MSG結構體的定義如下:
在MSG結構中,消息是由一個消息名稱(UINT)和兩個參數(shù)(WPARAM,LPARAM)組成。當用戶進行了輸入或者窗口的狀態(tài)發(fā)生改變時,系統(tǒng)都會發(fā)送消息到某一個窗口。例如,當菜單點中之后會有WM_COMMAND消息發(fā)送。其中,WPARAM的高字節(jié)(HIWORD(wParam))是命令的ID號,是菜單ID。同時,用戶能定義自己的消息名稱,也能利用自定義消息來發(fā)送通知和傳送數(shù)據(jù)。
系統(tǒng)通過窗口句柄在整個系統(tǒng)中唯一標識一個窗口,發(fā)送一個消息時必須指定一個窗口句柄表明該消息由指定窗口接收。窗口可以是任何類型的屏幕對象,因為Win32能夠維護大多數(shù)可視對象的句柄(窗口、對話框、按鈕、編輯框等)。句柄決定消息被發(fā)送到哪個窗口。
在Windows中發(fā)送消息時,一般使用PostMessage()和SendMessage()函數(shù)[5],但是它們在發(fā)送方式上有些差別。二者最基本的區(qū)別在于SendMessage()通過調用窗口過程,把消息立即發(fā)往另一個窗口并且等到該消息被處理完后才返回。PostMessage()是把消息封裝成一個MSG結構,投遞到消息隊列中,然后立即返回,無需等待。因此,PostMessage()是異步的,SendMessage()是同步的;PostMessage()只負責將消息放到消息隊列中,不確定何時處理。SendMessage()要等到收到消息處理的返回碼(DWord類型)后才繼續(xù);PostMessage()執(zhí)行后馬上返回,SendMessage()必須等到消息被處理后才會返回。
Windows消息機制是由消息隊列、消息循環(huán)和窗口過程三個部分組成。
Windows為所有消息維護著一個系統(tǒng)消息隊列,而對于每一個應用程序,系統(tǒng)又將會創(chuàng)建一個對應的消息隊列。Windows根據(jù)消息結構的內容將不同的消息發(fā)送給相應應用程序的消息隊列。應用程序通過PeekMessage()或GetMessage()函數(shù)從Windows消息隊列中獲取消息,然后分派給某個窗口。Windows保存的消息隊列是以線程(Thread)來分組的,即每個線程都有自己的消息隊列。
通過Windows消息循環(huán)機制[6],應用程序能從消息隊列中檢索消息,再把它分派給適當?shù)拇翱?。然后繼續(xù)從消息隊列中檢索下一條消息,再分派給適當?shù)拇翱冢来芜M行。函數(shù)的原型為:
消息循環(huán)以GetMessage()調用開始,它從消息隊列中取出一個消息。當取出的消息為WM_QUIT(退出消息),消息循環(huán)和應用程序退出。TranslateMessage()函數(shù)將鍵盤按鍵的虛擬碼轉換為ASCII碼,同時將WM_CHAR消息發(fā)送到消息隊列中。DispatchMessage()函數(shù)將消息轉發(fā)給Windows操作系統(tǒng)來調用相應的窗口過程函數(shù)處理。如果消息隊列為空,應用程序就將控制權交還給Windows。如果有需要控制權的應用程序,Windows就將控制權轉交給應用程序。這種控制權的交換使得Windows成為多任務的操作系統(tǒng)。
窗口過程是用來接收傳遞給窗口的消息,它的任務就是獲取消息然后響應它。任何一個窗口類都有一個窗口過程。同一個類的窗口使用同樣的窗口過程來響應消息。窗口過程是一個回調函數(shù)(Callback Function),它是由Windows操作系統(tǒng)負責調用的,而應用程序本身不能調用它。消息的處理是由窗口過程完成的,窗口過程處理了一個消息后,通常要返回一個值給Windows。系統(tǒng)發(fā)送消息給窗口過程,通常將消息數(shù)據(jù)作為參數(shù)傳遞給它。消息到來之后,窗口過程按照消息類型的排序進行處理,其中的參數(shù)則用來區(qū)分不同的消息。同時,窗口過程使用參數(shù)產(chǎn)生合適行為。下面是一個典型窗口過程的偽代碼:
Windows的操作會產(chǎn)生大量的不同種類的消息,窗口過程函數(shù)不可能處理所有的消息,只處理需要的消息,其它的消息就交給系統(tǒng)處理。DefaultWndProc()就是系統(tǒng)提供的處理其它程序里沒有捕獲的消息。
Windows消息機制的具體實現(xiàn)過程,如圖1所示:
圖1 Windows消息機制
一個消息從產(chǎn)生到被一個窗口響應,主要有5個步驟:
(1)系統(tǒng)中發(fā)生了某個事件;
(2)Windows把這個事件翻譯為消息,把它放到系統(tǒng)消息隊列中,然后轉發(fā)到相應線程消息隊列里;
(3)應用程序從消息隊列中接收到這個消息,把它存放在TMsg記錄中;
(4)應用程序把消息傳遞給系統(tǒng),系統(tǒng)調用適當?shù)拇翱谶^程;
(5)窗口過程響應這個消息并進行處理。
在Windows消息機制中,步驟3和4構成了應用程序的消息循環(huán)。消息循環(huán)使應用程序能夠響應外部的事件,所以,它是Windows應用程序的核心。消息循環(huán)的任務就是從消息隊列中檢索消息,然后把消息傳遞給適當?shù)拇翱?。如果消息隊列中沒有消息,Windows就允許其它應用程序處理它們的消息。
消息機制是Windows應用程序工作的核心,利用各種開發(fā)工具在此平臺上進行開發(fā),不可避免地要與消息處理打交道。本文從消息的結構、發(fā)送、處理介紹了Windows消息機制。對于一個編寫Windows程序的程序員來說,理解Windows消息機制的運行原理對于編寫Windows應用程序是十分有益的。
[1]陳希勝.基于WINDOWS下的DMA編程[J].科技廣場,2008,12:121.
[2]周金萍,徐丙立等.Windows系統(tǒng)編程[M].北京:人民郵電出版社,2002.7.
[3]王芳.Windows消息機制在VB編程中的應用[J].信息技術,2005(7):146.
[4]徐靜蓉,趙雷,楊季文.消息分層處理機制在Windows應用程序開發(fā)中的應用[J].蘇州大學學報(自然科學版),2006,22(1):61.
[5]張朝霞.MFC對消息的管理初探[J].內蒙古科技與經(jīng)濟,2004(23):55.
[6]李元臣.Windows的消息循環(huán)與Delphi中的消息機制[J].洛陽師范學院學報,2001(2):74.