WINDOWS的消息機(jī)制與回調(diào)機(jī)制_第1頁(yè)
WINDOWS的消息機(jī)制與回調(diào)機(jī)制_第2頁(yè)
WINDOWS的消息機(jī)制與回調(diào)機(jī)制_第3頁(yè)
WINDOWS的消息機(jī)制與回調(diào)機(jī)制_第4頁(yè)
WINDOWS的消息機(jī)制與回調(diào)機(jī)制_第5頁(yè)
已閱讀5頁(yè),還剩1頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

WINDOWS的消息機(jī)制與回調(diào)機(jī)制聲明CALLBACK調(diào)用(calling)機(jī)制從匯編時(shí)代起已經(jīng)大量使用:準(zhǔn)備一段現(xiàn)成的代碼,調(diào)用者可以隨時(shí)跳轉(zhuǎn)至此段代碼的起始地址,執(zhí)行完后再返回跳轉(zhuǎn)時(shí)的后續(xù)地址。CPU為此準(zhǔn)備了現(xiàn)成的調(diào)用指令,調(diào)用時(shí)可以壓棧保護(hù)現(xiàn)場(chǎng),調(diào)用結(jié)束后從堆棧中彈出現(xiàn)場(chǎng)地址,以便自動(dòng)返回。借堆棧保護(hù)現(xiàn)場(chǎng),它使調(diào)用者和被調(diào)者可以互不相識(shí),于是才有了后來(lái)的函數(shù)和構(gòu)件.此調(diào)用機(jī)制并非完美?;卣{(diào)函數(shù)就是一例。例如,寫(xiě)一個(gè)快速排序函數(shù)供他人調(diào)用,其中必包含比較大小。麻煩來(lái)了:此時(shí)并不知要比較的是何類(lèi)數(shù)據(jù)--整數(shù)、浮點(diǎn)數(shù)、字符串?于是只好為每類(lèi)數(shù)據(jù)制作一個(gè)不同的排序函數(shù)。更通行的辦法是在函數(shù)參數(shù)中列一個(gè)回調(diào)函數(shù)地址,并通知調(diào)用者:君需自己準(zhǔn)備一個(gè)比較函數(shù),其中包含兩個(gè)指針類(lèi)參數(shù),函數(shù)要比較此二指針?biāo)笖?shù)據(jù)之大小,并由函數(shù)返回值說(shuō)明比較結(jié)果。排序函數(shù)借此調(diào)用者提供的函數(shù)來(lái)比較大小,借指針傳遞參數(shù),可以全然不管所比較的數(shù)據(jù)類(lèi)型。被調(diào)用者回頭調(diào)用調(diào)用者的函數(shù)(夠咬嘴的),故稱(chēng)其為回調(diào)(callback)。Windows系統(tǒng)還包含著另一種更為廣泛的回調(diào)機(jī)制,即消息機(jī)制。消息本是Windows的基本控制手段,乍看與函數(shù)調(diào)用無(wú)關(guān),其實(shí)是一種變相的函數(shù)調(diào)用。發(fā)送消息的目的是通知收方運(yùn)行一段預(yù)先準(zhǔn)備好的代碼,相當(dāng)于調(diào)用一個(gè)函數(shù)。消息所附帶的WParam和LParam相當(dāng)于函數(shù)的參數(shù),只不過(guò)比普通參數(shù)更通用一些。應(yīng)用程序可以主動(dòng)發(fā)送消息,更多情況下是坐等Windows發(fā)送消息。一旦消息進(jìn)入所屬消息隊(duì)列,便檢感興趣的那些,跳轉(zhuǎn)去執(zhí)行相應(yīng)的消息處理代碼。操作系統(tǒng)本是為應(yīng)用程序服務(wù),由應(yīng)用程序來(lái)調(diào)用。而應(yīng)用程序一旦啟動(dòng),卻要反過(guò)來(lái)等待操作系統(tǒng)的調(diào)用。這分明也是一種回調(diào),或者說(shuō)是一種廣義回調(diào)。其實(shí),應(yīng)用程序之間也可以形成這種回調(diào)。假如進(jìn)程B收到進(jìn)程A發(fā)來(lái)的消息,啟動(dòng)了一段代碼,其中又向進(jìn)程A發(fā)送消息,這就形成了回調(diào)。這種回調(diào)比較隱蔽,弄不好會(huì)搞成遞歸調(diào)用,若缺少終止條件,將會(huì)循環(huán)不已,直至把程序搞垮。若是故意編寫(xiě)成此遞歸調(diào)用,并設(shè)好終止條件,倒是很有意思。但這種程序結(jié)構(gòu)太隱蔽,除非十分必要,還是不用為好。利用消息也可以構(gòu)成狹義回調(diào)。上面所舉排序函數(shù)一例,可以把回調(diào)函數(shù)地址換成窗口handle。如此,當(dāng)需要比較數(shù)據(jù)大小時(shí),不是去調(diào)用回調(diào)函數(shù),而是借API函數(shù)SendMessage向指定窗口發(fā)送消息。收到消息方負(fù)責(zé)比較數(shù)據(jù)大小,把比較結(jié)果通過(guò)消息本身的返回值傳給消息發(fā)送方。所實(shí)現(xiàn)的功能與回調(diào)函數(shù)并無(wú)不同。當(dāng)然,此例中改為消息純屬畫(huà)蛇添腳,反倒把程序搞得很慢。但其他情況下并非總是如此,特別是需要異步調(diào)用時(shí),發(fā)送消息是一種不錯(cuò)的選擇。假如回調(diào)函數(shù)中包含文件處理之類(lèi)的低速處理,調(diào)用方等不得,需要把同步調(diào)用改為異步調(diào)用,去啟動(dòng)一個(gè)單獨(dú)的線(xiàn)程,然后馬上執(zhí)行后續(xù)代碼,其余的事讓線(xiàn)程慢慢去做。一個(gè)替代辦法是借API函數(shù)PostMessage發(fā)送一個(gè)異步消息,然后立即執(zhí)行后續(xù)代碼。這要比自己搞個(gè)線(xiàn)程省事許多,而且更安全。如今我們是活在一個(gè)object時(shí)代。只要與編程有關(guān),無(wú)論何事都離不開(kāi)object。但object并未消除回調(diào),反而把它發(fā)揚(yáng)光大,弄得到處都是,只不過(guò)大都以事件(event)的身份出現(xiàn),鑲嵌在某個(gè)結(jié)構(gòu)之中,顯得更正統(tǒng),更容易被人接受。應(yīng)用程序要使用某個(gè)構(gòu)件,總要先弄清構(gòu)件的屬性、方法和事件,然后給構(gòu)件屬性賦值,在適當(dāng)?shù)臅r(shí)候調(diào)用適當(dāng)?shù)臉?gòu)件方法,還要給事件編寫(xiě)處理例程,以備構(gòu)件代碼來(lái)調(diào)用。何謂事件?它不過(guò)是一個(gè)指向事件例程的地址,與回調(diào)函數(shù)地址沒(méi)什么區(qū)別。不過(guò),此種回調(diào)方式比傳統(tǒng)回調(diào)函數(shù)要高明許多。首先,它把讓人不太舒服的回調(diào)函數(shù)變成一種自然而然的處理例程,使編程者頓覺(jué)氣順。再者,地址是一個(gè)危險(xiǎn)的東西,用好了可使程序加速,用不好處處是陷阱,程序隨時(shí)都會(huì)崩潰?,F(xiàn)代編程方式總是想法把地址隱藏起來(lái)(隱藏比較徹底的如VB和Java),其代價(jià)是降低了程序效率。事件例程使編程者無(wú)需直接操作地址,但并不會(huì)使程序減速?;卣{(diào)函數(shù):它是這樣一種機(jī)制:調(diào)用者在初始化一個(gè)對(duì)象(這里的對(duì)象是泛指,包括OOP中的對(duì)象、全局函數(shù)等)時(shí),將一些參數(shù)傳遞給對(duì)象,同時(shí)將一個(gè)調(diào)用者可以訪問(wèn)的函數(shù)地址傳遞給該對(duì)象(被調(diào)用者)。這個(gè)函數(shù)就是調(diào)用者和被調(diào)用者之間的一種通知約定,當(dāng)約定的事件發(fā)生時(shí),被調(diào)用者(一般會(huì)包含一個(gè)工作線(xiàn)程)就會(huì)按照回調(diào)函數(shù)地址調(diào)用該函數(shù),并向被調(diào)用者返回一個(gè)結(jié)果。這種方式,調(diào)用者在一個(gè)線(xiàn)程,被調(diào)用者在另一個(gè)線(xiàn)程。句柄:handle,handle的本意是把柄,把手的意思,就是一個(gè)標(biāo)號(hào)。是你與操作系統(tǒng)打交道的東東。舉個(gè)通俗的例子,比如你考上了大學(xué),入學(xué)后,學(xué)校(操作系統(tǒng))會(huì)給你一個(gè)學(xué)生證號(hào)。注意,這個(gè)號(hào)碼是學(xué)校指定的,你無(wú)法自選。有了這個(gè)號(hào)碼(學(xué)生證,假設(shè)一證多用)就可以享受學(xué)校提供的服務(wù):如你就可以去圖書(shū)館借書(shū),去食堂吃飯,去教室上課等等。但你不能到食堂里買(mǎi)啤酒,因?yàn)閷W(xué)校不允許這種服務(wù)。而在計(jì)算機(jī)中系統(tǒng)提供的服務(wù)就是API調(diào)用,你有了HANDLE,就可以理直氣壯地向系統(tǒng)提出調(diào)用API的服務(wù)。而指針的權(quán)力就大多了,有了指針你可以到處去喝酒,打架,學(xué)校(操作系統(tǒng))管不著,所以句柄和指針的區(qū)別在于句柄只能調(diào)用系統(tǒng)提供的服務(wù)。而句柄雖然是一個(gè)能相互區(qū)別的號(hào)碼,但與我們普通的ID號(hào)又有區(qū)別,普通的ID號(hào)是可以由程序員自己定義的,而句柄不行,它是對(duì)象生成時(shí)系統(tǒng)指定的,是為了區(qū)別系統(tǒng)中存在的各個(gè)對(duì)象,這個(gè)句柄不是由程序員符給的。實(shí)際應(yīng)用中,最常用的就是文件句柄和窗口句柄。例如,窗口句柄的值是一個(gè)長(zhǎng)整數(shù),每個(gè)窗體都用一個(gè)句柄來(lái)表示。所以句柄是不會(huì)重復(fù)的,很多的函數(shù)都會(huì)用到窗體的句柄。消息:一個(gè)消息由一個(gè)消息名稱(chēng)(UINT),和兩個(gè)參數(shù)(WPARAM,LPARAM)組成。windows的消息機(jī)制:消息”是windows運(yùn)行機(jī)制中一個(gè)基本而又重要的概念。消息是一個(gè)報(bào)告事件發(fā)生的通知,消息驅(qū)動(dòng)是圍繞消息的產(chǎn)生與處理展開(kāi)的,并依靠消息循環(huán)機(jī)制來(lái)實(shí)現(xiàn)。某條消息可被視為某個(gè)事件的發(fā)生,比如點(diǎn)擊鼠標(biāo)。事件即可以由用戶(hù)引發(fā),也可以由應(yīng)用程序產(chǎn)生,當(dāng)然windows本身也能發(fā)出消息。windows是一個(gè)多任務(wù)操作系統(tǒng),所以沒(méi)有哪一個(gè)程序能夠獨(dú)占系統(tǒng)的資源,資源都是由windows統(tǒng)一管理的。那么某個(gè)程序是如何獲得用戶(hù)的信息呢?事實(shí)上,windows在時(shí)刻監(jiān)視著用戶(hù)的每個(gè)舉動(dòng),一旦發(fā)生了動(dòng)作,就由windows捕捉而不是應(yīng)用程序,windows分析該動(dòng)作與哪一個(gè)程序相關(guān),然后將動(dòng)作以消息的形式發(fā)送給當(dāng)前的應(yīng)用程序。相反,應(yīng)用程序也在時(shí)時(shí)等著消息的到來(lái),一旦發(fā)現(xiàn)它的消息隊(duì)列中有未處理的信息,就獲取并分析該消息,并根據(jù)消息所包含的內(nèi)容采取適當(dāng)?shù)膭?dòng)作來(lái)響應(yīng),并將結(jié)果返回給系統(tǒng)。例如窗口程序,當(dāng)用戶(hù)點(diǎn)擊按鈕時(shí)候,這一動(dòng)作被windows捕捉,并且以消息(ID和參數(shù))的形式發(fā)給該窗口的消息隊(duì)列,該窗口發(fā)現(xiàn)隊(duì)列中有消息,就根據(jù)消息調(diào)用相應(yīng)的過(guò)程進(jìn)行處理,并將返回結(jié)果返回給系統(tǒng)。每個(gè)窗口本身都有一個(gè)窗口函數(shù),未處理的消息就由它處理,例如拖動(dòng)。windows為每個(gè)線(xiàn)程維護(hù)了相應(yīng)的消息隊(duì)列,應(yīng)用程序的任務(wù)就是不停地從特定的消息隊(duì)列中獲取消息、分析消息并處理消息,直到消息(WM_QUIT)為止。這個(gè)過(guò)程的程序結(jié)構(gòu)稱(chēng)為''消息循環(huán)”。函數(shù)回調(diào)與消息機(jī)制:可以看出,消息機(jī)制是一種特殊的函數(shù)回調(diào)。因?yàn)閼?yīng)用程序本是調(diào)用系統(tǒng)函數(shù)的,但是一旦啟動(dòng)就等待系統(tǒng)發(fā)來(lái)的消息,等到消息調(diào)用相應(yīng)過(guò)程進(jìn)行處理,相當(dāng)于系統(tǒng)進(jìn)行了回調(diào)。所以消息機(jī)制是一種廣義的函數(shù)回調(diào)。Windows消息機(jī)制要點(diǎn)1.窗口過(guò)程每個(gè)窗口會(huì)有一個(gè)稱(chēng)為窗口過(guò)程的回調(diào)函數(shù)(WndProc),它帶有四個(gè)參數(shù),分別為:窗口句柄(WindowHandle),消息ID(MessageID),和兩個(gè)消息參數(shù)(wParam,IParam),當(dāng)窗口收到消息時(shí)系統(tǒng)就會(huì)調(diào)用此窗口過(guò)程來(lái)處理消息。(所以叫回調(diào)函數(shù))2消息類(lèi)型1)系統(tǒng)定義消息(System-DefinedMessages)在SDK中事先定義好的消息,非用戶(hù)定義的,其范圍在[0x0000,0x03ff]之間,可以分為以下三類(lèi):1>窗口消息(WindowsMessage)與窗口的內(nèi)部運(yùn)作有關(guān),如創(chuàng)建窗口,繪制窗口,銷(xiāo)毀窗口等??梢允且话愕拇翱?,也可以是Dialog,控件等。如:WM_CREATE,WM_PAINT,WM_MOUSEMOVE,WM_CTLCOLOR,WM_HSCROLL...2>命令消息(CommandMessage)與處理用戶(hù)請(qǐng)求有關(guān),如單擊菜單項(xiàng)或工具欄或控件時(shí),就會(huì)產(chǎn)生命令消息。WM_COMMAND,LOWORD(wParam)表示菜單項(xiàng),工具欄按鈕或控件的ID。如果是控件,HIWORD(wParam)表示控件消息類(lèi)型3>控件通知(NotifyMessage)控件通知消息,這是最靈活的消息格式,其Message,wParam,lParam分別為:WM_NOTIFY,控件ID,指向NMHDR的指針。NMHDR包含控件通知的內(nèi)容,可以任意擴(kuò)展。2)程序定義消息(Application-DefinedMessages)用戶(hù)自定義的消息,對(duì)于其范圍有如下規(guī)定:WM_USER:0x0400-0x7FFF(ex.WM_USER+10)WM_APP(winver>4.0):0x8000-0xBFFF(ex.WM_APP+4)RegisterWindowMessage:0xC000-0xFFFF消息隊(duì)歹列(MessageQueues)Windows中有兩種類(lèi)型的消息隊(duì)列系統(tǒng)消息隊(duì)列(SystemMessageQueue)這是一個(gè)系統(tǒng)唯一的Queue,設(shè)備驅(qū)動(dòng)(mouse,keyboard)會(huì)把操作輸入轉(zhuǎn)化成消息存在系統(tǒng)隊(duì)列中,然后系統(tǒng)會(huì)把此消息放到目標(biāo)窗口所在的線(xiàn)程的消息隊(duì)列(thread-specificmessagequeue)中等待處理線(xiàn)程消息隊(duì)歹J(Thread-specificMessageQueue)每一個(gè)GUI線(xiàn)程都會(huì)維護(hù)這樣一個(gè)線(xiàn)程消息隊(duì)列。(這個(gè)隊(duì)列只有在線(xiàn)程調(diào)用GDI函數(shù)時(shí)才會(huì)創(chuàng)建,默認(rèn)不創(chuàng)建。然后線(xiàn)程消息隊(duì)列中的消息會(huì)被送到相應(yīng)的窗口過(guò)程WndProc)處理.注意:線(xiàn)程消息隊(duì)列中WM_PAINT,WM_TIMER只有在Queue中沒(méi)有其他消息的時(shí)候才會(huì)被處理,WM_PAINT消息還會(huì)被合并以提高效率。其他所有消息以先進(jìn)先出(FIFO)的方式被處理。隊(duì)列消息(QueuedMessages)和非隊(duì)列消息(Non-QueuedMessages)1)隊(duì)列消息(QueuedMessages)消息會(huì)先保存在消息隊(duì)列中,消息循環(huán)會(huì)從此隊(duì)列中取消息并分發(fā)到各窗口處理如鼠標(biāo),鍵盤(pán)消息。2)非隊(duì)列消息(NonQueuedMessages)消息會(huì)繞過(guò)系統(tǒng)消息隊(duì)列和線(xiàn)程消息隊(duì)列直接發(fā)送到窗口過(guò)程被處理如:WM_ACTIVATE,WM_SETFOCUS,WM_SETCURSOR,WM_WINDOWPOSCHANGED注意:postMessage發(fā)送的消息是隊(duì)列消息,它會(huì)把消息Post到消息隊(duì)列中;SendMessage發(fā)送的消息是非隊(duì)列消息,被直接送到窗口過(guò)程處理PostMessage(PostThreadMessage),SendMessagePostMessage:把消息放到指定窗口所在的線(xiàn)程消息隊(duì)列中后立即返回。PostThreadMessage:把消息放到指定線(xiàn)程的消息隊(duì)列中后立即返回。SendMessage:直接把消息送到窗口過(guò)程處理,處理完了才返回。GetMessage,PeekMessagePeekMessage會(huì)立即返回可以保留消息GetMessage在有消息時(shí)返回會(huì)刪除消息TranslateMessage,TranslateAcceleratorTranslateMessage:把一個(gè)virtual-key消息轉(zhuǎn)化成字符消息(charactermessage),并放到當(dāng)前線(xiàn)程的消息隊(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ì)返回。8(消息死鎖(MessageDeadlocks)假設(shè)有線(xiàn)程A和B,現(xiàn)在有以下下步驟1)線(xiàn)程ASendMessage給線(xiàn)程B,A等待消息在線(xiàn)程B中處理后返回2)線(xiàn)程B收到了線(xiàn)程A發(fā)來(lái)的消息,并進(jìn)行處理,在處理過(guò)程中,B也向線(xiàn)程ASendMessgae,然后等待從A返回。因?yàn)榇藭r(shí),線(xiàn)程A正等待從線(xiàn)程B返回,無(wú)法處理B發(fā)來(lái)的消息,從而導(dǎo)致了\線(xiàn)程A,B相互等

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論