![深入探討MFC消息循環(huán)和消息泵_第1頁](http://file4.renrendoc.com/view/0dc68f6eca2c76c70787d6215010e207/0dc68f6eca2c76c70787d6215010e2071.gif)
![深入探討MFC消息循環(huán)和消息泵_第2頁](http://file4.renrendoc.com/view/0dc68f6eca2c76c70787d6215010e207/0dc68f6eca2c76c70787d6215010e2072.gif)
![深入探討MFC消息循環(huán)和消息泵_第3頁](http://file4.renrendoc.com/view/0dc68f6eca2c76c70787d6215010e207/0dc68f6eca2c76c70787d6215010e2073.gif)
![深入探討MFC消息循環(huán)和消息泵_第4頁](http://file4.renrendoc.com/view/0dc68f6eca2c76c70787d6215010e207/0dc68f6eca2c76c70787d6215010e2074.gif)
![深入探討MFC消息循環(huán)和消息泵_第5頁](http://file4.renrendoc.com/view/0dc68f6eca2c76c70787d6215010e207/0dc68f6eca2c76c70787d6215010e2075.gif)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
深入探討MFC消息循環(huán)和消息泵作者:周焱首先,應(yīng)該清楚MFC的消息循環(huán)(::GetMessage,::PeekMessage),消息泵(CWinThread::PumpMessage)和MFC的消息在窗口之間的路由是兩件不同的事情。在MFC的應(yīng)用程序中(應(yīng)用程序類基于CWinThread繼承),必須要有一個消息循環(huán),他的作用是從應(yīng)用程序的消息隊列中讀取消息,并把它派送出去(::DispatchMessage)。而消息路由是指消息派送出去之后,系統(tǒng)(USER32.DLL)把消息投遞到哪個窗口,以及以后消息在窗口之間的傳遞是怎樣的。消息分為隊列消息(進(jìn)入線程的消息隊列)和非隊列消息(不進(jìn)入線程的消息隊列)。對于隊列消息,最常見的是鼠標(biāo)和鍵盤觸發(fā)的消息,例如WM_MOUSERMOVE,WM_CHAR等消息;還有例女如WM_PAINT、WM_TIMER和WM_QUITO當(dāng)鼠標(biāo)、鍵盤事件被觸發(fā)后,相應(yīng)的鼠標(biāo)或鍵盤驅(qū)動程序就會把這些事件轉(zhuǎn)換成相應(yīng)的消息,然后輸送到系統(tǒng)消息隊列,由Windows系統(tǒng)負(fù)責(zé)把消息加入到相應(yīng)線程的消息隊列中,于是就有了消息循環(huán)(從消息隊列中讀取并派送消息)。還有一種是非隊列消息,他繞過系統(tǒng)隊列和消息隊列,直接將消息發(fā)送到窗口過程。例如,當(dāng)用戶激活一個窗口系統(tǒng)發(fā)送WM_ACTIVATE,WM_SETFOCUS,andWM_SETCURSOR。創(chuàng)建窗口時發(fā)送WM_CREATE消息。在后面你將看到,MS這么設(shè)計是很有道理的,以及他的整套實現(xiàn)機(jī)制。這里講述MFC的消息循環(huán),消息泵。先看看程序啟動時,怎么進(jìn)入消息循環(huán)的:_tWinMain->AfxWinMain->AfxWinInit->CWinThread::InitApplication->CWinThread::InitInstance->CWinThread::Run非對話框程序的消息循環(huán)的事情都從這CWinThread的一Run開始...第一部分:非對話框程序的消息循環(huán)機(jī)制。//thrdcore.cpp//mainrunningroutineuntilthreadexitsintCWinThread::Run(){ASSERT_VALID(this);//fortrackingtheidletimestateBOOLbIdle=TRUE;LONGlIdleCount=0;//acquireanddispatchmessagesuntilaWM_QUITmessageisreceived.for(;;){//phase1:checktoseeifwecandoidleworkwhile(bIdle&&!::PeekMessage(&m_msgCur,NULL,NULL,NULL,PM_NOREMOVE)){//callOnIdlewhileinbIdlestateif(!OnIdle(lIdleCount++))bIdle=FALSE;//assume"noidle"state}//phase2:pumpmessageswhileavailabledo{//pumpmessage,butquitonWM_QUITif(!PumpMessage())returnExitInstance();//reset"noidle"stateafterpumping"normal"messageif(IsIdleMessage(&m_msgCur)){bIdle=TRUE;lIdleCount=0;}}while(::PeekMessage(&m_msgCur,NULL,NULL,NULL,PM_NOREMOVE));} //無限循環(huán),退出條件是收到WM_QUIT消息。ASSERT(FALSE);//notreachable}這是一個無限循環(huán),他的退出條件是收到WM_QUIT消息:if(!PumpMessage())returnExitInstance();在PumpMessage中,如果收到WM_QUIT消息,那么返回FALSE,所以ExitInstance()函數(shù)執(zhí)行,跳出循環(huán),返回程序的退出代碼。所以,一個程序要退出,只用在代碼中調(diào)用函數(shù)VOIDPostQuitMessage(intnExitCode)。指定退出代碼nExitCode就可以退出程序。下面討論一下這個函數(shù)Run的流程,分兩步:1,第一個內(nèi)循環(huán)phasel。bldle代表程序是否空閑。他的意思就是,如果程序是空閑并且消息隊列中沒有要處理的消息,那么調(diào)用虛函數(shù)Onldle進(jìn)行空閑處理。在這個處理中將更新UI界面(比如工具欄按鈕的enable和disable狀態(tài)),刪除臨時對象(比如用FromHandle得到的對象指針。由于這個原因,在函數(shù)之間傳遞由FromHandle得到的對象指針是不安全的,因為他沒有持久性)。Onldle是可以重載的,你可以重載他并返回TRUE使消息循環(huán)繼續(xù)處于空閑狀態(tài)。NOTE:MS用臨時對象是出于效率上的考慮,使內(nèi)存有效利用,并能夠在空閑時自動撤銷資源。關(guān)于由句柄轉(zhuǎn)換成對象,可以有若干種方法。一般是先申明一個對象obj,然后使用obj.Attatch來和一個句柄綁定。這樣產(chǎn)生的對象是永久的,你必須用obj.Detach來釋放對象。2,第二個內(nèi)循環(huán)phase2。在這個循環(huán)內(nèi)先啟動消息泵(PumpMessage),如果不是WM_QUIT消息,消息泵將消息發(fā)送出去(::DispatchMessage)。消息的目的地是消息結(jié)構(gòu)中的hwnd字段所對應(yīng)的窗口。//thrdcore.cppBOOLCWinThread::PumpMessage(){ASSERT_VALID(this);//如果是WM_QUIT就退出函數(shù)(returnFALSE),這將導(dǎo)致程序結(jié)束.if(!::GetMessage(&m_msgCur,NULL,NULL,NULL)){#ifdef_DEBUGif(afxTraceFlags&traceAppMsg)TRACE0("CWinThread::PumpMessage-ReceivedWM_QUIT.\n");m_nDisablePumpCount++;//applicationmustdie//Note:preventscallingmessageloopthingsin'ExitInstance'//willneverbedecremented#endifreturnFALSE;}#ifdef_DEBUGif(m_nDisablePumpCount!=0){TRACE0("Error:CWinThread::PumpMessagecalledwhennotpermitted.\n");ASSERT(FALSE);}#endif#ifdef_DEBUGif(afxTraceFlags&traceAppMsg)_AfxTraceMsg(_T("PumpMessage"),&m_msgCur);#endif//processthismessageif(m_msgCur.message!=WM_KICKIDLE&&!PreTranslateMessage(&m_msgCur)){::TranslateMessage(&m_msgCur);//鍵轉(zhuǎn)換::DispatchMessage(&m_msgCur);//派送消息}returnTRUE;}在這一步有一個特別重要的函數(shù)大家一定認(rèn)識:PreTranslateMessage。這個函數(shù)在::DispatchMessage發(fā)送消息到窗口之前,進(jìn)行對消息的預(yù)處理。PreTranslateMessage函數(shù)是CWinThread的成員函數(shù),大家重載的時候都是在View類或者主窗口類中,那么,它是怎么進(jìn)入別的類的呢?代碼如下://thrdcore.cppBOOLCWinThread::PreTranslateMessage(MSG*pMsg){ASSERT_VALID(this);//如果是線程消息,那么將會調(diào)用線程消息的處理函數(shù)if(pMsg->hwnd==NULL&&DispatchThreadMessageEx(pMsg))returnTRUE;//walkfromtargettomainwindowCWnd*pMainWnd=AfxGetMainWnd();if(CWnd::WalkPreTranslateTree(pMainWnd->GetSafeHwnd(),pMsg))returnTRUE;//incaseofmodelessdialogs,lastchanceroutethroughmain//window'sacceleratortableif(pMainWnd!=NULL){CWnd*pWnd=CWnd::FromHandle(pMsg->hwnd);if(pWnd->GetTopLevelParent()!=pMainWnd)returnpMainWnd->PreTranslateMessage(pMsg);}returnFALSE;//nospecialprocessing}由上面這個函數(shù)可以看出:第一,如果(pMsg->hwnd==NULL),說明這是一個線程消息。調(diào)用CWinThread::DispatchThreadMessageEx到消息映射表找到消息入口,然后調(diào)用消息處理函數(shù)。NOTE:一般用PostThreadMessage函數(shù)發(fā)送線程之間的消息,他和窗口消息不同,需要指定線程id,消息激被系統(tǒng)放入到目標(biāo)線程的消息隊列中;用ON_THREAD_MESSAGE(message,memberFxn)宏可以映射線程消息和他的處理函數(shù)。這個宏必須在應(yīng)用程序類(從CWinThread繼承)中,因為只有應(yīng)用程序類才處理線程消息。如果你在別的類(比如視圖類)中用這個宏,線程消息的消息處理函數(shù)將得不到線程消息。第二,消息的目標(biāo)窗口的PreTranslateMessage函數(shù)首先得到消息處理權(quán),如果函數(shù)返回FALSE,那么他的父窗口將得到消息的處理權(quán),直到主窗口;如果函數(shù)返回TRUE(表示消息已經(jīng)被處理了),那么就不需要調(diào)用父類的PreTranslateMessage函數(shù)。這樣,保證了消息的目標(biāo)窗口以及他的父窗口都可以有機(jī)會調(diào)用PreTranslateMessage--在消息發(fā)送到窗口之前進(jìn)行預(yù)處理(如果自己處理完然后返回FALSE的話-_-b),如果你想要消息不傳遞給父類進(jìn)行處理的話,返回TRUE就行了。第三,如果消息的目標(biāo)窗口和主窗口沒有父子關(guān)系,那么再調(diào)用主窗口的PreTranslateMessage函數(shù)。為什么這樣?由第二步知道,一個窗口的父窗口不是主窗口的話,盡管它的PreTranslateMessage返回FALSE,主窗口也沒有機(jī)會調(diào)用PreTranslateMessage函數(shù)。我們知道,加速鍵的轉(zhuǎn)換一般在框架窗口的PreTranslateMessage函數(shù)中。我找遍了MFC中關(guān)于加速鍵轉(zhuǎn)換的處理,只有CFrameWnd,CMDIFrameWnd,CMDIChildWnd等窗口類有。所以,第三步的意思是,如果消息的目標(biāo)窗口(他的父窗口不是主窗口,比如一個這樣的非模式對話框)使消息的預(yù)處理繼續(xù)漫游的話(他的PreTranslateMessage返回FALSE),那么給一次機(jī)會給主窗口調(diào)用PreTranslateMessage(萬一他是某個加速鍵消息呢?),這樣能夠保證在有非模式對話框的情況下還能保證主窗口的加速鍵好使。我做了一個小例子,在對話框類的PreTranslateMessage中,返回FALSE。在主窗口顯示這個非模式對話框,在對話框擁有焦點的時候,仍然能夠激活主窗口的快捷鍵??傊?,整個框架就是讓每個消息的目標(biāo)窗口(包括他的父窗口)都有機(jī)會參與消息到來之前的處理。呵呵~至此,非對話框的消息循環(huán)和消息泵的機(jī)制就差不多了。這個機(jī)制在一個無限循環(huán)中,不斷地從消息隊列中獲取消息,并且保證了程序的線程消息能夠得到機(jī)會處理,窗口消息在預(yù)處理之后被發(fā)送到相應(yīng)的窗口處理過程。那么,還有一點疑問,為什么要一會兒調(diào)用::PeekMessage,—會兒調(diào)用::GetMessage呢,他們有什么區(qū)別?NOTE:一般來說,GetMessage被設(shè)計用來高效地從消息隊列獲取消息。如果隊列中沒有消息,那么函數(shù)GetMessage將導(dǎo)致線程休眠(讓出CPU時間)。而PeekMessage是判斷消息隊列中如果沒有消息,它馬上返回0,不會導(dǎo)致線程處于睡眠狀態(tài)。在上面的phasel第一個內(nèi)循環(huán)中用到了PeekMessage,它的參數(shù)PM_NOREMOVE表示并不從消息隊列中移走消息,而是一個檢測查詢,如果消息隊列中沒有消息他立刻返回0,如果這時線程空閑的話將會引起消息循環(huán)調(diào)用OnIdle處理過程(上面講到了這個函數(shù)的重要性)。如果將::PeekMessage改成::GetMessage(***),那么如果消息隊列中沒有消息,線程將休眠,直到線程下一次獲得CPU時間并且有消息出現(xiàn)才可能繼續(xù)執(zhí)行,這樣,消息循環(huán)的空閑時間沒有得到應(yīng)用,OnIdle也將得不到執(zhí)行。這就是為什么既要用::PeekMessage(查詢),又要用::GetMessage(做實際的工作)的緣故。第二部分:對話框程序的消息循環(huán)機(jī)制基于對話框的MFC工程和上面的消息循環(huán)機(jī)制不一樣。實際上MFC的對話框工程程序就是模式對話框。他和上面講到的非對話框程序的不同之處,主要在于應(yīng)用程序?qū)ο蟮腎nitinstance()不一樣。//dlg_5Dlg.cppBOOLCDlg_5App::InitInstance(){AfxEnableControlContainer();#ifdef_AFXDLLEnable3dControls();//CallthiswhenusingMFCinasharedDLL#elseEnable3dControlsStatic();//CallthiswhenlinkingtoMFCstatically#endifCDlg_5Dlgdlg;//定義一個對話框?qū)ο髆_pMainWnd=&dlg;intnResponse=dlg.DoModal();//對話框的消息循環(huán)在這里面開始if(nResponse==IDOK){//TODO:Placecodeheretohandlewhenthedialogis//dismissedwithOK}elseif(nResponse==IDCANCEL){//TODO:Placecodeheretohandlewhenthedialogis//dismissedwithCancel}//Sincethedialoghasbeenclosed,returnFALSEsothatweexitthe//application,ratherthanstarttheapplication'smessagepump.returnFALSE;}NOTE:Initinstance函數(shù)返回FALSE,由最上面程序啟動流程可以看出,CWinThread::Run是不會得到執(zhí)行的。也就是說,上面第一部分說的消息循環(huán)在對話框中是不能執(zhí)行的。實際上,對話框也有消息循環(huán),她的消息循環(huán)在CDialog::DoModal()虛函數(shù)中的一個RunModalLoop函數(shù)中。這個函數(shù)的實現(xiàn)體在CWnd類中:intCWnd::RunModalLoop(DWORDdwFlags){ASSERT(::IsWindow(m_hWnd));//windowmustbecreatedASSERT(!(m_nFlags&WF_MODALLOOP));//windowmustnotalreadybeinmodalstate//fortrackingtheidletimestateBOOLbIdle=TRUE;LONGlIdleCount=0;BOOLbShowIdle=(dwFlags&MLF_SHOWONIDLE)&&!(GetStyle()&WS_VISIBLE);HWNDhWndParent=::GetParent(m_hWnd);m_nFlags|=(WF_MODALLOOP|WF_CONTINUEMODAL);MSG*pMsg=&AfxGetThread()->m_msgCur;//acquireanddispatchmessagesuntilthemodalstateisdonefor(;;){ASSERT(ContinueModal());//phase1:checktoseeifwecandoidleworkwhile(bIdle&&!::PeekMessage(pMsg,NULL,NULL,NULL,PM_NOREMOVE)){ASSERT(ContinueModal());//showthedialogwhenthemessagequeuegoesidleif(bShowIdle){ShowWindow(SW_SHOWNORMAL);UpdateWindow();bShowIdle=FALSE;}//callOnIdlewhileinbIdlestateif(!(dwFlags&MLF_NOIDLEMSG)&&hWndParent!=NULL&&lIdleCount==0){//sendWM_ENTERIDLEtotheparent::SendMessage(hWndParent,WM_ENTERIDLE,MSGF_DIALOGBOX,(LPARAM)m_hWnd);}if((dwFlags&MLF_NOKICKIDLE)||!SendMessage(WM_KICKIDLE,MSGF_DIALOGBOX,lIdleCount++)){//stopidleprocessingnexttimebIdle=FALSE;}}//phase2:pumpmessageswhileavailabledo{ASSERT(ContinueModal());//pumpmessage,butquitonWM_QUIT//PumpMessage(消息泵)的實現(xiàn)和上面講的差不多。都是派送消息到窗口。if(!AfxGetThread()->PumpMessage()){AfxPostQuitMessage(0);return-1;}//showthewindowwhencertainspecialmessagesrec'dif(bShowIdle&&(pMsg->message==0x118||pMsg->message==WM_SYSKEYDOWN)){ShowWindow(SW_SHOWNORMAL);UpdateWindow();bShowIdle=FALSE;}if(!ContinueModal())gotoExitModal;//reset"noidle"stateafterpumping"normal"messageif(AfxGetThread()->IsIdleMessage(pMsg)){bIdle=TRUE;lIdleCount=0;}}while(::PeekMessage(pMsg,NULL,NULL,NULL,PM_NOREMOVE));}//無限循環(huán)ExitModal:m_nFlags&=~(WF_MODALLOOP|WF_CONTINUEMODAL);returnm_nModalResult;}先說說怎么退出這個無限循環(huán),在代碼中:if(!ContinueModal())gotoExitModal;決定是否退出循環(huán),消息循環(huán)函數(shù)返回也就是快要結(jié)束結(jié)束程序了。BOOLCWnd::ContinueModal(){returnm_nFlags&WF_CONTINUEMODAL;}NOTE:CWnd::ContinueModal()函數(shù)檢查對話框是否繼續(xù)模式。返回TRUE,表示現(xiàn)在是模式的;返回FALSE,表示對話框已經(jīng)不是模式(將要結(jié)束)。如果要結(jié)束對話框,在內(nèi)部最終會調(diào)用函數(shù)CWnd::EndModalLoop,它取消m_nFlags的模式標(biāo)志(消息循環(huán)中的ContinueModal函數(shù)將返回FALSE,消息循環(huán)將結(jié)束,程序?qū)⑼顺?;然后激發(fā)消息循環(huán)讀取消息。也就是說,結(jié)束模式對話框是一個標(biāo)志,改變這個標(biāo)志就可以了。他的代碼是://wincore.cppvoidCWnd::EndModalLoop(intnResult){ASSERT(::IsWindow(m_hWnd));//thisresultwillbereturnedfromCWnd::RunModalLoopm_nModalResult=nResult;//makesureamessagegoesthroughtoexitthemodalloopif(m_nFlags&WF_CONTINUEMODAL){m_nFlags&=~WF_CONTINUEMODAL;PostMessage(WM_NULL);}}NOTE:PostMessage(NULL)是有用的。如果消息隊列中沒有消息的話,可能消息循環(huán)中的ContinueModalO不會馬上執(zhí)行,發(fā)送一個空消息是激發(fā)消息循環(huán)馬上工作。下面說一下CWnd::RunModalLoop函數(shù)中的消息循環(huán)究竟干了些什么事情:1,第一個內(nèi)循環(huán)。首先從消息隊列中查詢消息,如果對話框空閑,而且消息隊列中沒有消息,他做三件事情,大家應(yīng)到都能從字面上明白什么意思。最重要的是發(fā)送WM_KICKIDLE消息。為什么呢?第一部分講到了,非對話框程序用OnIdle來更新用戶界面(UI),比如工具欄,狀態(tài)欄。那么,如果對話框中也有工具欄和狀態(tài)欄呢,在哪里更新(網(wǎng)上有很多這樣的程序)?可以處理WM_KICKIDLE消息:LRESULTCDlg_5Dlg::OnKickIdle(WPARAMw,LPARAMl){//調(diào)用CWnd::UpdateDialogControls更新用戶界面UpdateDialogControls(this,TRUE);return0;}NOTE:CWnd::UpdateDialog函數(shù)發(fā)送CN_UPDATE_COMMAND_UI消息給所有的用戶界面對話框控件。2,第二個內(nèi)循環(huán)。最重要的還是PumpMessage派送消息到目標(biāo)窗口。其他的,像第二個if語句,0x118消息好像是WM_SYSTIMER消息(系統(tǒng)用來通知光標(biāo)跳動的一個消息)。也就是說,如果消息為WM_SYSTIMER或者WM_SYSKEYDOWN,并且空閑顯示標(biāo)志為真的話,就顯示窗口并通知窗口立刻重繪??傊?,對話框的消息循環(huán)機(jī)制和非對話框(比如SDI,MDI)還是類似的,僅僅側(cè)重點不同。模式對話框是模式顯示,自然有他的特點。下面部分討論一下模式對話框和非模式對話框的區(qū)別。因為模式對話框有自己的特殊消息循環(huán);而非模式對話框,共用程序的消息循環(huán),和普通的窗口已經(jīng)沒有什么大的區(qū)別了。第三部分:模式對話框和非模式對話框的區(qū)別這個話題已經(jīng)有很多人討論,我說說我所理解的意思。在MFC框架中,一個對話框?qū)ο驞oModal一下就能產(chǎn)生一個模式對話框,Create一下就能產(chǎn)生一個非模式對話框。實際上,無論是模式對話框還是非模式對話框,在MFC內(nèi)部都是調(diào)用::CreateDialoglndirect(***)函數(shù)來創(chuàng)建非模式對話框。只是模式對話框作了更多的工作,包括使父窗口無效,然后進(jìn)入自己的消息循環(huán)等等。::CreateDialoglndirect(***)函數(shù)最終調(diào)用CreateWindowEx函數(shù)通知系統(tǒng)創(chuàng)建窗體并返回句柄,他內(nèi)部沒有實現(xiàn)自己的消息循環(huán)。非模式對話框創(chuàng)建之后立即返回,并且和主程序共用一個消息循環(huán)。非模式對話框要等對話框結(jié)束之后才返回,自己有消息循環(huán)。比如下面的代碼:CMyDlg*pdlg=newCMyDlg;pdlg->Create(IDD_DIALOG1);pdlg->ShowWindow(SW_SHOW);MessageBox("abc");非模式對話框和消息框MessageBox幾乎是同時彈出來。而如果將Create改成DoModal,那么,只能彈出模式對話框,在關(guān)閉了對話框之后(模式對話框自己的消息循環(huán)結(jié)束),消息框才彈出來。NOTE:可以在模式對話框中調(diào)用GetParent()->EnableWindow(true);這樣,主窗口的菜單,工具欄又激活了,能用了。MFC使用非模式對話框來模擬模式對話框,而在Win32SDK程序中,模式對話框激發(fā)他的父窗口Enable操作是沒有效果的。關(guān)于消息循環(huán)總結(jié):1,我們站在一個什么高度看消息循環(huán)?消息循環(huán)其實沒有什么深奧的道理。如果一個郵遞員要不斷在一個城市中送信,我們要求他做什么?要求他來回跑,但他一次只能在一個地方出現(xiàn)。如果我們的應(yīng)用程序只有一個線程的話,我們要他不斷地為窗口傳遞消息,我們怎么做?在一個循環(huán)中不斷的檢測消息,并將他發(fā)送到適當(dāng)?shù)拇翱?。窗口可以有很多個,但消息循環(huán)只有一個,而且每時每刻最多只有一個地方在執(zhí)行代碼。為什么?看第二點。2,因為是單線程的(程序進(jìn)程啟動的時候,只有而且有一個線程,我們稱他為主線程),所以就像郵遞員一樣,每次只能在某一個地方干活。什么意思呢?舉個例子,用::DiapatchMessage派送消息,在窗口處理過程(WinProc,窗口函數(shù))返回之前,他是阻塞的,不會立即返回,也就是消息循環(huán)此時不能再從消息隊列中讀取消息,直到::DispatchMessage返回。如果你在窗口函數(shù)中執(zhí)行一個死循環(huán)操作,就算你用PostQuitMessage函數(shù)退出,程序也會down掉。while(1){PostQuitMessage(O);//程序照樣down.}所以,當(dāng)窗口函數(shù)處理沒有返回的時候,消息循環(huán)是不會從消息隊列中讀取消息的。這也是為什么在模式對話框中要自己用無限循環(huán)來繼續(xù)消息循環(huán),因為這個無限循環(huán)阻塞了原來的消息循環(huán),所以,在這個無限循環(huán)中要用GetMessage,PeekMessage,DispatchMessage來從消息隊列中讀取消息并派送消息了。要不然程序就不會響應(yīng)了,這不是我們所希望的。所以說,消息循環(huán)放在程序的什么的地方都基本上是過的去的,比如放在DLL里面。但是,最好在任何時候,只有一個消息循環(huán)在工作(其他的都被阻塞了)。然后,我們要作好的一件事情,就是怎么從消息循環(huán)中退出!當(dāng)然用WM_QUIT是可以拉~(PostThreadMessage也是個好主意),這個消息循環(huán)退出后,可能程序退出,也可能會激活另外一個被阻塞的消息循環(huán),程序繼續(xù)運(yùn)行。這要看你怎么想,怎么去做。最后一個消息循環(huán)結(jié)束的時候,也許就是程序快結(jié)束的時候,因為主線程的執(zhí)行代碼也快要完了(除非BT的再作個死循環(huán))。NOTE:讓windows系統(tǒng)知道創(chuàng)建一個線程的唯一方法是調(diào)用APICreatThread函數(shù)(__beginthreadex之類的都要在內(nèi)部調(diào)用他創(chuàng)建新線程)。好像windows核心編程說,在win2000下,系統(tǒng)用CreateRemoteThread函數(shù)來創(chuàng)建線程,CreateThread在內(nèi)部調(diào)用CreateRemoteThread。不過這不是爭論的焦點,至少win98下CreateRemoteThread并不能正常工作,還是CreateThread主持大局。3,在整個消息循環(huán)的機(jī)制中,還必須談到窗口函數(shù)的可重入性。什么意思?就是窗口函數(shù)(他是個回調(diào)函數(shù))的代碼什么時候都可以被系統(tǒng)(調(diào)用者一般是user32模塊)調(diào)用。比如在窗口過程中,向自己的窗口SendMessage(***);那么執(zhí)行過程是怎樣的?我們知道,SendMessage是要等到消息發(fā)送并被目標(biāo)窗口執(zhí)行完之后才返回的。那么窗口在處理消息,然后又等待剛才發(fā)送到本窗口的消息被處理后之后(SendMessage返回)才繼續(xù)往下執(zhí)行,程序不就互相死鎖了嗎?其實是不會的。windows設(shè)計一套適合SendMessage的算法,他判斷如果發(fā)送的消息是屬于本線程創(chuàng)建的窗口的,那么直接由user32模塊調(diào)用窗口函數(shù)(可能就有窗口重入),并將消息的處理結(jié)果結(jié)果返回。這樣做體現(xiàn)了窗口重入。上面的例子,我們調(diào)用SendMessage(***)發(fā)送消息到本窗口,那么窗口過程再次被調(diào)用,處理完消息之后將結(jié)果返回,然后SendMessage之后的程序接著執(zhí)行。對于非隊列消息,如果沒有窗口重入,不知道會是什么樣子。NOTE:由于窗口的可重入
溫馨提示
- 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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 入駐培訓(xùn)機(jī)構(gòu)協(xié)議合同范本
- 2025年動態(tài)計量秤項目可行性研究報告
- 2025至2030年中國生物解剖室數(shù)據(jù)監(jiān)測研究報告
- 2025至2030年病人極板項目投資價值分析報告
- 2025至2030年中國EVA壓紋鼠標(biāo)墊數(shù)據(jù)監(jiān)測研究報告
- 2025年度辦公室裝修與室內(nèi)空氣凈化設(shè)備采購合同
- 2025至2030年全自動單面淋膜紙碗機(jī)項目投資價值分析報告
- 2025至2030年醫(yī)院專用殺菌消毒劑項目投資價值分析報告
- 2025年北京健身俱樂部教練職業(yè)培訓(xùn)與聘用一體化合同
- 2025年中國三環(huán)過山車市場調(diào)查研究報告
- 商業(yè)與公積金貸款政策
- 年獸的故事之The Legend of Nian
- 初中美術(shù)教學(xué)策略與方法
- 甲流護(hù)理查房病例
- 概率論與數(shù)理統(tǒng)計智慧樹知到課后章節(jié)答案2023年下四川師范大學(xué)
- 2024屆高考作文主題訓(xùn)練:時評類(含解析)
- 260噸汽車吊地基承載力驗算
- 譯林版英語小學(xué)四年級下冊-課文翻譯(英漢對照)
- Vue.js前端開發(fā)實戰(zhàn)(第2版)全套完整教學(xué)課件
- 公司與個人合伙買車經(jīng)營協(xié)議書
- 企業(yè)更名通知函
評論
0/150
提交評論