Windows 訊息機制

2021-09-06 14:29:44 字數 4172 閱讀 4023

windows 是乙個訊息驅動的作業系統。乙個訊息由乙個訊息名稱(uint 型別)和兩個引數

(wparam,lparam)構成。當使用者進行了輸入或是視窗的狀態發生改變時,系統會傳送訊息到某

乙個視窗。例如當選單選中之後會有wm_command 訊息傳送,wparam 的高字中

(hiword(wparam))是命令的id 號,對選單來說就是選單id。當然使用者也可以定義自己的訊息名稱,

也可以利用自定義訊息來傳送通知和傳送資料。

乙個訊息必須由乙個視窗接收。在視窗的訊息處理函式中可以對訊息進行分析,對自己感興趣的

訊息進行處理。例如希望對選單選擇進行處理,那麼可以定義對wm_command 進行處理的**,

如果希望在視窗中進行圖形輸出就必須對wm_paint 進行處理。

事實上為了應付那些沒有被響應的訊息,windows 為視窗編寫了預設的視窗訊息處理函式,這個

視窗過程將負責處理那些程式中沒有處理的訊息。正因為有了這個預設視窗過程,程式設計師才可以利用

windows 的視窗進行開發而不必過多關注視窗各種訊息的處理。例如視窗在被拖動時會有很多訊息發

送,而程式設計師都可以不予理睬讓系統自己去處理。

說到訊息就不能不說視窗控制代碼,系統通過視窗控制代碼在整個作業系統中唯一標識乙個視窗。傳送消

息時必須指定乙個視窗控制代碼表明該訊息由哪個視窗接收。而每個視窗都會有自己的視窗訊息處理函式,

所以使用者的輸入就會被正確的處理。

下面這段偽**演示如何在視窗過程中處理訊息:

long windowproc(hwnd hwnd,uint umessagetype,wparam w,lparam l)

}

在windows 作業系統中維護著乙個或多個訊息佇列,所有產生的訊息都被放入到佇列中。系統在

佇列中每次取出一條訊息,根據訊息的接收控制代碼而將該訊息傳送給擁有該視窗的訊息迴圈。每乙個運

行的程式都有自己的訊息迴圈,在迴圈中得到屬於自己的訊息並根據接收視窗的控制代碼呼叫相應的視窗

過程。而在沒有訊息時訊息迴圈就將控制權交給系統,從而使windows 可以同時進行多個任務。下面

的偽**演示了訊息迴圈的用法:

while (1

)

初看這段**容易給人一種錯覺,這是乙個忙等待(busy waiting)的訊息迴圈,因為採用了while(1)

的迴圈方式,而忙等待是個非常糟糕的東西。

而實際上絕大部分時間裡這個程式是在阻塞狀態, 因為當程式沒有收到訊息通知時

getmessage 就不會返回,所以也就不會占用系統的cpu 時間。getmessage 函式的阻塞呼叫是這

段**的關鍵部分。

上面這段**的意思是呼叫getmessage 函式從訊息佇列中取出訊息,然後呼叫dispatchmessage

將訊息傳送給視窗訊息處理程式。

在16 位的系統中只有乙個訊息佇列,所以系統必須等待當前任務處理訊息後才可以傳送下一訊息

到相應程式,如果乙個程式陷入死迴圈或是耗時操作時,系統就會得不到控制權。這種多工系統也

稱為協同式的多工系統。windows 3.x 就是這種系統。而32 位的系統中每乙個執行的程式都會有一

個訊息佇列,所以系統可以在多個訊息佇列中轉換而不必等待當前程式完成訊息處理就可以得到控制

權。這種多工系統就稱為搶先式的多工系統,windows 95/nt 就是這種系統。

訊息能夠被分為佇列化的和非佇列化的。佇列化的訊息是由windows 放入程式訊息佇列中的。在

程式的訊息迴圈中,重新傳回並分配給視窗訊息處理程式。非佇列化的訊息在windows 呼叫視窗時直

接送給視窗訊息處理程式。也就是說,佇列化的訊息被傳送給訊息佇列,而非佇列化的訊息則傳送給

視窗訊息處理程式。任何情況下,視窗訊息處理程式都將獲得視窗所有的訊息——包括佇列化的和非

佇列化的。視窗訊息處理程式是視窗的訊息中心。

佇列化訊息基本上是使用者輸入的結果,以擊鍵(如wm_keydown 和wm_keyup 訊息)、

擊鍵產生的字元(wm_char)、滑鼠移動(wm_mousemove)和滑鼠按鈕(wm_lbuttondown)

的形式給出。佇列化訊息還包含時鐘訊息(wm_timer)、更新訊息(wm_paint)和退出訊息

(wm_quit)。

在許多情況下,非佇列化訊息來自呼叫特定的windows 函式。例如,當winmain 呼叫createwindow

時,windows 將建立視窗並在處理中給視窗訊息處理程式傳送乙個wm_create 訊息。當winmain

呼叫showwindow 時,windows 將給視窗訊息處理程式傳送wm_size 和wm_showwindow訊息。

雖然windows 程式可以多執行緒執行,但訊息佇列只為視窗訊息處理程式在該執行中的視窗處理消

息。換句話說,訊息迴圈和視窗訊息處理程式不是併發執行的。當乙個訊息迴圈從其訊息佇列中接收

乙個訊息,然後呼叫dispatchmessage 將訊息傳送給視窗訊息處理程式時,直到視窗訊息處理程式將

控制傳回給windows,dispatchmessage 才能結束執行。

當然,視窗訊息處理程式能呼叫給視窗訊息處理程式傳送另乙個訊息的函式。這時,視窗訊息處

理程式必須在函式呼叫傳回之前完成對第二個訊息的處理。那時視窗訊息處理程式將處理最初的訊息。

例如,當視窗過程呼叫updatewindow 時,windows 將呼叫視窗訊息處理程式來處理wm_paint 訊息。

視窗訊息處理程式處理wm_paint 訊息結束以後,updatewindow 呼叫將把控制傳回給視窗訊息處理

程式。在工程中經常還會有這樣的需求,即要求程式在空閒的時候執行某種額外的操作或運算。實際上

在windows 中有很多閒置時間,在這個時間內,所有訊息隊列為空,windows 只停在乙個小迴圈中等

待鍵盤或者滑鼠輸入。能否在閒置時間內獲得控制,從而做某種操作或運算,並且只在有訊息加入程

序的訊息佇列之後才釋放控制呢?這就是peekmessage 函式的目的之一。下面是peekmessage 呼叫的

乙個例子:

peekmessage (&msg, null, 0, 0, pm_remove) ;

前面的4 個引數(乙個指向msg 結構的指標、乙個視窗控制代碼、兩個值指示訊息範圍)與getmessage

的引數相同。將第

二、三、四個引數設定為null 或0 時,表明想讓peekmessage 傳回程式中所有窗

口的所有訊息。如果要將訊息從訊息佇列中刪除,則將peekmessage 的最後乙個引數設定為

pm_remove。如果不希望刪除訊息,那麼可以將這個引數設定為pm_noremove。

getmessage 不將控制傳回給程式,它一直處於阻塞狀態,直到從程式的訊息佇列中取得訊息,但

是peekmessage 總是立刻傳回,而不論乙個訊息是否出現。當訊息佇列中有乙個訊息時,peekmessage

的傳回值為true,並且將按通常方式處理訊息。當佇列中沒有訊息時,peekmessage 傳回false。

可以將如下所示的訊息迴圈:

while (1

)

替換為下面的迴圈:

while

(true)

else

}return msg.wparam ;

如果peekmessage 的傳回值為true,則訊息按通常方式進行處理。如果傳回值為false,則在

將控制傳回給windows 之前,還可以做一點工作。

需要注意的是,不能用peekmessage 從訊息佇列中刪除wm_paint 訊息,實際上getmessage 並

不從訊息佇列中刪除wm_paint 訊息。從佇列中刪除wm_paint 訊息的唯一方法是令視窗顯示區域

的失效區域變得有效,這可以用validaterect 和validatergn 或者beginpaint 和endpaint 對來完成。如

果在使用peekmessage 從佇列中取出wm_paint 訊息後,同平常一樣處理它,那麼就不會有問題了。

所不能作的是使用如下所示的程式**來清除訊息佇列中的所有訊息:

while (peekmessage (&msg, null, 0, 0, pm_remove)) ;

這行**從訊息佇列中刪除wm_paint 之外的所有訊息。如果佇列中有乙個wm_paint 訊息,

程式就會永遠地陷在while 迴圈中。

windows訊息機制

一 windows中有乙個系統訊息佇列,對於每乙個正在執行的windows應用程式,系統為其建立乙個 訊息佇列 即應用程式佇列,用來存放該程式可能 建立的各種視窗的訊息。應用程式中含有一段稱作 訊息迴圈 的 用來從訊息佇列中檢索這些訊息並把它們分發到相應的視窗函式中。二 windows為當前執行的每...

windows訊息機制

一 windows中有乙個系統訊息佇列,對於每乙個正在執行的windows應用程式,系統為其建立乙個 訊息佇列 即應用程式佇列,用來存放該程式可能 建立的各種視窗的訊息。應用程式中含有一段稱作 訊息迴圈 的 用來從訊息佇列中檢索這些訊息並把它們分發到相應的視窗函式中。二 windows為當前執行的每...

Windows訊息機制

訊息佇列分為 系統訊息佇列 執行緒訊息佇列 應用程式訊息佇列 系統訊息佇列 這是系統唯一的佇列,輸入裝置 滑鼠 鍵盤等 的驅動程式把使用者的操作轉換成訊息的形式放置到系統佇列中,然後系統會把此訊息轉到目標視窗所在的執行緒訊息佇列中等待處理。執行緒訊息佇列 每個gui 圖形使用者 介面 graphic...