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

下載本文檔

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

文檔簡介

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

溫馨提示

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

評論

0/150

提交評論