Windows 消息機制詳解

總的來說:
MSG包括:
窗口句柄,指示MSG發送的目的窗口
消息標識
lPARAM、wParam
發送時間
發送時的鼠標位置
 
關於消息隊列:
Windows系統有一個系統消息隊列
每個線程都有一個自己的消 息隊列(由於發送消息MSG需 要提供一個窗口HWnd,而基 本有窗口的線程,都是UI線 程),因此基本上如果線程使用了GDI函數,則windows給該線程分配一個線程消息隊列,這個消息隊列負責該線程的所有窗口的消息。
 
所有的窗口都有自己的句柄(HWND),消息被髮送時,這個句柄就已經被指定了。所以 當子窗口收到一個消息時,其父窗口不會也收到這個消息,除非子窗口手 動的轉發。
 
消息分爲:
實際上MSDN把消息分爲隊列型(Queued Message)和非隊列型(Non-queued Message),這只是不同的路由方式, 但最終都會由消息處理函數來處理。
隊 列型消息包括硬件的輸入(WM_KEY*等)、WM_TIMER消 息、WM_PAINT消息等;非隊列型的一些例子有WM_SETFOCUS, WM_ACTIVE, WM_SETCURSOR等,它們被直接發送給處理函數。
其實,按照MSDN的說法和消息的路由過程可以理 解爲,Posted Message Queue裏的消息是真正的隊列型消 息,而通過SendMessage()發送到消息,即使它進入了Sent Message Queue,由於SendMessage要求的同步處理,這些消息也 應該算非隊列型消息。也許,Windows系統會特殊處理,使消息強行繞 過隊列。
 
  

=====================

一節詳細描述消息和消息隊列以及如何在 你程序中使用他們。 
關於消息和消息 隊列
與傳統的應用程序不 同,Microsoft Windows應用程序並不顯式地用一個函數的調用(如c運行庫)來獲取輸入,而是,等待windows系統把輸入傳給它們。 
windows系統把應用程序 的所有輸入傳給應用程序的窗口,每個窗口都有一個稱之爲窗口過程的函數.當窗口有輸入時windows系統要調用它,窗口過程處理輸入並把控制返回 windows系統。有關窗口過程,參見 “窗口過程”。 這一章講述消息及消息隊列,並說明在應用程序中如何使用它們。 
消息
windows系統以消息的形式把輸入傳給窗口過程,消息是由windows系 統或應用程序產生的.windows系統對每一個輸入事件都要產生消息,例如,用戶按鍵盤、移動鼠標或單擊一個滾動條控制框。windows系統爲了響應 應用程序給系統帶來的變化也會產生消息,比如應用程序改變了系統字體資源池或是改變了一個窗門的大小。應用程序可通過產生消息指導它自己的窗口來完成某個 任務,或是與其它應用程序的窗口進行通信。 
windows 系統把消息發送給窗口過程.窗口過程有四個參數:窗口句柄、消息標識以及兩個叫做消息參數的32位值。窗口句柄決定消息將發送到哪—個窗 口,windows系統則用它來確定向哪一個窗口過程發送消息。 
消息標識是一個命名的常量,由它來標明消息的目的。如果窗口過程接收到一條消息,它就通過消息標識來決定如何處理這條 消息。例如,消息標識WM_PAINT 通知窗口過程,窗口的客戶區被改變了,需要重畫。 
消息參數指定窗口過程在處理消息時所用的數據或數據的位 置,消息的意圖及數值取決了消息本身。消息參數可以是一個整數、緊縮的位標誌、一個含有附加數據結構的指針等等。如果消息不使用消息參數,一般就都設置成NULL 、 窗口過程必須檢查消息標識以確定如何解釋消息參數。 
消息路由
windows系統用兩種方式向窗口過程發送消息:把消息投遞到一個先進先出的消息隊列中,它是一個系統定義的內存塊用於臨時存儲消息;或是把消 息直接發給窗口過程。 
投遞到 消息隊列中的消息叫排隊消息,它們主要是用戶通過鼠標或鍵盤的輸入結果.如WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_KEYDOWN, and WM_CHAR 消息。其它的排隊消息包括定時器、繪製和退出消息:WM_TIMER, WM_PAINT, and WM_QUIT 。所有直接發送到窗口過程的其它消息稱之爲非排隊消息。 
排隊消息
windows系統在同一時間可顯示多個窗口,要發送鼠標和鍵盤輸入到相應 的窗口,windows系統要用到消息隊列,它要管理一個系統消息隊列和任意數目線程消息隊列,每一個隊列對應於一個線程。 
不管什麼時候,只要用戶移動鼠標或是敲鍵盤.鼠標或鍵盤的 設備驅動器都要把輸入轉換成消息,並把它們放到系統消息隊列中去。windows從系統隊列中每次移走一條消息,確定目的窗口,再把它們投遞到創建目的窗 口的線程的消息隊列中,線程消息隊列接收所有由該線程創建的窗口的鼠標和鍵盤消息。線程從它的隊列中移走消息並指導windows系統將它們發送到相應的 窗口過程進行處理。有關線程,參見 “進程和線程”。 
WM_PAINT 消息有點特別,windows系統總是把這條消息放在消息隊列的最後,這樣 可保證窗口按先進先出次序接收它的輸入消息,WM_PAINT 消息被保持在隊列中,只有在隊列中沒有其它消息時才發送 到窗口過程。同一個窗口的多個WM_PAINT 消息被合併成一個WM_PAINT 消 息,把客戶區所有無效部分合併成一個區域.合併WM_PAINT 消息節約了窗口必須重畫客戶區內容的時間。 
系統向線程消息隊列投遞消息是通過填充 一個MSG 結構,再把它複製到消息隊列中,MSG 結構中的信息包括接收消息的窗口 句柄、消息標識、兩個消息參數、消息時間以及鼠標的位置,線程可把消息投遞到它自己的消息隊列中或是通過函數 PostMessage 和PostThreadMessage 把 消息投遞到其它線程的隊列中去。 
應 用程序可通過函數GetMessage 從它的隊列中移走一條消息,應用程序還可用函數PeekMessage 來 檢查隊列中的某個消息但並不移走它,這個函數用有關這條消息的信息填充MSG 結構。 
把一條消息從它的隊列中移走後.應用程序可用函數DispatchMessage 指 導windows系統把這條消息發送到窗口過程進行處理。DispatchMessage 利用前面調用函數GetMessage 或PeekMessage 時 填充的MSG 結構的指針,把窗口句柄、消息標識及兩個消息參數傳給窗口過程,但它並不傳送時間或鼠標光標的位置.應用 程序可以在處理一條消息時,通過調用函數GetMessageTime 和GetMessagePos 來 獲取這些信息。 
一個線程可以 用函數WaitMessage 當他沒有其他消息在其隊列裏時,產生對其他線程的控制。此函數將終止線程,直到一個新消 息被放入該線程的消息隊列裏,然後返回。 
你 可以調用函數SetMessageExtraInfo 來設置當前線程消息隊列的附加信息。是和當前線程的消息隊列聯繫 的32位值。用戶可以用函數GetMessageExtraInfo 來獲得附加信息,該信息將會保留到下次調用函數GetMessage 或PeekMessage 之 前。 
非排隊消息
非 排隊消息是直接發送到目標窗口過程的,而不通過系統消息隊列和線程消息隊列。windows系統一般通過發送非排隊消息把影響某窗口的事件通知窗口。例 如,如果用戶激活一個新的應用程序窗口.windows系統就會向該窗口發送一系列的消息,包括:WM_ACTIVATE ,WM_SETFOCUS 和WM_SETCURSOR ,這些消息分別通知窗口: 它被激活了;將通過這個窗口進行鍵盤輸入;鼠標已移到這個窗口邊 框的裏面了 。非排隊消息也有可能發生在 應用程序調用一個windows系統函數時,例如,在應用程序用函數SetWindowPos 來移動一個窗口之 後,windows系統發送一條WM_WINDOWPOSCHANGED 消息。 
應用程序是調用函數SendMessage 、SendNotifyMessage 或SendDlgItemMessage 發 送消息的。 
消息處理
應用程序必須刪除和處理投遞到它的線 程消息隊列中的消息,單一線程的應用程序一般是在它的WinMain函數中使用一個消息環來刪除消息,並把消息發送到相應的窗口過程進行處理。具有多重線 程的應用程序在創建窗口的每一個線程中使用一個消息環,下一節將講述消息環是如何工作的,另外還解釋了窗口過程的一般規則。 
消息環
一個簡單的消息環含有一個對下列函數的調 用:GetMessage, TranslateMessage和DispatchMessage。函數GetMessage從隊列中檢取一條消息並把它複製到一個MSG結構 中.GetMessage應返回TRUE,但如果它得到的是WM_QUIT消息,它就返回FALSE並結束循環。在單一線程的應用程序中,結束消息循環通 常是關閉應用程序的第一步。一般在應用程序主窗口的窗口過程中響應WM_DESTROY消息時,應用程序通過函數PostQuitMessage關閉它自 己的消息環。 
如果在 GetMessage中指定窗口句柄,那麼從隊列中檢取的只是指定窗口的消息。GetMessage 也能過濾隊列中的消息,這種情況下檢取的只是指定範圍內的消息。有關過濾消息,參見 “消息過濾”。 
如果某個線程想接收鍵盤的字符輸入,那麼線程消息環中必須含有 TranslateMessage。Windows系統在用戶每按一次鍵時會產生一個虛鍵消息(WM_KEYDOWN和WM_KEYUP),虛鍵消息含有 一個標識哪一個鍵被按過的虛鍵碼,但不是它的字符值,要得到這個值,消息環中必須含有TranslateMessage,由它來把虛鍵消息翻譯成字符消息 (WM_CHAR),再把它放回到應用程序的消息隊列中去.這樣字符消息才能在消息環的下一輪循環中被髮送到窗口過程。 
函數DispatchMessage把消息發送到與MSG結構 中指定的窗口句柄相應的窗口過程,如果窗口句柄是HWND_TOPMOST ,DispatchMessage就把消息發送到系統中所有頂層窗口的窗口過程。如果窗口句柄是NULL,對於這條消息DispatchMessage則 什麼也不做。 
應用程序的主線 程在初始化應用程序並且至少創建了一個窗口之後就開始了消息循環,一旦開始,消息環就連續不斷地從線程的消息隊列中校取消息並把它們分發到相應的窗口,函 數GetMessage從消息隊列中檢取到WM_QUIT消息時,消息環就結束了。 
一個消息隊列只需要有一個消息環,而不管應用程序有多少個窗口,因爲隊列中的每一條消息是一個 MSG結構,其中含有接收消息的窗口句柄,DispatchMessage總能把消息發送到相應的窗口。 
應用程序可以有多種方法修改它的消息環,例如,它可以從隊列中檢取消息但並不 發送到任何窗口,這對那些投遞不指定窗口的消息的應用程序是很有用的,(這些消息是提供給應用程序的,而不是某個窗口,因爲它們含有NULL窗口句柄)。 應用程序也能指導GetMessage來搜索隊列中一個特定的消息,而不管其它消息,這對那些有時不按消息隊列先進先出次序檢取消息的應用程序來說是很有 用的。 
使用鍵盤加速鍵的應用 程序必須能夠把鍵盤消息轉換成命令消息,要這樣做,應用程序的消息環必須調用函數TranslateAccelerator有關加速鍵,參見 “鍵盤加速鍵”。 
窗口過程
窗口過程是一個函數,用來接收和處理 所有發送到該窗口的消息,每個窗口類都有一個窗口過程,同一窗口類所創建的窗口共用同一個窗口過程來響應消息。 
系統通過把消息數據作爲過程的參數來向窗口過程發送消息,再由窗口過程 完成與消息相應的活動。它需要檢查消息的標識,在處理消息時要使用由消息參數指定的這個信息。 
窗口過程一般不會忽略—條消息,如果它不處理某條消息,它就必須把這條消息傳回系統進行 默認處理,窗口過程是調用函數DefWindowProc 來完成的,由它完成一個默認的操作並返回消息結果。絕大多數 窗口過程只處理幾種類型的消息,其它的則通過調用DefWindowProc 傳給了系統。 
因爲窗口過程是由所有屬於同類窗口共享的,所以它能處理 幾個不同窗口的消息,要識別受消息影響的某個窗口,窗口過程可以檢查消息所帶的窗口句柄。有關窗口過程,參見 “窗口過程”。 
傳遞和發送消息
任何應用程序都能投遞和發送消息,就跟系統一樣,應用程序投遞一 條消息是通過把它複製到消息隊列,發送消息則是通過把消息數據作爲窗門過程的參數。要投遞消息,應用程 序需 要用到函數PostMessage ,要發送消息,程序使用函數SendMessage, BroadcastSystemMessage, SendMessageCallback, SendMessageTimeout, SendNotifyMessage 或SendDlgItemMessage 。 
應用程序通常投遞—條消息來通知某個窗口去完成 一個任務。PostMessage 爲消息創建一個MSG 結構並把消息拷到消息隊列 中,最後由應用程序的消息環檢取這條消息再把它發送到相應的窗口過程。 
應用程序一般是通過發送一條消息通知窗口過程立即完成某項任務,函數SendMessage 把 消息發送到與給定窗口相應的窗口過程,這個函數要等待窗口過程完成處理井返回消息的結果。父窗口與子窗口之間也是通過發送消息來進行相互間的通信,例如, 某個父窗口有一個編輯控制框作爲它的子窗口,就可通過向它發送消息設置控制框的正文,這個控制框則通過向父窗口發送消息來把用戶對正文的改變通知其父窗 口。 
函數SendMessageCallback 也 能發送消息到指定窗口的窗口過程裏,但是,這函數是立即返回,當窗口過程函數處理完消息後,系統調用指定的回調函數,有關更多回調函數信息,參考函數SendAsyncProc 。 
有時,應用程序也有可能要求 向系統中的所有頂層窗口發送或投遞一條消息,例如,如果應用程序改變了系統的時間,它必須通過發送WM_TIMECHANGE 消 息來通知所有頂層窗口,應用程序向所有頂層窗口發送或投遞一條消息是調用函數SendMessage 或PostMessage , 並在hwnd 參數中指定HWND_TOPMOST 。你同樣通過函數BroadcastSystemMessage 指 定參數lpdwRecipients 的值爲BSM_APPLICATIONS 來 廣 播消息給所有程序 
應用程序能 夠投遞一條消息而不指定窗口,在調用PostMessage 時應用程序提供NULL 窗 口句柄,這條消息就被投遞到與當前線程相應的隊列中。因爲沒有指定窗口句柄,應用程序就必須在處理消息環中的這條消息,這也是一種創建消息的方法.此類消 息適用於整個應用程序,而不只是指某個窗口。 
使用函數InSendMessage 窗口過程能夠確定它所處理的消息是從另一個線程發來的,這種能力 在需要根據消息源進行消息處理時是很有用的。 
經常出現的一個編程錯誤是假設函數PostMessage 總能成功地投遞一條消息,這在消息隊列是滿 的時候是不對的,應用程序應該檢查函數PostMessage 的返回值以確認消息是否已經被投遞,否則要重新投遞這條 消息。 
消息種類
這部分將兩種類型windows消 息;系統定義的消息,程序定義的消息 
系 統消息
系統使用系統定義的 消息來控制應用程序的操作,並給應用程序提供輸入或其他信息進行處理。系統在與應用程序進行通信是時是發送系統消息的。應用程序也能發送或投遞系統消息, 應用程序通常用這些消息來控制預註冊類創建的控制窗口的操作。 
每條系統消息都有一個唯一的消息標識,對應於一個符號常量(在Windows系統頭文件中定義),它表明了消息的目的, 例如,常量WM_PAINT 要求窗口繪製它的內容。 
符號常量指定了系統消息所屬的類別,常量的前綴標識能夠解釋和處理消息的畝口的類型。下表列出 了前綴及相應的消息類別: 
前 綴 消息類 
ABM Application desktop toolbar 
BM Button control 
CB Combo box control 
CDM Common dialog box 
DBT Device 
DL Drag list box 
DM Default push button control 
EM Edit control 
HDM Header control 
LB List box control 
LVM List view control 
PBM Progress bar 
PSM Property sheet 
SB Status bar window 
SBM Scroll bar control 
STM Static control 
TB Toolbar 
TBM Trackbar 
TCM Tab control 
TTM Tooltip control 
TVM Tree-view control 
UDM Up-down control 
WM General window 
通 用窗口消息覆蓋了—個較大範圍的信息和請求,包括鼠標和鍵盤輸入消息、菜單和對話框輸入消息、窗口創建和管理消息及動態數據交換消息(DDL)。 
應用程序定義消息
應用程 序可創建用在它自己的窗口中的消息,或是與其它進程中的窗口進行通信的消息。如果應用程序創建了它自己的消息,接收它們的窗口過程必須能夠對消息進行翻 譯,並提供相應的處理。 ’ 
windows 系統保留用於系統定義的消息的標識值的範圍從0x0000到0x03FF(等於WM_USER —1)和0x8000到 0xBFFF應用程序不能把這些值用於私有消息。 
從0x0400(WM_USER 的值)到0x7FFF之間的值是可用於應用程序定義的用於它自己 的消息標識,而從0xC000到0xFFFF之間的值是應用程序爲了與其它應用程序中的窗口進行通信所定義的消息標識。 
應用程序用函數RegisterWindowMessage 注 冊一條消息時,windows系統返回的消息標識在0xC000到0xFFFF之間,這個函數所返回的消息標識應保證在整個系統中是唯一的。如果應用程序 要創建與其它應用程序中的窗口進行通信的消息,則使用RegisterWindowMessage 來對它進行註冊,這 個函數可防止由於其它的應用程序基於不同的目的使用了相同的消息標識所產生的衝突。 
消息過濾
應用程序可使用函數GetMessage 或PeekMessage 來 指定一個消息過濾器,從消息隊列中檢取指定的消息[忽略其它的消息),這是一個消息標識的範圍(由第一個和最後一個標識指定)、一個窗口句柄或者兩者都是GetMessage 和PeekMessage 利 用消息過濾器有選擇地檢取隊列中的某條消息。如果某個應用程序必須檢索消息隊列中的排在後面的消息,消息過濾則是很有用的。 
過濾消息的應用程序必須保證滿足消息過濾器的消息是能被投 遞的,例如,如果某個應用程序的過濾器用於一個並不接收鍵盤輸入的窗口中的WM_CHAR 消息,函數GetMessage 就 不能返回,這樣就會“掛起”這個應用程序。 
要 過濾鍵盤、鼠標和DDE消息,應用程序可以便用下列常量WM_KEYFIRST 和 WM_KEYLAST, WM_MOUSEFIRST 和 WM_MOUSELAST messages, 和 WM_DDE_FIRST 和 WM_DDE_LAST 
消息死鎖
調 用函數SendMessage 的線程向另一個線程發送一條消息,要等待接收消息的窗口過程返回,如果接收消息的線程在 處理消息時放棄了控制,發送消息的線程就不能繼續執行下去,因爲它正等待SendMessage 返回,這種情況就叫做 死鎖。接收消息的線程無須直接地放棄控制,調用下列函數其個的一個就能讓線程放棄控制。 
DialogBox 
DialogBoxIndirect 
DialogBoxIndirectParam 
DialogBoxParam 
GetMessage 
MessageBox 
PeekMessage 
窗口過程可以確定它所接收的 消息是不是另一個線程通過調用函數InSendMessage 發來的。在處理一條消息時調用前面所列出的任一個函數之 前,窗口過程應首先調用InSendMessage ,如果函數返回TRUE ,窗口 過程就必須在調用任何能使線程放棄控制的函數之前調用函數ReplyMessage 。 
使用消息和消息隊列
這節描述如何完成下面的工作 
創建消息環 
檢查消息隊列 
投遞消息 
發送消息 
創建消息環
windows 系統爲每一個線程自動創建消息隊列,如果線程創建了一個或多個窗口,就必須提供從線程消息隊列中檢取消息,並把它們發送至相應窗口過程的消息環。 
因爲windows系統指導向應用程 序中的某個窗口發送消息,線程就必須在啓動它的消息環之前至少要創建—個窗口,絕大多數windows應用程序含有一個創建窗口的線程。一個典型的應用程 序是在函數WinMain 中註冊它主窗口的窗口類。創建和顯示主窗口.然後啓動消息環。 
函數GetMessage 和 DispatchMessage 用來創建消息環,如果應用程序必須從用戶得到字符輸入,那麼在消息環中應包含函數TranslateMessage , TranslateMessage 把 虛鍵消轉換成字符消息。下面的範例說明了一個簡單的windows應用程序的WinMain 函數中的消息環 
HINSTANCE hinst; 
HWND hwndMain; 
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
LPSTR lpszCmdLine, int nCmdShow) 

MSG msg; 
WNDCLASS wc; 
UNREFERENCED_PARAMETER(lpszCmdLine); 
// Register the window class for the main window. 
if (!hPrevInstance) 

wc.style = 0; 
wc.lpfnWndProc = (WNDPROC) WndProc; 
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 (!RegisterClass(&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 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(&msg); 

// Return the exit code to Windows. 
return msg.wParam; 

函數GetMessage,TranslateMessage 以 及DispatchMessage 把MSG 結構的指針當作一個參數。如果有消息,GetMessage 把 它複製到MSG 結構中,如果這個消息是一條虛鍵消息(如WM_KEYDOWN 或WM_SYSKEYDOWN ),TranslateMessage 產 生一個字符消息(WM_CHAR 或WM_SYSCHAR ),並把它放到消息隊列中 去。DispatchMessage 也使用MSG 結構的成員用作窗口過程的參數. 但要等到窗口過程完成處理後才返回。 
如 果某個線程支持加速鍵,那麼它的消息環必須含有函數TranslateAccelerator 。這個函數檢查與線程加 速鍵表中的一個入口相匹配的組合鍵,如果它找到一個匹配值.TranslateAccelerator 就把組合鍵翻譯 成一條WM_COMMAND 消息,並把它發送到窗口過程。 
如果某個線程使用模式對話框,消息環中必須含有函數IsDialogMessage 以 便於對話框能夠接收鍵盤輸入。 
有 關對話框,參見“對話框”。 
下 面的範例說明了一個使用加速鍵的線程的消息環,其中顯示了一個模式對話框。 
如果TranslateAccelerator 或IsDialogMessage 返 回TRUE (指示消息已被處理),就不再調用TranslateMessage 和 DispatchMessage 原因是TranslateAccelerator 或IsDialogMessage 完 成所有對消息的翻譯和發送工作。 
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 == (HWND) NULL || 
!IsDialogMessage(hwndDlgModeless, &msg) && 
!TranslateAccelerator(hwndMain, haccel, 
&msg)) 

TranslateMessage(&msg); 
DispatchMessage(&msg); 


檢消息隊列
有時,應用程序需要在線程 消息環的外面檢查線程消息隊列的內容,例如,如果某個應用程序的窗口過程進行一個較長的繪畫 操作,就可能允許用戶中斷這個操作。除非應用程序在處理鼠標和鍵盤消息的操作過程中不停地檢查消息隊列,否則在操作結束之前就不再會響應用戶的輸入.原因 是線程消息環中的函數DispatchMessage在窗口過程處理完消息之前是不會返回的。 
對於一個較長時間的操作,可使用函數PeekMessage來 檢查消息隊列,PeekMessage與函數GetMessage是很相似的,都 可用來檢查消息隊列中與過濾器標準相匹配的消息,再把這個消息複製到一個MSG結構中。它們之間主要的不同就是GetMessage要 等待隊列中出現一條與過濾器標準相匹配的消息,而PeekMessage 會立即返回,不管隊列中是否有某條消息。 
下面的範例說明了如何使用PeekMessage在 一個長操作期間,檢查消息隊列中的一條單擊鼠標或鍵盤輸入消息。 
HWND hwnd; 
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 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; 



其它的函數如GetQueueStatus和GetInputState也 能用來檢查線程消息隊列中的內容,GetQueueStatus返回一組標誌,用來指明隊列中消息的類型,這是一個最 快的辦法來確定隊列中是否有消息,如果隊列中臺有鼠標或鍵盤消息,GetInputState就返回TRUE, 這兩個函數都能用來確定隊列中是否有需要處理的消息。 
投遞消息
使用函數PostMessage把一條消息投遞到消息隊列中,PostMessage在 線程消息隊列的最後放置消息並立即返回,它不等待線程處理這條消息。函數的參數包括窗口句柄、消息標識相兩個消息參數,windows系統把這些參數複製 到一個MSG結構中,填充結構的time和pt成 員,再把這個結構放到消息隊列中。 
windows 系統用函數PostMessage所帶的窗口句柄來決定哪一個線程消息隊列接收消息.如果句柄是HWND_TOPMOST,windows 系統就把這條消息投遞到所有頂層窗口的線程消息隊列中。 
函數PostThreadMessage可用來向一個指定的線程消息隊列投遞消息,PostThreadMessage與PostMessage也 很相似.只是它的第一個參數是線程標識而不是窗口句柄,可通過調用函數GetCurrentThreadId檢取這個 線程標識。 
函數PostQuitMessage用 來退出消息環,PostQuitMessage向當前正在執行的線程發送WM_QUIT消 息,如果線程消息環接收到WM_QUIT消息,就結束消息環並把控制返回給windows系統。應用程序通常調用PostQuitMessage響 應WM_DESTROY消息, 
用法如下 
case WM_DESTROY: 
// Perform cleanup tasks. 
PostQuitMessage(0); 
break; 
發送消息
函數SendMessage是用來直接向 一個窗口過程發送消息,SendMessage調用一個窗口過程,並等待過程對消息的處理和返回結果。 一條消息可以被髮往系統中的任何一個窗口,而僅要求有一個窗口句柄,windows系統用這個句柄決定哪一個窗口過程應該接收這條消息。 如果窗口過程在處理由另一個線程發來的消息時放棄控制,就會出現消息死鎖(有關消息死鎖,參見 “消息死鎖”)。在處理一個可能是發自另一個線程的消息之前,窗口過程應首先調用函數InSendMessage,如 果這個函數返回TRUE,那麼窗口過程就應在調用任何可以使線程放棄控制的函數之前調用ReplyMessage, 做法如下: 
case WM_USER + 5: 
if (InSendMessage()) 
ReplyMessage(TRUE); 
DialogBox(hInst, "MyDialogBox", hwndMain, (DLGPROC) MyDlgProc); 
break; 
有一些消息可以發給對話框中的控制框,這些控制框消息設置控制框的外觀、特性和內容或是檢取有關 控制框的信息。例如,CB_ADDSTRING消息可以向組合框添加字串,BM_SETCHECK消 息能夠設置複選框或單選按鈕的選擇狀態。 
使 用函數SendDlgItemMessage向一個控制框發送一條消息,要指定控制框的標識,含有這個控制框的對話框 窗口的句柄。下面的範例用在對話框過程中的,把一個字串從組合框的編輯控制框拷到它的列表框,這個例子用SendDlgItemMessage向 組合框發送一條CB_ADDSTRING消息. 
HWND hwndCombo; 
int cTxtLen; 
PSTR pszMem; 
switch (uMsg) 

case WM_COMMAND: 
switch (LOWORD(wParam)) 

case IDD_ADDCBITEM: 
// Get the handle of the combo box and the 
// length of the string in the edit control 
// of the combo box. 
hwndCombo = GetDlgItem(hwndDlg, IDD_COMBO); 
cTxtLen = GetWindowTextLength(hwndCombo); 
// Allocate memory for the string and copy 
// the string into the memory. 
pszMem=(PSTR)VirtualAlloc((LPVOID)NULL,(DWORD)(cTxtLen+1),MEM_COMMIT, PAGE_READWRITE); 
GetWindowText(hwndCombo, pszMem, cTxtLen + 1); 
// Add the string to the list box of the 
// combo box and remove the string from the 
// edit control of the combo box. 
if (*pszMem != NULL) 

SendDlgItemMessage(hwndDlg, IDD_COMBO, CB_ADDSTRING, 0, (DWORD) ((LPSTR) pszMem)); 
SetWindowText(hwndCombo, (LPSTR) NULL); 

// Free the memory and return. 
VirtualFree(pszMem, 0, MEM_RELEASE); 
return TRUE; 
// Process other dialog box commands. 

// Process other dialog box messages. 

消息及消息隊列參考
下列函數函數用於消息和消息隊列 
BroadcastSystemMessage 
DefWindowProc 
DispatchMessage 
GetInputState 
GetMessage 
GetMessageExtraInfo 
GetMessagePos 
GetMessageTime 
GetQueueStatus 
InSendMessage 
PeekMessage 
PostMessage 
PostQuitMessage 
PostThreadMessage 
RegisterWindowMessage 
ReplyMessage 
SendAsyncProc 
SendMessage 
SendMessageCallback 
SendMessageTimeout 
SendNotifyMessage 
SetMessageExtraInfo 
TranslateMessage 
WaitMessage 
Obsolete Functions 
PostAppMessage 
SetMessageQueue 

WM_USER

文章來源:http://blog.csdn.net/yxp200401/article/details/7736122

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章