系統發送消息給窗口過程並傳遞4個參數,windows句柄, 消息標識符, 2個消息參數。系統使用窗體句柄來決定那個窗口過程來接受消息。
消息標識符以常量命名指出消息的含義。當窗口過程接收到消息,使用消息標識符決定如何處理消息。例如、WM_PAINT告訴窗口過程窗體客戶區被改變了需要重繪。
消息參數指定被窗口過程使用的數據和數據的位置。其含義和值取決於消息類型。消息參數可以包含壹個整數, 標誌位,壹個指針等。 當消息不使用消息參數時,他們被設置位NULL。壹個Window窗口過程必須根據消息標識符來決定如何解釋消息參數。
Message Types
This section describes the two types of messages:
· System-Defined Messages
· Application-Defined Messages
System-Defined Messages
當系統和應用程序通訊時,系統post和send系統定義消息。他使用消息來控制應用程序的操作,提供輸入和其他信息讓應用程序處理。應用程序也可以post或者send系統定義消息。
每壹個系統定義消息由壹個唯壹的標識符與壹致的常量以聲明消息的含義。例如 WM_PAINT 要求窗口繪制它的內容。
符號常量指定系統定義消息屬於的類別,常量的前綴指定處理解釋消息的窗體的類型。以下使壹些前綴和他們相關的消息類別。
Prefix Message category
ABM Application desktop toolbar
BM Button control
CB Combo box control
CBEM Extended combo box control
CDM Common dialog box
DBT Device
DL Drag list box
DM Default push button control
DTM Date and time picker control
EM Edit control
HDM Header control
HKM Hot key control
IPM IP address control
LB List box control
LVM List view control
MCM Month calendar control
PBM Progress bar
PGM Pager control
PSM Property sheet
RB Rebar control
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
通用窗體消息覆蓋了很大壹個信息和請求的範圍, 包括鼠標鍵盤消息, 菜單對話框的輸入, 窗體產生與管理, 動態數據交換 (DDE).
Application-Defined Messages
應用程序可以產生自己用的消息或者與其他進程中窗體通訊。如果應用程序產生自己的消息,窗口過程接受並且必須提供合適的處理。
系統保留消息標識符的值在0x0000在0x03ff(WM_USER-1)範圍。這些值被系統定義消息使用。 應用程序不能使用這些值給自己的消息。
private window classes用0x0400(WM_USER)到0x7fff消息標識符
· If your application is marked version 4.0, you can use message-identifier values in the range 0x8000 (WM_APP) through 0xBFFF for private messages.
系統使用RegisterWindowMessage來註冊消息,返回壹個消息標識符範圍在0XC000到0XFFFF,使用這個函數來保證整個系統範圍內是唯壹的
Message Routing
系統有兩個方法將消息傳遞到窗口過程。Post壹個消息到先進先出的消息隊列。系統定義的臨時內存對象。和直接 send消息到窗口過程。
被發送到消息隊列的消息稱做入隊消息,主要是由鼠標鍵盤輸入,例如 WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_KEYDOWN, and WM_CHAR messages。還包括定時器, 刷新, 退出: WM_TIMER, WM_PAINT, and WM_QUIT。其他直接發送到窗口過程的消息被稱為 非入隊消息。
Queued Messages
系統可以顯示任何數量的窗體同壹時間。為了傳遞鼠標鍵盤消息到合適的窗口,系統使用消息隊列。
系統維護壹個系統消息隊列和每壹個GUI線程的消息隊列,為避免給non-GUI現成創建消息隊列,所有線程產生時並沒有消息隊列。僅當線程第壹次調用GDI函數時,系統給線程創建壹個消息隊列。只要用戶移動鼠標,點擊鼠標,敲鍵,驅動程序將其轉換為消息將他們放在系統消息隊列中。系統將他們從系統消息隊列中移走,檢查他們的目標窗口,然後將他們發送到創建目標窗口的線程的消息隊列。線程消息隊列接收由這個線程創建的所有窗口的鼠標鍵盤消息。線程刪除消息系統調用窗口過程進行處理。
WM_PAINT是壹個例外,系統總是將消息Post在消息隊列的末尾。這樣保證窗口以先進先出的順序接受消息。然而, 僅當沒有其他消息時WM_PAINT才被傳遞窗口過程。同壹個窗口的多個 WM_PAINT被合並成壹個 WM_PAINT 消息, 合並所有的無效區域到壹個無效區域。合並WM_PAIN減少了刷新窗口的次數。
系統通過填充MSG結構並將它復制到消息隊列來發送消息到線程隊列。MSG結構包括:窗口句柄,消息標識符,兩個消息參數。 消息被posted的時間, 和鼠標的位置。線程可以使用PostMessage和PostThreadMessage來給發送消息到自己消息隊列或者另壹個線成的消息隊列。
應用程序可以使用GetMessage從消息隊列刪除消息。可以使用 PeekMessage來檢查壹個消息而不刪除它。 這個函數將消息隊列的消息填充到MSG結構。
在從消息隊列刪除了壹個消息,應用程序可以使用DispatchMessage使系統將消息發送到窗口過程來處理。DispatchMessage擁有壹個指向由GetMessage或者PeekMessage填充的MSG結構的指針,傳遞窗口句柄,消息標識符,消息參數給窗口過程。但它並不傳遞消息發送的時間和鼠標的位置,應用程序可以通過GetMessageTime和GetMessagePos來得到這些信息。
線程可以使用WaitMessage將控制交給其他線程當消息隊列中沒有他的消息隊烈時,這個函數掛起線程,並不返回,直到新的消息放置於消息隊列中。
妳可以調用SetMessageExtraInfo函數來關聯壹個值到當前線程的消息隊列。調用GetMessageExtraInfo來得到這個與最後壹次通過GetMessage或者PeekMessaage獲得的消息關聯得值。
Nonqueued Messages
非入隊消息即直接發送到窗口過程的消息,繞過系統隊列和線程消息隊列。系統發送非入隊消息通知壹個窗口事件,例如,當用戶激活壹個新的應用程序窗口,系統發送WM_ACTIVATE, WM_SETFOCUS, and WM_SETCURSOR。這些消息通知窗口它被激活了,鍵盤輸入被直接傳遞到窗口,鼠標在當前窗口內移動。 非入隊消息也可以由當應用程序調用系統函數產生。例如,當程序調用SetWindowPos系統發送WM_WINDOWPOSCHANGED消息。
壹些函數也發送非入隊消息如 BroadcastSystemMessage, BroadcastSystemMessageEx, SendMessage, SendMessageTimeout, and SendNotifyMessage.
Message Handling
應用程序必須移除和處理被post到消息隊列的消息。單線程應用程序通常在WinMain使用消息循環來移除和分發消息到何時窗口過程來處理。多線程應用程序可以在每壹個創建窗口的線程中中包含消息循環。
Message Loop
A simple message loop consists of one function call to each of these three functions: GetMessage, TranslateMessage, and DispatchMessage. Note that if there is an error, GetMessage returns -1 -- thus the need for the special testing.
Show Example
MSG msg;
BOOL bRet;
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
GetMessage 函數從消息隊列獲得壹個消息並將它復制到MSG結構。他返回壹個非0值,除非遇到WM_QUIT消息。否則它返回0然後結束循環。In a single-threaded application, ending the message loop is often the first step in closing the application. 應用程序可以使用PostQuitMessage來結束自己的消息循環。通常在主窗口的WM_DESTROY消息中調用。
如果妳將壹個窗口句柄作為第二個參數傳入GetMessage,那麽只有指定窗口的的消息可以從隊列中獲得。GetMessage也可以從消息隊列中過濾消息只接受消息隊列中落在範圍內的消息。詳細見消息過濾。 壹個線程循環必須包括TranslateMessage如果線程接受鍵盤的字符輸入。每壹次用戶按鍵系統產生虛擬鍵消息,壹個虛擬鍵消息包含虛擬鍵用來標誌那個鍵被按下,並不是他的字符值,要獲得這個值消息循環必須調用TranslateMessage,用於將虛擬鍵轉換為字符消息WM_CHAR然後將它放回應用程序消息隊列。通過將它轉發到窗口過程,字符消息被刪除。
DispatchMessage 函數分發消息到MSG結構中的窗口句柄關聯的窗口過程。如果窗口句柄是HWND_TOPMOST,DispatchMessage分發消息到系統中的所有的top-level窗口的窗口過程。如果句柄是NULL,DispatchMessage不做任何事。
應用程序得主線程在初始化,創建至少壹個窗口後啟動它的消息循環,壹旦啟動消息循環持續從線程隊列中獲得消息,然後分發他們到合適的窗口。消息循環在通過GetMessage得到WM_QUIT並將他從隊列中刪除後結束。
壹個消息都列僅需要壹個消息循環, 即使程序包含很多窗口。DispatchMessage 總是分發消息到合適的窗口,這是因為MSG結構包含消息所屬的窗口的句柄。
妳可以用各種方式修改消息循環。例如,從消息隊列獲得消息消息但不把他們分發到窗口中去。當應用程序發送壹個消息但不指定窗口時是有用的。妳可以用GetMessage獲得壹個特定的消息,而保留其他消息在消息隊列。當妳需要改變先進先出的順序時是有用的。
應用程序使用加速鍵必須將鍵盤消息轉換為WM_COMMAND消息。所以消息循環必須包括TranslateAccelerator函數。詳細信息參見加速鍵。
如果線程使用非模態對話框,消息循環必須包括 IsDialogMessage 以使非模態對話框獲得鍵盤輸入。
Window Procedure
窗口過程是壹個用於處理所有發送到這個窗口的消息的函數。任何壹個窗口類都有壹個窗口過程。同壹個類的窗口使用同樣的窗口過程來響應消息。
系統發送消息給窗口過程將消息數據作為參數傳遞給他,窗口過程使用參數產生合適行為。
壹個窗口過程通常不忽略消息,如果他不處理,它會將消息傳回到執行默認的處理。窗口過程通過調用DefWindowProc來做這個處理。窗口過程必須return壹個值作為它的消息處理結果。大多數窗口只處理小部分消息和將其他的通過DefWindowProc傳遞給系統做默認的處理。
因為窗口過程是同壹個類的窗口***享的,它可以為不同的窗口處理消息。通過檢查消息中的窗口句柄來找到被消息影響的窗口。詳細信息請看Window Procedures。
Message Filtering
應用程序可以從消息隊列選擇特定的消息。使用GetMessage或者PeekMessage並指定壹個消息過濾器。這個過濾器是壹個消息標識符的範圍或者是壹個窗體句柄,或者兩者同時指定。GetMessage和PeekMessage使用過濾器來選擇從消息隊列中獲得那些消息。當應用程序要查找壹個後入消息隊列的消息是很有用。
壹個應用程序過濾消息時必須保證符合過濾條件的消息能被發送。例如應用程序在窗口中過濾WM_CHAR並不能得到鍵盤輸入,GetMessage並不返回。這將掛起應用程序。
Posting and Sending Messages
應用程序可以post和send消息,通過將消息復制到消息隊列即post消息,send消息將消息數據作為參數直接傳遞到窗口過程。
可以使用PostMessage來post消息,SendMessage,BroadcastSystemMessage, SendMessageCallback, SendMessageTimeout, SendNotifyMessage, or SendDlgItemMessage來send消息。
Posting Messages
應用程序post消息通知指定窗體執行任務。PostMessage可以創建MSG結構並將它Copy到消息隊列。消息循環最終捕獲消息並分發到合適的窗口過程。
給PostMessage傳遞壹個NULL句柄不指定哪壹個窗口,這個消息就被發送到當前線程消息隊列,應用程序必須在消息處理中處理這個消息。這是為整個應用程序發送消息的壹個方法。
偶爾妳可以使用HWND_TOPMOST 這個參數作為句柄參數向所有的top-level窗口發送消息。
當消息隊列滿的時候PostMessage並不發送消息,應用程序需要檢查PostMessage函數的返回值來確定消息是否被發送,或者沒有需要重發。
Sending Messages
通過Send消息來通知窗口過程立即執行任務。SendMessage將消息發送給指定窗口的窗口過程。函數將等待窗口過程處理完才返回壹個消息結果。父窗口和子窗口通常使用Send消息來互相通訊。例如,壹個父窗口擁有以壹個文本框作為它的子窗口,它可以通過發送消息到子窗口來給文本框設置文字。子窗口也可將文字被用戶改變的消息發送給父窗口。
SendMessageCallback也將消息發送給指定窗口的窗口過程,但是他立即返回。在窗口過程處理完消息後,系統調用指定的回調函數,回調函數的詳細資料參見SendAsyncProc
偶爾,妳可以發送消息系統中到所有的top-level窗口,例如,應用程序改變了系統時間。它必須以HWND_TOPMOST作為句柄參數發送壹個WM_TIMECHANGE 消息通知所有的top-level窗口,妳也可以將lpdwRecipients 指定為BSM_APPLICATIONS 用BroadcastSystemMessage函數向所有應用程序廣播。
可以使用InSendMessage或者InSendMessageEx函數,窗口過程可以判斷它處理的消息是否是由其他線程調用SendMessage發送過來的。This capability is useful when message processing depends on the origin of the message.
Message Deadlocks
壹個線程可以調用SendMessage想其他線程發送消息,這個線程不能繼續執行直到獲得消息得窗口過程返回。如果接受消息的線程處理消息時yields控制,發送線程的消息將永遠得不到執行,因為他在等待SendMessage返回。如果接受線程和發送線成語同壹個消息隊列聯系起來,它可能導致消息死鎖。
Note that the receiving thread need not yield control explicitly; calling any of the following functions can cause a thread to yield control implicitly.
接受線程不需要明確yield控制,下面任何壹個函數回導致壹個線程明確yield控制。
· DialogBox
· DialogBoxIndirect
· DialogBoxIndirectParam
· DialogBoxParam
· GetMessage
· MessageBox
· PeekMessage
· SendMessage
為了避免潛在的死鎖,可以使用SendNotifyMessage 或者 SendMessageTimeout,否則窗口過程,將用InSendMessage或者InSendMessageEx判斷消息是否由另壹個線程發送過來。當調用前面任何壹個函數窗口過程將首先調用InSendMessage或者InSendMessagEx,如果函數返回true窗口過程必須在引起線程yeild控制前調用ReplyMessage 。
Broadcasting Messages
每壹個消息包括消息標識符和兩個參數,wParam和lParam,消息標識符是唯壹的代表這個消息的含義。參數提供與消息相關的額外的信息,但是wParam參數通常是壹個類型值提供更多的消息信息。
消息廣播是簡單的將消息發送到系統中的多個接收者。使用BroadcastSystemMessage函數來廣播消息,妳必須指定壹個或者多個接收者類型,這些類型可以是applications, installable drivers, network drivers, and system-level device drivers。系統將消息發送給指定類型的所有成員。
系統廣播消息來響應系統設備驅動程序或者組件的變化。驅動程序或相關組件廣播消息給應用程序和其他組件以通知他們這些變化。例如,負責磁盤響應的組件廣播消息只要軟盤驅動程序發現媒體的變化,如當用戶將磁盤插入驅動器。
系統按壹下順序廣播消息給接收者:系統級的設備驅動程序,網絡驅動程序,installable drivers,和應用程序。意味著如果系統級設備驅動程序作為接收者總是第壹個有機會來響應消息。在接受者類型中,沒有壹個驅動程序能保證在其他驅動程序前接受壹個消息。即壹個給特定驅動程序的消息必須有壹個全局唯壹的標誌使其他不關心這個消息的驅動程序不處理它。
妳也可以廣播消息給所有頂層窗口通過在SendMessage等函數中指定HWND_BROADCAST。
應用程序通過頂層窗口的窗口過程來接收消息。消息不發送到子窗口。服務可以接收消息通過窗口過程或者他們的服務控制函數。
Query Messages
妳可以創建自定義的消息使用它們來調整妳的應用程序和其他組件之間的行為。這個非常有用如果妳已創建妳自己的installable drivers和系統機設備驅動程序。妳的驅動程序和使用這個驅動程序的應用程序可以通過自定義消息互相傳遞信息。
To poll recipients for permission to carry out a given action, use a query message.妳可以通過在dwFlags參數中設置BSF_QUERY調用BroadcastSystemMessage。每壹個query message的接收者必須返回TRUE來將消息發送到下壹個接收者。如果任何壹個接收者返回BROADCAST_QUERY_DENY,廣播立即停止函數返回0。
Windows 95/98/Me: 妳可以創建廣播和處理消息的installable drivers。壹個installable drivers是壹個導出DriverProc函數的dll。驅動程序通過它的DriverProc來接收消息。Installable drivers典型的用來支持多媒體設備,例如sound boards,也可以用於其他設備和目的。
Windows 95/98/Me: 網絡驅動程序是給應用程序提供以下支持的dlls。系統級設備驅動程序是系統特定的提供直接訪問和管理計算機硬件的可執行組件。這些組件如何處理系統消息超出了這篇文章的範圍。
程序出錯,幫忙看下, 很簡單的。謝謝咯