1、在桌面右鍵彈出菜單,然后點(diǎn)擊個(gè)性化;
創(chuàng)新互聯(lián)長(zhǎng)期為近1000家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為冊(cè)亨企業(yè)提供專業(yè)的成都網(wǎng)站制作、成都做網(wǎng)站,冊(cè)亨網(wǎng)站改版等技術(shù)服務(wù)。擁有十余年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開發(fā)。
2、點(diǎn)擊主頁(yè);
3、點(diǎn)擊系統(tǒng);
4、找到通知和操作一欄,把通知關(guān)閉即可。
拓展資料
Windows 10是美國(guó)微軟公司研發(fā)的跨平臺(tái)及設(shè)備應(yīng)用的操作系統(tǒng)。是微軟發(fā)布的最后一個(gè)獨(dú)立Windows版本。
事件發(fā)生的時(shí)候你可以選擇不讓它傳送消息,同樣你可以傳送一個(gè)消息但是可以不用觸發(fā)一個(gè)事件。
答:消息系統(tǒng):硬件系統(tǒng)、系統(tǒng)軟件、應(yīng)用軟件
window的消息:標(biāo)準(zhǔn)windows消息、控制消息、命令消息。
①標(biāo)準(zhǔn)Windows消息的特點(diǎn):都以“WM_”為前綴。如:WM_KEYDOWN:鍵盤被按下、WM_KEYUP:鍵盤彈起等。
②控件消息是由控件或子窗口產(chǎn)生,并傳送給父窗口的WM_COMMAND消息。控件消息沒有默認(rèn)的消息處理函數(shù),在使用ClassWizard添加消息處理函數(shù)時(shí),系統(tǒng)會(huì)自動(dòng)提供一個(gè)消息處理函數(shù)聲明。
③命令消息來(lái)自用戶界面,是用戶自定義的消息。命令消息也沒有默認(rèn)的消息處理函數(shù),可以用ClassWizard添加消息處理函數(shù)聲明和定義框架。
win10自動(dòng)彈窗。
(win10如何解決自動(dòng)彈窗。
說(shuō)到彈窗,老毛桃討厭!每次打開win10系統(tǒng),不久彈窗滿天飛,經(jīng)我許可嗎?自己的電腦被弄得煙霧繚繞!呼呼~別生氣,忍一時(shí)風(fēng)平浪靜,退一步海闊天空。但話說(shuō)回來(lái),這個(gè)廣告不能有價(jià)值嗎。
既然遇到了彈窗廣告樣的壞心事,老毛桃只能想盡一切辦法解決問題。
首先,我們應(yīng)該知道,計(jì)算機(jī)彈出各種彈出窗口的原因必須由程序操作。要想永久刪除這些彈窗廣告,我們只需要定位這些程序,一舉刪除它們。這時(shí),我們的第一步就完成了!。
好戲還在后面!刪除程序后,我們?nèi)匀恍枰袛嗨暮舐贰T鯓硬僮???jiǎn)單來(lái)說(shuō),就是建立同名文件,設(shè)置為拒絕讀取。當(dāng)有彈出廣告的軟件想要操作這個(gè)程序時(shí),它會(huì)發(fā)現(xiàn)它根本不能打開,它不能讀取和寫入數(shù)據(jù)或刪除,所以彈出廣告不能彈出!。
具體怎么操作。
方法一:對(duì)于容易定位的彈窗程序第一步:右鍵單擊桌面下方的任務(wù)欄,選擇任務(wù)管理器。
第二步:找到對(duì)應(yīng)彈窗程序的進(jìn)程,右鍵點(diǎn)擊,選擇“打開文件所在的位置”。
第三步:定位彈窗軟件后,我們將其復(fù)制并保存在其他位置,以防止程序出錯(cuò)。
步驟4:此時(shí),我們需要復(fù)制程序的文件名稱及其擴(kuò)展名,復(fù)制后刪除程序。
第五步:新建一個(gè)txt替換復(fù)制文件名并單擊保存文件。注:需要將txt擴(kuò)展名覆蓋文檔。
第六步:右鍵單擊此文檔,選擇屬性。在其屬性窗口中,將選項(xiàng)卡切換為安全,單擊編輯,在權(quán)限窗口中檢查拒絕欄的選項(xiàng),最后單擊確定。
方法二:針對(duì)隱藏較深的彈窗程序第一步:試錯(cuò)。在其屬性窗口中,將選項(xiàng)卡切換為安全,單擊編輯,在權(quán)限窗口中檢查拒絕欄的選項(xiàng),最后單擊確定。
方法二:針對(duì)隱藏較深的彈窗程序。
第一步:試錯(cuò)。如何試呢?例如,我們?cè)谌蝿?wù)管理器中發(fā)現(xiàn)了一個(gè)我們從未見過(guò)的過(guò)程。此時(shí),我們可以先定位文件,然后關(guān)閉過(guò)程。當(dāng)彈出窗口消失時(shí),表明定位成功。假如沒有,我們還需要繼續(xù)試錯(cuò)。
第二步:如果定位成功。我們可以按照方法一的步驟刪除程序-新建程序txt文檔-添加權(quán)限。
方法三:win10系統(tǒng)內(nèi)置廣告。
開始菜單廣告。
右鍵在你不感興趣的游戲或應(yīng)用中,點(diǎn)擊卸載并執(zhí)行→鍵盤按下“WinX”→進(jìn)入設(shè)置-個(gè)性化→點(diǎn)擊左側(cè)開始→關(guān)閉右側(cè)的偶爾在開始菜單中顯示建議。
鎖屏廣告。
點(diǎn)擊設(shè)置→“個(gè)性化”→鎖屏界面,將背景切換到圖片或幻燈片放映。接下來(lái),取消鎖屏界面Windows和Cortana獲取花絮、提示等前面的復(fù)選框,即可關(guān)閉鎖屏廣告。
磁鐵廣告右擊推廣磁貼上的鼠標(biāo),選擇從菜單開始取消固定→“個(gè)性化”→開始,取消偶爾在‘開始’菜單中顯示建議的復(fù)選框。磁鐵廣告右擊推廣磁貼上的鼠標(biāo),選擇從菜單開始取消固定→“個(gè)性化”→開始,取消偶爾在‘開始’菜單中顯示建議的復(fù)選框。
(1)操作系統(tǒng)接收到應(yīng)用程序的窗口消息,將消息投遞到該應(yīng)用程序的消息隊(duì)列中。 (2)應(yīng)用程序在消息循環(huán)中調(diào)用GetMessage函數(shù)從消息隊(duì)列中取出一條一條的消息。取出消息后,應(yīng)用程序可以對(duì)消息進(jìn)行一些預(yù)處理,例如,放棄對(duì)某些消息的響應(yīng),或者調(diào)用TranslateMessage產(chǎn)生新的消息。 (3)應(yīng)用程序調(diào)用DispatchMessage,將消息回傳給操作系統(tǒng)。消息是由MSG結(jié)構(gòu)體對(duì)象來(lái)表示的,其中就包含了接收消息的窗口的句柄。因此,DispatchMessage函數(shù)總能進(jìn)行正確的傳遞。 (4)系統(tǒng)利用WNDCLASS結(jié)構(gòu)體的lpfnWndProc成員保存的窗口過(guò)程函數(shù)的指針調(diào)用窗口過(guò)程,對(duì)消息進(jìn)行處理(即“系統(tǒng)給應(yīng)用程序發(fā)送了消息”)。 注意:消息映射為什么不是虛函數(shù)呢? 答:C++有一個(gè)名為vtable的虛函數(shù)分發(fā)表。如果用虛函數(shù)發(fā)送消息CWnd將為超過(guò)100個(gè)消息來(lái)申明虛函數(shù),對(duì)于沒個(gè)虛函數(shù),vtable中對(duì)應(yīng)有4個(gè)字節(jié),那么應(yīng)用程序?qū)⑿枰?00多個(gè)字節(jié)的表來(lái)支持虛擬消息處理函數(shù)。所以為了避免大型的vtable,MFC使用宏來(lái)把WINDOWS消息連接到C++成員函數(shù)。MFC消息處理程序需要函數(shù)原型,函數(shù)體和在消息映射中的輸入項(xiàng)(宏調(diào)用),ClassWizard幫助我們將消息處理程序添加到類中。
一、 引言
二、Windows消息機(jī)制的概念
1、DOS與Windows驅(qū)動(dòng)機(jī)制的區(qū)別
2、消息
3、消息的來(lái)源
4、Windows的消息系統(tǒng)的組成
5、消息的響應(yīng)
三、Windows消息機(jī)制要點(diǎn)
1. 窗口過(guò)程
2 消息類型
3消息隊(duì)列(Message Queues)
4 隊(duì)列消息和非隊(duì)列消息
5 Windows消息函數(shù)
6消息死鎖( Message Deadlocks
7 BroadcastSystemMessage
四、MFC消息機(jī)制
1.MFC框架下,接收處理來(lái)自Windows消息的過(guò)程
2.MFC內(nèi)部消息處理方式
一、 引言
在 C++程序架構(gòu) 一文中,我們看到,程序是由一些層次和模塊組成的,那么,這些模塊之間, 以及你的程序和windows 之間,是如何傳遞信息呢?在windows 的平臺(tái)上,傳遞信息是由 windows message 消息機(jī)制來(lái)負(fù)責(zé)的,這是Windows 的核心部分。
消息包括數(shù)據(jù)和指令。
二、Windows消息機(jī)制的概念
1、DOS與Windows驅(qū)動(dòng)機(jī)制的區(qū)別
1)DOS是過(guò)程驅(qū)動(dòng)的。
傳統(tǒng)的MS-DOS程序主要采用順序的。關(guān)聯(lián)的、過(guò)程驅(qū)動(dòng)的程序設(shè)計(jì)方法。一個(gè)過(guò)程是一系列預(yù)先定義好的操作序列的組合,它具有一定的開頭、中間過(guò)程和結(jié)束。程序直接控制程序事件和過(guò)程的順序。這樣的程序設(shè)計(jì)方法是面向程序而不是面向用戶的,交互性差,用戶界面不夠友好,因?yàn)樗鼜?qiáng)迫用戶按照某種不可更改的模式進(jìn)行工作。它的基本模型如圖1.1所示。
2)Windows是事件(消息)驅(qū)動(dòng)
事件驅(qū)動(dòng)程序設(shè)計(jì)是一種全新的程序設(shè)計(jì)方法,它不是由事件的順序來(lái)控制,而是由事件的發(fā)生來(lái)控制,而這種事件的發(fā)生是隨機(jī)的、不確定的,并沒有預(yù)定的順序,這樣就允許程序的的用戶用各種合理的順序來(lái)安排程序的流程。對(duì)于需要用戶交互的應(yīng)用程序來(lái)說(shuō),事件驅(qū)動(dòng)的程序設(shè)計(jì)有著過(guò)程驅(qū)動(dòng)方法無(wú)法替代的優(yōu)點(diǎn)。它是一種面向用戶的程序設(shè)計(jì)方法,它在程序設(shè)計(jì)過(guò)程中除了完成所需功能之外,更多的考慮了用戶可能的各種輸入,并針對(duì)性的設(shè)計(jì)相應(yīng)的處理程序。它是一種“被動(dòng)”式程序設(shè)計(jì)方法,程序開始運(yùn)行時(shí),處于等待用戶輸入事件狀態(tài),然后取得事件并作出相應(yīng)反應(yīng),處理完畢又返回并處于等待事件狀態(tài)。它的框圖如圖1.2所示:
2、消息
Windows系統(tǒng)是一個(gè)事件驅(qū)動(dòng)的OS,每一個(gè)事件的發(fā)生都會(huì)產(chǎn)生一個(gè)消息,我們通過(guò)消息來(lái)知道發(fā)生了什么事件,了解事件,進(jìn)而解決事件。什么是消息呢?很難下一個(gè)定義,下面從不同的幾個(gè)方面講解一下:
1) 消息的組成:一個(gè)消息由一個(gè)消息名稱(UINT),和兩個(gè)參數(shù)(WPARAM,LPARAM)。當(dāng)用戶進(jìn)行了輸入或是窗口的狀態(tài)發(fā)生改變時(shí)系統(tǒng)都會(huì)發(fā)送消息到某一個(gè)窗口。例如當(dāng)菜單轉(zhuǎn)中之后會(huì)有WM_COMMAND消息發(fā)送,WPARAM的高字中(HIWORD(wParam))是命令的ID號(hào),對(duì)菜單來(lái)講就是菜單ID。當(dāng)然用戶也可以定義自己的消息名稱,也可以利用自定義消息來(lái)發(fā)送通知和傳送數(shù)據(jù)。
2)誰(shuí)將收到消息:一個(gè)消息必須由一個(gè)窗口接收。在窗口的過(guò)程(WNDPROC)中可以對(duì)消息進(jìn)行分析,對(duì)自己感興趣的消息進(jìn)行處理。例如你希望對(duì)菜單選擇進(jìn)行處理那么你可以定義對(duì)WM_COMMAND進(jìn)行處理的代碼,如果希望在窗口中進(jìn)行圖形輸出就必須對(duì)WM_PAINT進(jìn)行處理。
3)未處理的消息到那里去了:M$為窗口編寫了默認(rèn)的窗口過(guò)程,這個(gè)窗口過(guò)程將負(fù)責(zé)處理那些你不處理消息。正因?yàn)橛辛诉@個(gè)默認(rèn)窗口過(guò)程我們才可以利用Windows的窗口進(jìn)行開發(fā)而不必過(guò)多關(guān)注窗口各種消息的處理。例如窗口在被拖動(dòng)時(shí)會(huì)有很多消息發(fā)送,而我們都可以不予理睬讓系統(tǒng)自己去處理。
4)窗口句柄:說(shuō)到消息就不能不說(shuō)窗口句柄,系統(tǒng)通過(guò)窗口句柄來(lái)在整個(gè)系統(tǒng)中唯一標(biāo)識(shí)一個(gè)窗口,發(fā)送一個(gè)消息時(shí)必須指定一個(gè)窗口句柄表明該消息由那個(gè)窗口接收。而每個(gè)窗口都會(huì)有自己的窗口過(guò)程,所以用戶的輸入就會(huì)被正確的處理。例如有兩個(gè)窗口共用一個(gè)窗口過(guò)程代碼,你在窗口一上按下鼠標(biāo)時(shí)消息就會(huì)通過(guò)窗口一的句柄被發(fā)送到窗口一而不是窗口二。
3、消息的來(lái)源
事件驅(qū)動(dòng)圍繞著消息的產(chǎn)生與處理展開,一條消息是關(guān)于發(fā)生的事件的消息。事件驅(qū)動(dòng)是靠消息循環(huán)機(jī)制來(lái)實(shí)現(xiàn)的。也可以理解為消息是一種報(bào)告有關(guān)事件發(fā)生的通知。
Windows應(yīng)用程序的消息來(lái)源有一下四種:
1)輸入消息:包括鍵盤和鼠標(biāo)的輸入。這一類消息首先放在系統(tǒng)消息隊(duì)列中,然后由Windows將它們送入應(yīng)用程序消息隊(duì)列中,由應(yīng)用程序來(lái)處理消息。
2)控制消息:用來(lái)與Windows的控制對(duì)象,如列表框、按鈕、檢查框等進(jìn)行雙向通信。當(dāng)用戶在列表框中改動(dòng)當(dāng)前選擇或改變了檢查框的狀態(tài)時(shí)發(fā)出此類消息。這類消息一般不經(jīng)過(guò)應(yīng)用程序消息隊(duì)列,而是直接發(fā)送到控制對(duì)象上去。
3)系統(tǒng)消息:對(duì)程序化的事件或系統(tǒng)時(shí)鐘中斷作出反應(yīng)。一些系統(tǒng)消息,象DDE消息(動(dòng)態(tài)數(shù)據(jù)交換消息)要通過(guò)Windows的系統(tǒng)消息隊(duì)列,而有的則不通過(guò)系統(tǒng)消息隊(duì)列而直接送入應(yīng)用程序的消息隊(duì)列,如創(chuàng)建窗口消息。
4)用戶消息:這是程序員自己定義并在應(yīng)用程序中主動(dòng)發(fā)出的,一般由應(yīng)用程序的某一部分內(nèi)部處理。
4、Windows的消息系統(tǒng)的組成
Windows的消息系統(tǒng)由以下3部分組成:
消息隊(duì)列:Windows能夠?yàn)樗械膽?yīng)用程序維護(hù)一個(gè)消息隊(duì)列,應(yīng)用程序必須從消息隊(duì)列中獲去消息,然后分派給某個(gè)窗體。
消息循環(huán):通過(guò)這個(gè)循環(huán)機(jī)制,應(yīng)用程序從消息隊(duì)列中檢索消息,再把它分派給適當(dāng)?shù)拇翱冢缓罄^續(xù)從消息隊(duì)列中檢索下一條消息,再分派給適當(dāng)?shù)拇翱?,依次進(jìn)行。
窗口過(guò)程:每個(gè)窗口都有一個(gè)窗口過(guò)程,以接收Windows 傳遞給窗口的消息,窗口過(guò)程的任務(wù)就是獲取消息并且響應(yīng)它。窗口過(guò)程是一個(gè)回調(diào)函數(shù),處理完一個(gè)消息后,通常要給Windows 一個(gè)返回值。
5、消息的響應(yīng)
消息的產(chǎn)生來(lái)源于系統(tǒng)事情(包括計(jì)時(shí)器事件)和用戶事情,Windows用消息來(lái)調(diào)入和關(guān)閉(還有其它處理,如繪制一個(gè)窗口等)應(yīng)用程序,一個(gè)典型表現(xiàn)是在關(guān)機(jī)操作中,Windows發(fā)一個(gè)關(guān)機(jī)的消息給所有正在運(yùn)行的應(yīng)用程序,告知它們退出內(nèi)存,此時(shí),應(yīng)用程序用回應(yīng)消息的方法來(lái)響應(yīng)OS,因此,消息是應(yīng)用程序與WinOS交互的手段..
消息產(chǎn)生到被窗口響應(yīng)的步驟:(如下圖)
1 系統(tǒng)發(fā)生了或用戶發(fā)出某個(gè)事件。
2 Windows把這個(gè)事件翻譯為消息,然后把他放到消息隊(duì)列中
3 應(yīng)用程序從消息隊(duì)列中接受到這個(gè)消息,把他存放到TMsg記錄中。
4 應(yīng)用程序把消息傳遞給一個(gè)適當(dāng)?shù)拇绑w過(guò)程。
窗體過(guò)程響應(yīng)這個(gè)消息并進(jìn)行處理。把消息傳遞給了這個(gè)窗體的窗體函數(shù)。
三、Windows消息機(jī)制要點(diǎn)
1. 窗口過(guò)程
每個(gè)窗口會(huì)有一個(gè)稱為窗口過(guò)程的回調(diào)函數(shù)(WndProc),它帶有四個(gè)參數(shù),分別為:窗口句柄(Window Handle),消息ID(Message ID),和兩個(gè)消息參數(shù)(wParam, lParam), 當(dāng)窗口收到消息時(shí)系統(tǒng)就會(huì)調(diào)用此窗口過(guò)程來(lái)處理消息。(所以叫回調(diào)函數(shù))
2 消息類型
1) 系統(tǒng)定義消息(System-Defined Messages)
在SDK中事先定義好的消息,非用戶定義的,其范圍在[0×0000, 0×03ff]之間, 可以分為以下三類:
窗口消息(Windows Message)
與窗口的內(nèi)部運(yùn)作有關(guān),如創(chuàng)建窗口,繪制窗口,銷毀窗口等??梢允且话愕拇翱?,可以是 Dialog,控件等。
如:WM_CREATE, WM_PAINT, WM_MOUSEMOVE, WM_CTLCOLOR, WM_HSCROLL..
命令消息(Command Message)
與處理用戶請(qǐng)求有關(guān), 如單擊菜單項(xiàng)或工具欄或控件時(shí), 就會(huì)產(chǎn)生命令消息。
WM_COMMAND, LOWORD(wParam)表示菜單項(xiàng),工具欄按鈕或控件的ID。如果是控件, HIWORD(wParam)表示控件消息類型
控件通知(Notify Message)
控件通知消息, 這是最靈活的消息格式, 其Message, wParam, lParam分別為:WM_NOTIFY, 控件ID,指向NMHDR的指針。NMHDR包含控件通知的內(nèi)容, 可以任意擴(kuò)展。
2) 程序定義消息(Application-Defined Messages)
用戶自定義的消息, 對(duì)于其范圍有如下規(guī)定:
WM_USER: 0×0400-0×7FFF (ex. WM_USER+10)
WM_APP(winver4.0): 0×8000-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)的窗口過(guò)程(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ì)繞過(guò)系統(tǒng)消息隊(duì)列和線程消息隊(duì)列直接發(fā)送到窗口過(guò)程被處理
如: WM_ACTIVATE, WM_SETFOCUS, WM_SETCURSOR, WM_WINDOWPOSCHANGED
注意: postMessage發(fā)送的消息是隊(duì)列消息,它會(huì)把消息Post到消息隊(duì)列中; SendMessage發(fā)送的消息是非隊(duì)列消息, 被直接送到窗口過(guò)程處理
5 Windows消息函數(shù)
1)PostMessage(PostThreadMessage), SendMessage
PostMessage:把消息放到指定窗口所在的線程消息隊(duì)列中后立即返回。 PostThreadMessage:把消息放到指定線程的消息隊(duì)列中后立即返回。
SendMessage:直接把消息送到窗口過(guò)程處理, 處理完了才返回。
2)GetMessage, PeekMessage
PeekMessage會(huì)立即返回 可以保留消息
GetMessage在有消息時(shí)返回 會(huì)刪除消息
3) 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ā)送到窗口過(guò)程處理, 處理完后才會(huì)返回。
6消息死鎖( Message Deadlocks
假設(shè)有線程A和B, 現(xiàn)在有以下下步驟
1) 線程A SendMessage給線程B, A等待消息在線程B中處理后返回
2)線程B收到了線程A發(fā)來(lái)的消息,并進(jìn)行處理, 在處理過(guò)程中,B也向線程A SendMessgae,然后等待從A返回。
因?yàn)榇藭r(shí), 線程A正等待從線程B返回, 無(wú)法處理B發(fā)來(lái)的消息, 從而導(dǎo)致了\線程A,B相互等待, 形成死鎖。多個(gè)線程也可以形成環(huán)形死鎖。
可以使用 SendNotifyMessage或SendMessageTimeout來(lái)避免出現(xiàn)死鎖。
7 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ā)送消息。
那么這些消息是怎樣傳送的呢。我們以MFC為例來(lái)看一下消息傳送過(guò)程。
四、MFC消息機(jī)制
在Windows應(yīng)用程序的主函數(shù)中,首先要注冊(cè)窗口類,然后創(chuàng)建并顯示窗口。創(chuàng)建窗口后程序就進(jìn)入消息循環(huán),在消息循環(huán)中,程序不斷地獲得消息并將消息派送給對(duì)應(yīng)的窗口函數(shù)進(jìn)行處理。
我們可以看到,在MFC的框架結(jié)構(gòu)下,可以進(jìn)行消息處理的類的頭文件里面
都會(huì)含有DECLARE_MESSAGE_MAP()宏,這里主要進(jìn)行消息映射和消息處理函數(shù)的聲
明。可以進(jìn)行消息處理的類的實(shí)現(xiàn)文件里一般都含有如下的結(jié)構(gòu)。
BEGIN_MESSAGE_MAP(CInheritClass, CBaseClass) //{{AFX_MSG_MAP(CInheritClass)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
這里主要進(jìn)行消息映射的實(shí)現(xiàn)和消息處理函數(shù)的實(shí)現(xiàn)。
所有能夠進(jìn)行消息處理的類都是基于CCmdTarget類的,也就是說(shuō)CCmdTarget
類是所有可以進(jìn)行消息處理類的父類。CCmdTarget類是MFC處理命令消息的基礎(chǔ)和核心。
同時(shí)MFC定義了下面的兩個(gè)主要結(jié)構(gòu):
AFX_MSGMAP_ENTRY
struct AFX_MSGMAP_ENTRY
{//“““//
};
和AFX_MSGMAP
struct AFX_MSGMAP
{//“““`//
};
其中AFX_MSGMAP_ENTRY結(jié)構(gòu)包含了一個(gè)消息的所有相關(guān)信息, 而AFX_MSGMAP主要作用是兩個(gè),一:用來(lái)得到基類的消息映射入口地址。二:得到本身的消息映射入口地址。
實(shí)際上,MFC把所有的消息一條條填入到AFX_MSGMAP_ENTRY結(jié)構(gòu)中去,形成一個(gè)數(shù)組,該數(shù)組存放了所有的消息和與它們相關(guān)的消息的參數(shù)。同時(shí)通過(guò)AFX_MSGMAP能得到該數(shù)組的首地址,同時(shí)也得到基類的消息映射入口地址,這是為例當(dāng)本身對(duì)該消息不響應(yīng)的時(shí)候,就調(diào)用其基類的消息響應(yīng)。
現(xiàn)在我們來(lái)分析MFC是如何讓窗口過(guò)程來(lái)處理消息的,實(shí)際上所有MFC的窗口類都通過(guò)鉤子函數(shù)_AfxCbtFilterHook截獲消息,并且在鉤子函數(shù)_AfxCbtFilterHook中把窗口過(guò)程設(shè)定為AfxWndProc。原來(lái)的窗口過(guò)程保存在成員變量m_pfnSuper中
1.MFC框架下,接收處理來(lái)自Windows消息的過(guò)程:
2.MFC內(nèi)部消息處理方式
MFC接收一個(gè)寄送的消息:
MFC處理一個(gè)寄送和發(fā)送消息的惟一明顯不同是寄送的消息要做應(yīng)用程序的消息隊(duì)列中花費(fèi)一些時(shí)間。在消息泵(message pump)彈出它之前,它要一直在隊(duì)列中。下面是怎樣接受寄送消息的過(guò)程。MFC應(yīng)用程序中的消息泵在CWinApp的成員函數(shù)Run()中。應(yīng)用程序開始運(yùn)行時(shí),Run()就被調(diào)用,Run()把時(shí)間分割成兩部分。一部分用來(lái)執(zhí)行后臺(tái)處理,如取消臨時(shí)CWnd對(duì)象;另一部分用來(lái)檢查消息隊(duì)列。當(dāng)一個(gè)新的消息進(jìn)來(lái)時(shí),Run()抽取它—即用GetMessage( )從隊(duì)列中取出該消息,運(yùn)行PreTranslateMessage( )和::TranslateMessage( )兩個(gè)消息翻譯函數(shù),然后用DispatchMessage( )函數(shù)調(diào)用該消息預(yù)期的目標(biāo)窗口進(jìn)程。如下圖。
我們用一個(gè)實(shí)例函數(shù)A發(fā)送消息到函數(shù)B的過(guò)程來(lái)看一下MFC內(nèi)部消息處理過(guò)程。
1. 首先函數(shù)A應(yīng)獲取消息的CWnd類對(duì)象的指針,然后,調(diào)用CWnd的成員函數(shù)SendMessage()。
LRESULT Res=pWnd-SendMessage(UINT Msg, WPARAM wParam, LPARAM lParam);
pWnd指針指向目標(biāo)CWnd類對(duì)象。變量Msg是消息,wParam和lParam變量包含消息的參數(shù),如鼠標(biāo)單單擊哪里或選擇了什么菜單項(xiàng)。目標(biāo)窗口返回的消息結(jié)果放在變量Res中。
發(fā)送消息到一個(gè)沒有CWnd的函數(shù)對(duì)象的窗口,可以用下列目標(biāo)窗口的句柄直接調(diào)用Windows API:
LRESULT Res=::SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
這里的hWnd是目標(biāo)窗口的句柄。
如果是異步傳輸也可使用PostMessage(),消息同上相同,但返回值Res不一樣,Res不是一個(gè)由目標(biāo)窗體返回的值,而是一個(gè)布爾值,用來(lái)表示消息是否成功的放到消息隊(duì)列中。
2. 正常情況下,一旦消息被發(fā)送后,應(yīng)用程序后臺(tái)會(huì)自動(dòng)的將它發(fā)送,但是在特殊情況下,需要你自己去刪除一個(gè)消息,例如想在應(yīng)用程序接收到某種消息之前停止應(yīng)用程序。有兩種方法可以從應(yīng)用程序消息隊(duì)列中刪除一個(gè)消息,但這兩種方法都沒有涉及MFC。
第一種方法:在不干擾任何事情之下窺視消息隊(duì)列,看看一個(gè)消息是否在那里。
BOOL res=::PeekMessage(LPMSG lpMsg, HWND hWnd, UINT wMsFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg ) ;
第二種方法:實(shí)際上是等待,一直等到一個(gè)新的消息到達(dá)隊(duì)列為止,然后刪除并返回該消息。
BOOL res=::GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);
在這兩種方法中,變量hWnd指定要截獲消息的窗口,如果該變量設(shè)為NULL,所有窗口消息將被截獲。wMsgFilterMin和wMsgFilterMax變量與SendMessage( )中的變量Msg相對(duì)應(yīng),指定查看消息的范圍。如果用“0,0〃,則所有的消息都將被截獲。如果用WM_KEYFIRST,WM_KEYLAST或WM_MOUSEFIRST,WM_MOUSELAST,則所有鍵盤或鼠標(biāo)的消息將被截獲。wRemoveMsg變量指定PeekMessage( )是否應(yīng)該真正地從隊(duì)列中刪除該消息。(GetMessage( )總是刪除消息)。該變量可以取兩個(gè)值:
PM_REMOVE,PeekMessage( )將刪除消息。
PM_NOREMOVE,PeekMessage( )將把消息留在隊(duì)列里,并返回它的一個(gè)拷貝。
當(dāng)然,如果把消息留在消息隊(duì)列中,然后再次調(diào)用PeekMessage( )查看相同類型的消息,則將返回完全相同的消息。
lpMsg變量是一個(gè)指向MSG結(jié)構(gòu)的指針,MSG包含檢索到的消息。
typedef struct tagMSG {
HWND hwnd; // window handle message is intended for
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time; // the time the message was put in the queue
POINT pt; // the location of the mouse cursor when the
// message was put in the queue
} MSG;
3. 消息會(huì)到消息隊(duì)列中。CwinApp的成員函數(shù)Run,在應(yīng)用程序運(yùn)行時(shí),Run就把時(shí)間分割成兩部分,一部分執(zhí)行后臺(tái)的處理,另一部分來(lái)檢查消息的隊(duì)列,當(dāng)發(fā)現(xiàn)新消息時(shí),Run就調(diào)用GetMessage()從隊(duì)列消息中取出該消息。
3.運(yùn)行兩個(gè)消息翻譯函數(shù)PreTranslateMessage()和::TranslateMessage(),進(jìn)行翻譯。主要找到函數(shù)對(duì)象的位置、消息的動(dòng)作標(biāo)識(shí)和跟消息相關(guān)的執(zhí)行操作。
4.用DispatchMessage()函數(shù)調(diào)用該消息預(yù)期的函數(shù)B進(jìn)程,進(jìn)行執(zhí)行。