日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > windows >内容正文

windows

Windows消息机制要点

發(fā)布時(shí)間:2025/5/22 windows 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Windows消息机制要点 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1. 窗口過程
??? 每個(gè)窗口會(huì)有一個(gè)稱為窗口過程的回調(diào)函數(shù)(WndProc),它帶有四個(gè)參數(shù),分別為:窗口句柄(Window Handle),消息ID(Message ID),和兩個(gè)消息參數(shù)(wParam, lParam), 當(dāng)窗口收到消息時(shí)系統(tǒng)就會(huì)調(diào)用此窗口過程來處理消息。(所以叫回調(diào)函數(shù))

2 消息類型
1) 系統(tǒng)定義消息(System-Defined Messages)

在SDK中事先定義好的消息,非用戶定義的,其范圍在[0x0000, 0x03ff]之間, 可以分為以下三類:
1> 窗口消息(Windows Message)
與窗口的內(nèi)部運(yùn)作有關(guān),如創(chuàng)建窗口,繪制窗口,銷毀窗口等??梢允且话愕拇翱?#xff0c;也可以是Dialog,控件等。
如:WM_CREATE, WM_PAINT, WM_MOUSEMOVE, WM_CTLCOLOR, WM_HSCROLL...
2> 命令消息(Command Message)
與處理用戶請(qǐng)求有關(guān), 如單擊菜單項(xiàng)或工具欄或控件時(shí), 就會(huì)產(chǎn)生命令消息。
WM_COMMAND, LOWORD(wParam)表示菜單項(xiàng),工具欄按鈕或控件的ID。如果是控件, HIWORD(wParam)表示控件消息類型
3> 控件通知(Notify Message)
控件通知消息, 這是最靈活的消息格式, 其Message, wParam, lParam分別為:WM_NOTIFY, 控件ID,指向NMHDR的指針。NMHDR包含控件通知的內(nèi)容, 可以任意擴(kuò)展。
2) 程序定義消息(Application-Defined Messages)
用戶自定義的消息, 對(duì)于其范圍有如下規(guī)定:
WM_USER: 0x0400-0x7FFF????? (ex. WM_USER+10)
WM_APP(winver> 4.0): 0x8000-0xBFFF (ex.WM_APP+4)
RegisterWindowMessage: 0xC000-0xFFFF

3 消息隊(duì)列(Message Queues)
Windows中有兩種類型的消息隊(duì)列
1) 系統(tǒng)消息隊(duì)列(System Message Queue)
這是一個(gè)系統(tǒng)唯一的Queue,設(shè)備驅(qū)動(dòng)(mouse, keyboard)會(huì)把操作輸入轉(zhuǎn)化成消息存在系統(tǒng)隊(duì)列中,然后系統(tǒng)會(huì)把此消息放到目標(biāo)窗口所在的線程的消息隊(duì)列(thread-specific message queue)中等待處理
2) 線程消息隊(duì)列(Thread-specific Message Queue)
每一個(gè)GUI線程都會(huì)維護(hù)這樣一個(gè)線程消息隊(duì)列。(這個(gè)隊(duì)列只有在線程調(diào)用GDI函數(shù)時(shí)才會(huì)創(chuàng)建,默認(rèn)不創(chuàng)建)。然后線程消息隊(duì)列中的消息會(huì)被送到相應(yīng)的窗口過程(WndProc)處理.
注意: 線程消息隊(duì)列中WM_PAINT,WM_TIMER只有在Queue中沒有其他消息的時(shí)候才會(huì)被處理,WM_PAINT消息還會(huì)被合并以提高效率。其他所有消息以先進(jìn)先出(FIFO)的方式被處理。

4 隊(duì)列消息(Queued Messages)和非隊(duì)列消息(Non-Queued Messages)
1)隊(duì)列消息(Queued Messages)
消息會(huì)先保存在消息隊(duì)列中,消息循環(huán)會(huì)從此隊(duì)列中取消息并分發(fā)到各窗口處理
如鼠標(biāo),鍵盤消息。
2) 非隊(duì)列消息(NonQueued Messages)
消息會(huì)繞過系統(tǒng)消息隊(duì)列和線程消息隊(duì)列直接發(fā)送到窗口過程被處理
如: WM_ACTIVATE, WM_SETFOCUS, WM_SETCURSOR, WM_WINDOWPOSCHANGED
注意: postMessage發(fā)送的消息是隊(duì)列消息,它會(huì)把消息Post到消息隊(duì)列中; SendMessage發(fā)送的消息是非隊(duì)列消息, 被直接送到窗口過程處理

5 PostMessage(PostThreadMessage), SendMessage
PostMessage:把消息放到指定窗口所在的線程消息隊(duì)列中后立即返回。 PostThreadMessage:把消息放到指定線程的消息隊(duì)列中后立即返回。
SendMessage:直接把消息送到窗口過程處理, 處理完了才返回。

6 GetMessage, PeekMessage
PeekMessage會(huì)立即返回??? 可以保留消息
GetMessage在有消息時(shí)返回? 會(huì)刪除消息

7 TranslateMessage, TranslateAccelerator
TranslateMessage: 把一個(gè)virtual-key消息轉(zhuǎn)化成字符消息(character message),并放到當(dāng)前線程的消息隊(duì)列中,消息循環(huán)下一次取出處理。
TranslateAccelerator: 將快捷鍵對(duì)應(yīng)到相應(yīng)的菜單命令。它會(huì)把WM_KEYDOWN 或 WM_SYSKEYDOWN轉(zhuǎn)化成快捷鍵表中相應(yīng)的WM_COMMAND 或WM_SYSCOMMAND消息, 然后把轉(zhuǎn)化后的 WM_COMMAND或WM_SYSCOMMAND直接發(fā)送到窗口過程處理, 處理完后才會(huì)返回。

8(消息死鎖( Message Deadlocks)
假設(shè)有線程A和B, 現(xiàn)在有以下下步驟
1) 線程A SendMessage給線程B, A等待消息在線程B中處理后返回
2) 線程B收到了線程A發(fā)來的消息,并進(jìn)行處理, 在處理過程中,B也向線程A SendMessgae,然后等待從A返回。
因?yàn)榇藭r(shí), 線程A正等待從線程B返回, 無法處理B發(fā)來的消息, 從而導(dǎo)致了線程A,B相互等待, 形成死鎖。多個(gè)線程也可以形成環(huán)形死鎖。
可以使用 SendNotifyMessage或SendMessageTimeout來避免出現(xiàn)死鎖。

9 BroadcastSystemMessage
我們一般所接觸到的消息都是發(fā)送給窗口的, 其實(shí), 消息的接收者可以是多種多樣的,它可以是應(yīng)用程序(applications), 可安裝驅(qū)動(dòng)(installable drivers), 網(wǎng)絡(luò)設(shè)備(network drivers), 系統(tǒng)級(jí)設(shè)備驅(qū)動(dòng)(system-level device drivers)等,
BroadcastSystemMessage這個(gè)API可以對(duì)以上系統(tǒng)組件發(fā)送消息。

?? ?? 一、引言
隨著Windows操作系統(tǒng)的不斷推廣,眾多軟件開發(fā)包都提供有開發(fā)基于Windows平臺(tái)應(yīng)用軟件的功能。雖然這些開發(fā)包不盡相同,流行的有Visual C++、Visual Basic、Delphi、C++ Builder 等多種,但由這些不同語言開發(fā)的軟件有一點(diǎn)卻是相同的--都是運(yùn)行于Windows 操作平臺(tái),都必須接受Windows 的運(yùn)行機(jī)制。作為Windows 操作系統(tǒng)靈魂的消息機(jī)制也就必然為眾多用不同語言開發(fā)的Windows操作系統(tǒng)下運(yùn)行的應(yīng)用程序所接受。因此,要編寫深入的Windows程序,就必須對(duì) Windows的運(yùn)行機(jī)制有很好的認(rèn)識(shí)和理解。本文下面將對(duì)Windows操作系統(tǒng)下的消息運(yùn)行機(jī)制做較為深入的剖析。
二、Windows事件驅(qū)動(dòng)機(jī)制
我們當(dāng)中不少使用VC、Delphi等作為開發(fā)語言的程序員是一步步從DOS下的Basic、C++中走過來的,而且大多在剛開始學(xué)習(xí)編程時(shí)也是先從 DOS下的編程環(huán)境入手的,因此在習(xí)慣了DOS下的過程驅(qū)動(dòng)形式的順序程序設(shè)計(jì)方法后,往往在向Windows下的開發(fā)環(huán)境轉(zhuǎn)型的過程中會(huì)對(duì) Windows所采取的事件驅(qū)動(dòng)方式感到無法適應(yīng)。因?yàn)镈OS和Windows這兩種操作系統(tǒng)的運(yùn)行機(jī)制是截然不同的,DOS下的任何程序都是使用順序的、過程驅(qū)動(dòng)的程序設(shè)計(jì)方法。這種程序都有一個(gè)明顯的開始、明顯的過程以及一個(gè)明顯的結(jié)束,因此通過程序就能直接控制程序事件或過程的全部順序。即使是在處理異常時(shí),處理過程也仍然是順序的、過程驅(qū)動(dòng)的結(jié)構(gòu)。而Windows的驅(qū)動(dòng)方式則是事件驅(qū)動(dòng)的,即程序的流程不是由事件的順序來控制,而是由事件的發(fā)生來控制,所有的事件是無序的,所為一個(gè)程序員,在編寫程序時(shí),并不知道用戶會(huì)先按下哪個(gè)按紐,也就不知道程序先觸發(fā)哪個(gè)消息。因此我們的主要任務(wù)就是對(duì)正在開發(fā)的應(yīng)用程序要發(fā)出的或要接收的消息進(jìn)行排序和管理。事件驅(qū)動(dòng)程序設(shè)計(jì)是密切圍繞消息的產(chǎn)生與處理而展開的,一條消息是關(guān)于發(fā)生的事件的消息。
三、Windows的消息循環(huán)
Windows操作系統(tǒng)為每一個(gè)正在運(yùn)行的應(yīng)用程序保持有一個(gè)消息隊(duì)列。當(dāng)有事件發(fā)生后,Windows并不是將這個(gè)激發(fā)事件直接送給應(yīng)用程序,而是先將其翻譯成一個(gè)Windows消息,然后再把這個(gè)消息加入到這個(gè)應(yīng)用程序的消息隊(duì)列中去。應(yīng)用程序需要通過消息循環(huán)來接收這些消息。在MFC中使用了對(duì) WinAPI進(jìn)行了很好封裝的類庫,雖然可以為編程提供一個(gè)面向?qū)ο蟮慕缑?#xff0c;使Windows程序員能夠以面象對(duì)象的方式進(jìn)行編程,把那些進(jìn)行SDK編程時(shí)最繁瑣的部分提供給程序員,使之專注于功能的實(shí)現(xiàn),但是由于引入了很好的封裝特性,使我們不能直接操縱部分核心代碼。對(duì)于消息的循環(huán)和接收也只是通過類似于下面的消息映射予以很簡(jiǎn)單的表示:
BEGIN_MESSAGE_MAP(CTEMMSView, CFormView)
//{ { AFX_MSG_MAP(CTEMMSView)
ON_WM_LBUTTONDOWN()
ON_COMMAND(ID_OPENDATA, OnOpenData)
ON_WM_TIMER()
ON_WM_PAINT()
//} } AFX_MSG_MAP
END_MESSAGE_MAP()
雖然上述消息映射在編程過程中處理消息非常簡(jiǎn)練方便,但顯然是難于理解消息是如何參與循環(huán)和分發(fā)的。因此有必要通過SDK(Software Developers Kit,軟件開發(fā)工具箱)代碼深入到被MFC封裝的Windows編程的核心中來研究其具體是如何工作的。在SDK編程中,一般是在Windows應(yīng)用程序的入口點(diǎn)WinMain函數(shù)中添加處理消息循環(huán)的代碼以檢索Windows送來的消息,然后WinMain再把這些消息分配給相應(yīng)的窗口函數(shù)并處理它們:
……
MSG msg; //定義消息名
while (GetMessage (& msg, NULL, 0, 0))
{
TranslateMessage (& msg) ; //翻譯消息
DispatchMessage (& msg) ; //撤去消息
}
return msg.wParam ;
上述幾句雖然簡(jiǎn)單但卻是所有Windows程序的關(guān)鍵代碼,擔(dān)負(fù)著獲取、解釋和分發(fā)消息的任務(wù),下面就重點(diǎn)對(duì)其功能和作用進(jìn)行分析:
MSG結(jié)構(gòu)在頭文件中定義如下:
typedef struct tagMSG
{
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG, *PMSG;
其數(shù)據(jù)成員的具體意義如下:
hwnd:消息將要發(fā)送到的那個(gè)窗口的句柄,用這個(gè)參數(shù)可以決定讓哪個(gè)窗口接收消息。
message:消息號(hào),它唯一標(biāo)識(shí)了一種消息類型。每種消息類型都在Windows文件進(jìn)行了預(yù)定義。
wParam:一個(gè)32位的消息參數(shù),這個(gè)值的確切意義取決于消息本身。
lParam:同上。
time:消息放入消息隊(duì)列中的時(shí)間,在這個(gè)域中寫入的并非當(dāng)時(shí)日期,而是從Windows啟動(dòng)后所測(cè)量的時(shí)間值。Windows用
這個(gè)域來使用消息保持正確的順序。
pt:消息放入消息隊(duì)列時(shí)的鼠標(biāo)坐標(biāo)。
消息循環(huán)以GetMessage調(diào)用開始,它從消息隊(duì)列中取出一個(gè)消息。該函數(shù)的四個(gè)參數(shù)可以有控制地獲取消息,第一個(gè)參數(shù)指定要接收消息的MSG結(jié)構(gòu)的地址,第二個(gè)參數(shù)表示窗口句柄,一般將其設(shè)置為空,表示要獲取該應(yīng)用程序創(chuàng)建的所有窗口的消息;第三、四參數(shù)用于指定消息范圍。后面三個(gè)參數(shù)被設(shè)置為默認(rèn)值,用于接收發(fā)送到屬于這個(gè)應(yīng)用程序的任何一個(gè)窗口的所有消息。在接收到除WM_QUIT之外的任何一個(gè)消息后,GetMessage()返回 TRUE;如果GetMessage收到一個(gè)WM_QUIT消息,則返回FALSE以退出消息循環(huán),終止程序運(yùn)行。因此,在接收到WM_QUIT之前,帶有GetMessage()的消息循環(huán)可以一直循環(huán)下去。當(dāng)除WM_QUIT的消息用GetMessage讀入后,首先要經(jīng)過函數(shù) TranslateMessage()對(duì)其進(jìn)行解釋,但對(duì)大多數(shù)消息來說并不起什么作用。這里起關(guān)鍵作用的是DispatchMessage()函數(shù),把由GetMessage獲取的Windows消息傳送給在MSG結(jié)構(gòu)中為窗口所指定的窗口過程。在消息處理函數(shù)處理完消息之后,代碼又循環(huán)到開始去接收另一個(gè)消息,這樣就完成了一個(gè)完整的消息循環(huán)。
由于Windows操作系統(tǒng)是一種非剝奪式多任務(wù)操作系統(tǒng)。只有在應(yīng)用程序主動(dòng)交出CPU控制權(quán)后,Windows才能把控制權(quán)交給其他應(yīng)用程序。在消息循環(huán)中,一定要有能交出控制的系統(tǒng)函數(shù)才能實(shí)現(xiàn)協(xié)同式多任務(wù)操作。能完成該功能的只有GetMessage、PeekMessage和 WaitMessage這三個(gè)函數(shù),如果在應(yīng)用程序中長(zhǎng)期不去調(diào)用這三個(gè)函數(shù)之一其他任務(wù)則無法執(zhí)行。GetMessage函數(shù)在找不到等待應(yīng)用程序處理的消息時(shí),會(huì)自動(dòng)交出控制權(quán),由Windows把CPU的控制權(quán)交給其他等待獲取控制權(quán)的應(yīng)用程序。由于任何Windows應(yīng)用程序都含有一個(gè)消息循環(huán),這種隱式交出控制權(quán)的方式可以保證合并各個(gè)應(yīng)用程序共享控制權(quán)。一旦發(fā)往該應(yīng)用程序的消息到達(dá)應(yīng)用程序隊(duì)列,即開始執(zhí)行GetMessage語句的下一條語句。使用GetMessage函數(shù)的消息循環(huán)在消息隊(duì)列中沒有消息時(shí)將等待,如果需要,可以利用這段時(shí)間進(jìn)行I/O端口操作等耗時(shí)操作,不過需要在消息循環(huán)中使用PeekMessage函數(shù)來代替GetMessage。使用PeekMessage的方法同GetMessage類似,下面是一段使用 PeekMessage函數(shù)的消息循環(huán)的典型例子:
MSG msg;
BOOL bDone=FALSE;
do{
if(PeekMessage(& msg,NULL,0,0,PM_REMOVE)){
if(msg.message==WM_QUIT)
bDone=TRUE;
else{
TranslateMessage(& msg);
DispatchMessage(& msg);
}
}
//無消息處理,進(jìn)行長(zhǎng)時(shí)間操作
else{
……//長(zhǎng)時(shí)間操作
}
} while(!bDone)
……
無論應(yīng)用程序消息隊(duì)列中是否有消息,PeekMessage函數(shù)都立即返回,如果希望等待新消息入隊(duì),可以利用無返回值的函數(shù)WaitMessage配合PeekMessage進(jìn)行消息循環(huán)。
四、對(duì)Windowds消息的處理
窗口過程處理消息通常以switch語句開始,對(duì)于它要處理的每一條消息ID都跟有一條case語句,這在功能上同MFC的消息映射有些類似:
switch(uMsgId)
{
case WM_TIMER:
//對(duì)WM_TIMER定時(shí)器消息的處理過程
return 0;
case WM_LBUTTONDOWN:
//對(duì)WM_ LBUTTONDOWN鼠標(biāo)左鍵單擊消息的處理過程
ruturn 0;
……
default:
//其他消息由這個(gè)默認(rèn)處理函數(shù)來處理
return DefWindowProc(hwnd,uMsgId,wParam,lParam);
}
在處理完消息后必須返回0,這很重要,否則Windows將要不停地重試下去。對(duì)于那些在程序中不準(zhǔn)備處理的消息,窗口過程會(huì)把它們都扔給 DefWindowProc進(jìn)行缺省處理,而且還要返回那個(gè)函數(shù)的返回值。在消息傳遞層次中,可以認(rèn)為DefWindowProc函數(shù)是最頂層的函數(shù)。該函數(shù)發(fā)出WM_SYSCOMMAND消息,由系統(tǒng)執(zhí)行Windows環(huán)境中多數(shù)窗口所公用的各種通用操作,如更新窗口的正文標(biāo)題等等。在MFC下可以用下述部分代碼實(shí)現(xiàn)與上述SDK代碼相同的功能:
BEGIN_MESSAGE_MAP(CTEMMSView, CFormView)
//{ { AFX_MSG_MAP(CTEMMSView)
ON_WM_LBUTTONDOWN()
ON_WM_TIMER()
//} } AFX_MSG_MAP
END_MESSAGE_MAP()
小結(jié):Windows環(huán)境提供有非常豐富的系統(tǒng)資源,在這個(gè)基礎(chǔ)上可以編制出能滿足各種各樣目標(biāo)功能的應(yīng)用系統(tǒng)。要深入Windows編程就必須首先對(duì)Windows系統(tǒng)的運(yùn)行機(jī)理有很好的認(rèn)識(shí),本文僅針對(duì)Windows的一種重要運(yùn)行機(jī)制--消息機(jī)制作了較深入的剖析和闡述。對(duì)培養(yǎng)在Windows 下的編程思想有一定的幫助。對(duì)某些相關(guān)問題的詳細(xì)論述可以參考MSDN在線幫助的" SDK Reference" 部分。

轉(zhuǎn)載于:https://www.cnblogs.com/xiongyingfeixiang/archive/2011/12/08/2280283.html

總結(jié)

以上是生活随笔為你收集整理的Windows消息机制要点的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。