中文字幕 另类精品,亚洲欧美一区二区蜜桃,日本在线精品视频免费,孩交精品乱子片免费

<sup id="3hn2b"></sup>

    1. <sub id="3hn2b"><ol id="3hn2b"></ol></sub><legend id="3hn2b"></legend>

      1. <xmp id="3hn2b"></xmp>

      2. 新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > 深入剖析MFC中Windows消息處理機制

        深入剖析MFC中Windows消息處理機制

        作者: 時間:2007-05-11 來源:網(wǎng)絡 收藏
          Windows程序和DOS程序的主要不同點之一是:Windows程序是以事件為驅(qū)動、為基礎

          本人對Windows系統(tǒng)、MFC談不上有深入的了解,但對MFC本身包裝API的機制很有興趣,特別是讀了候老師的《深入淺出MFC》后,感覺到Visual C++的Application FrameWork十分精制。在以前,我對SDI結構處理消息有一定的認識,但對于模式對話框的不了解,讀了《深入》一書也沒能得到解決,近日,通過在網(wǎng)友的幫助和查閱MSDN,自認為已經(jīng)了解。一時興起,寫下這些文字,沒有其它目的,只是希望讓后來者少走彎路,也希望和我一樣 喜歡“鉆牛角尖”的人共同討論、學習。如果你是牛人,那么你現(xiàn)在要慎重考慮有沒有充足的時間讀這些幼稚文字。

          正文:

          Windows程序和DOS程序的主要不同點之一是:Windows程序是以事件為驅(qū)動、為基礎。如何理解?

          舉了例子,當你CLICK Windows “開始”BUTTON時,為什么就會彈出一個菜單呢?

          當你單擊鼠標左鍵時,操作系統(tǒng)中與MOUSE相關的驅(qū)動程序在第一時間內(nèi)得到這個信號[LBUTTONDOWN],然后它通知操作系統(tǒng)―――“嗨,鼠標左鍵被單擊了!”,操作系統(tǒng)得到這一信號后,馬上要判斷――用戶單擊鼠標左鍵,這是針對哪個窗口呢?如何判斷?這很簡單!當前狀態(tài)中,具有焦點的窗口[或控件]就是了[這里當然是“開始”BUTTON了]。然后操作系統(tǒng)馬上向這個窗口發(fā)送一條消息到這個窗口所在進程的消息隊列,消息內(nèi)容應是消息本身的代號、附加參數(shù)、窗口句柄…等等了。那么,只有操作系統(tǒng)才有資格發(fā)送消息至某一窗口的消息隊列嗎?不然,其它程序也有資格。你可以在你的程序中調(diào)用:SendMessage、PostMessage。這樣,被單擊的窗口得到了一條由操作系統(tǒng)發(fā)送的包含CLICK的消息,操作系統(tǒng)已經(jīng)暫時不再管窗口的任何事,因為它還要忙于處理其它事務。你的程序得到一條消息后如何做呢?Windows對于你在“開始”BUTTON上的單擊事件做出如下反映:彈出一菜單??墒牵玫较⒌阶龀龇从尺@一過程是如何實現(xiàn)的呢?這就是本文討論的主要內(nèi)容[當然只是針對MFC了]。

          我首先簡要談一下SDI,然后會花更多文字描述模式對話框。

          對于SDI窗口,你的應用程序類的InitInstance()大約如下:

        BOOL CEx06aApp::InitInstance()
        {
          ……………
         CSingleDocTemplate* pDocTemplate;
         pDocTemplate = new CSingleDocTemplate(
          IDR_MAINFRAME,
          RUNTIME_CLASS(CEx06aDoc),
          RUNTIME_CLASS(CMainFrame), // main SDI frame window
          RUNTIME_CLASS(CEx06aView));
         AddDocTemplate(pDocTemplate);
         CCommandLineInfo cmdInfo;
         ParseCommandLine(cmdInfo);
         if (!ProcessShellCommand(cmdInfo))
          return FALSE;
         m_pMainWnd->ShowWindow(SW_SHOW);
         m_pMainWnd->UpdateWindow();
         return TRUE;
        }

          完成一些如動態(tài)生成相關文檔、視,顯示主框架窗口、處理參數(shù)行信息等工作。這些都是顯示在你工程中的“明碼”。我們現(xiàn)在把斷點設置到return TRUE;一句,跟入MFC源碼中,看看到底MFC內(nèi)部做了什么。

          程序進入SRCWinMain.cpp,下一個大動作應是:

        nReturnCode = pThread->Run();

          注意了,重點來了。F11進入

        int CWinApp::Run()
        {
         if (m_pMainWnd == NULL AfxOleGetUserCtrl())
         {
          // Not launched /Embedding or /Automation, but has no main window!
          TRACE0(Warning: m_pMainWnd is NULL in CWinApp::Run - quitting application. );
          AfxPostQuitMessage(0);
         }
         return CWinThread::Run();
        }

          再次F11進入:

        int CWinThread::Run()
        {
         ASSERT_VALID(this);

         // for tracking the idle time state
         BOOL bIdle = TRUE;
         LONG lIdleCount = 0;

         // acquire and dispatch messages until a WM_QUIT message is received.
         for (;;)
         {
          // phase1: check to see if we can do idle work
          while (bIdle !::PeekMessage(m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
          {
           // call OnIdle while in bIdle state
           if (!OnIdle(lIdleCount++))
           bIdle = FALSE; // assume no idle state
          }

          // phase2: pump messages while available
          do
          {
           // pump message, but quit on WM_QUIT
           if (!PumpMessage())
            return ExitInstance();

           // reset no idle state after pumping normal message
           if (IsIdleMessage(m_msgCur))
           {
            bIdle = TRUE;
            lIdleCount = 0;
           }

          } while (::PeekMessage(m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
         }

         ASSERT(FALSE); // not reachable
        }

        BOOL CWinThread::IsIdleMessage(MSG* pMsg)
        {
         // Return FALSE if the message just dispatched should _not_
         // cause OnIdle to be run. Messages which do not usually
         // affect the state of the user interface and happen very
         // often are checked for.

         // redundant WM_MOUSEMOVE and WM_NCMOUSEMOVE
         if (pMsg->message == WM_MOUSEMOVE || pMsg->message == WM_NCMOUSEMOVE)
         {
          // mouse move at same position as last mouse move?
          if (m_ptCursorLast == pMsg->pt pMsg->message == m_nMsgLast)
           return FALSE;

          m_ptCursorLast = pMsg->pt; // remember for next time
          m_nMsgLast = pMsg->message;
          return TRUE;
         }

         // WM_PAINT and WM_SYSTIMER (caret blink)
         return pMsg->message != WM_PAINT pMsg->message != 0x0118;
        }

          這是SDI處理消息的中心機構,但請注意,它覺對不是核心!

          分析一下,在無限循環(huán)FOR內(nèi)部又出現(xiàn)一個WHILE循環(huán)

        while (bIdle
        !::PeekMessage(m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
        {
         // call OnIdle while in bIdle state
         if (!OnIdle(lIdleCount++))
          bIdle = FALSE; // assume no idle state
        }

          這段代碼是當你程序進程的消息隊列中沒有消息時,會調(diào)用OnIdle做一些后備工作,臨時對象在這里被刪除。當然它是虛函數(shù)。其中的PeekMessage,是查看消息隊列,如果有消息返回TRUE,如果沒有消息返回FALSE,這里指定PM_NOREMOVE,是指查看過后不移走消息隊列中剛剛被查看
        到的消息,也就是說這里的PeekMessage只起到一個檢測作用,顯然返回FALSE時[即沒有消息],才會進入循環(huán)內(nèi)部,執(zhí)行OnIdle,當然了,你的OnIdle返回FLASE,會讓程序不再執(zhí)行OnIdle。你可能要問:

        當bidle=0或消息隊例中有消息時,程序又執(zhí)行到哪了呢?

        do
        {
         // pump message, but quit on WM_QUIT
         if (!PumpMessage())
          return ExitInstance();

         // reset no idle state after pumping normal message
         if (IsIdleMessage(m_msgCur))
         {
          bIdle = TRUE;
          lIdleCount = 0;
         }

        } while (::PeekMessage(m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));

          看啊,又進入一個循環(huán)!

          其中有個重要的函數(shù),PumpMessage,內(nèi)容如下:

        BOOL CWinThread::PumpMessage()
        {
         ASSERT_VALID(this);

         if (!::GetMessage(m_msgCur, NULL, NULL, NULL))
         {
          #ifdef _DEBUG
          if (afxTraceFlags traceAppMsg)
           TRACE0(CWinThread::PumpMessage - Received WM_QUIT. );
           m_nDisablePumpCount++; // application must die
           // Note: prevents calling message loop things in ’ExitInstance’
           // will never be decremented
          #endif
          return FALSE;
         }

         #ifdef _DEBUG
         if (m_nDisablePumpCount != 0)
         {
          TRACE0(Error: CWinThread::PumpMessage called when not permitted. );
          ASSERT(FALSE);
         }
         #endif

         #ifdef _DEBUG
         if (afxTraceFlags traceAppMsg)
          _AfxTraceMsg(_T(PumpMessage), m_msgCur);
         #endif

         // process this message

         if (m_msgCur.message != WM_KICKIDLE !PreTranslateMessage(m_msgCur))
         {
          ::TranslateMessage(m_msgCur);
          ::DispatchMessage(m_msgCur);
         }
         return TRUE;
        }

          如你所想,這才是MFC消息處理的核心基地[也是我個人認為的]。

          GetMessage不同于PeekMessae,它是不得到消息不罷體,PeekMessage如果發(fā)現(xiàn)消息隊列中沒有消息會返回0,而GetMessage如果發(fā)現(xiàn)沒有消息,等,直到有了消息,而且,GetMessage不同于PeekMessage,它會將消息移走[當然,PeekMessage也可以做到這點]。我想當你讀了這個函數(shù)后,
        你應明白PreTranslateMessage函數(shù)的用法了吧[我比較喜歡在程序中充分利用這個函數(shù)]。

        ::TranslateMessage(m_msgCur);
        ::DispatchMessage(m_msgCur);

          將消息發(fā)送到窗口的處理函數(shù)[它是由窗口類指定的],之后的動作一直到你的程序做出反映的過程,你可以在《深入》一書中得到完美的解釋。我們還是通過reurn
        TRUE;回到CWinThread::Run()中的Do{}while;循環(huán)。然后還是對IDLE的處理,即便剛才你的ONIDLE返回了FALSE,在這里你看到,你的程序還是有機會執(zhí)行它的。然后又是利用PeekMessage檢測消息隊列:

          如果有消息[這個消息不被移動的原因是因為它要為PumpMessage內(nèi)的GetMessage所利用。]再次進入PumpMessage[叫它“消息泵”吧]。

          如果沒有消息,退出DO循環(huán),但它還在FOR內(nèi)部,所以又執(zhí)行第一個While循環(huán)。

          這是CwinThread::Run的一個執(zhí)行過程。

          不用擔心退不出for(;;)如果你的消息隊列中有一條WM_QUIT,會使GetMessage返回0,然后PumpMessage返回0而RUN()內(nèi)部:

        if (!PumpMessage())
        return ExitInstance();

          SDI就說到這,下面我來談一下模式對話框。我分2種情況討論:

          一當你的工程以模式對話框為基礎時[沒父窗口,或為桌面]。

          與SDI不同處在于,在應用程序類的InItInstance內(nèi)部:

        BOOL CComboBoxApp::InitInstance()
        {
         AfxEnableControlContainer();
         // Standard initialization
         // If you are not using these features and wish to reduce the size
         // of your final executable, you should remove from the following
         // the specific initialization routines you do not need.
         #ifdef _AFXDLL
          Enable3dControls(); // Call this when using MFC in a shared DLL
         #else
          Enable3dControlsStatic(); // Call this when linking to MFC statically
         #endif
         this->m_nCmdShow = SW_HIDE;
         CComboBoxDlg dlg;
         m_pMainWnd = dlg;
         int nResponse = dlg.DoModal();
         if (nResponse == IDOK)
         {
          // TODO: Place code here to handle when the dialog is
          // dismissed with OK
         }
         else if (nResponse == IDCANCEL)
         {
          // TODO: Place code here to handle when the dialog is
          // dismissed with Cancel
         }
         // Since the dialog has been closed, return FALSE so that we exit the
         // application, rather than start the application’s message pump.
         return FALSE;
        }

          int nResponse = dlg.DoModal();一句使你的整個程序都在DoModal()內(nèi)部進行。而且,你退出DoMal()時[你一定結束了你的對話框],InitInstance返回的是False,我們知道,這樣,CwinThread::Run是不會執(zhí)行的。

          但對話框程序是在哪里進行消息處理的呢。

          原來,dlg.DoModal()內(nèi)部會調(diào)用CwinThread::RunModalLoop,它起到的作用和RUN()是一樣的[當然內(nèi)部有細小差別,請參考MSDN]!!!

          第二種情況,你是在SDI[或其它]程序中調(diào)用Dlg.DoModal() 產(chǎn)生了一模式對話框[有父窗口].

          這又是如何運作的呢?

          建了這樣一個工程做為例子。

          SDI,在View中處理LBUTTONDOWN:

        MyDLg.DoModal();

          MyDLg內(nèi)有按鈕,以憊后用.

          沒有顯示模式對話框前,消息處理一直在Cthread::Run()中進行.

          你單擊后,程序執(zhí)行點進入DoModal()內(nèi)部的RunModalLoop,這又是一個消息處理機制.

          不過DoModal()中調(diào)用RunModalLoop,前會Disable掉它的父窗口.從RunModalLoop中出來后,再 Enable它.

          模式對話框和非模式對話框都是通過調(diào)用CreateDialogIndirect()產(chǎn)生創(chuàng)建對話框.那它和非模式對話框區(qū)別是什么造成的呢?

          1 模式對話框?qū)⒏复翱贒ISABLE掉.

          我原以為被Disable的窗口是不接收消息的.但后來我馬上發(fā)現(xiàn)我是錯的.但,為什么你對被Disable的窗口進行KeyBorad,Mouse動作時,窗口沒反映呢,我想,這可能是操作系統(tǒng)從中搞的鬼.我在本文一開始,就寫出操作系統(tǒng)向窗口發(fā)送消息的過程,我想當它發(fā)現(xiàn)目標窗口處理Disabled狀態(tài)時,
        不會將消息發(fā)送給它,但這不能說窗口不接收消息,其它程序[或它本身]發(fā)送給它的消息還是可以接收并處理的.

          2 模式對話框本身有消息處理機制 RunModalLoop.

          對以上兩點加以實驗.

          我在我的剛才建的項目中的模式對話框中加上一個BUTTON,其中加入如下代碼:

        OnButton1()
        {
         GetParaent()->EnableWindow(1);
        }

          單擊,后我們發(fā)現(xiàn),此時它已經(jīng)不再表現(xiàn)為”模態(tài)”,我試著點擊菜單,還是會作出正常反映.

          我想這此消息[對于父窗口的,如:菜單動作]的處理也應是在模式對話框中的RunModalLoop中進行處理的吧[這點我不能確定].
        Windows程序和DOS程序的主要不同點之一是:Windows程序是以事件為驅(qū)動、消息機制為基礎

          本人對Windows系統(tǒng)、MFC談不上有深入的了解,但對MFC本身包裝API的機制很有興趣,特別是讀了候老師的《深入淺出MFC》后,感覺到Visual C++的Application
        FrameWork十分精制。在以前,我對SDI結構處理消息有一定的認識,但對于模式對話框的消息機制不了解,讀了《深入》一書也沒能得到解決,近日,通過在網(wǎng)友的幫助和查閱MSDN,自認為已經(jīng)了解。一時興起,寫下這些文字,沒有其它目的,只是希望讓后來者少走彎路,也希望和我一樣
        喜歡“鉆牛角尖”的人共同討論、學習。如果你是牛人,那么你現(xiàn)在要慎重考慮有沒有充足的時間讀這些幼稚文字。

          正文:

          Windows程序和DOS程序的主要不同點之一是:Windows程序是以事件為驅(qū)動、消息機制為基礎。如何理解?

          舉了例子,當你CLICK Windows “開始”BUTTON時,為什么就會彈出一個菜單呢?

          當你單擊鼠標左鍵時,操作系統(tǒng)中與MOUSE相關的驅(qū)動程序在第一時間內(nèi)得到這個信號[LBUTTONDOWN],然后它通知操作系統(tǒng)―――“嗨,鼠標左鍵被單擊了!”,操作系統(tǒng)得到這一信號后,馬上要判斷――用戶單擊鼠標左鍵,這是針對哪個窗口呢?如何判斷?這很簡單!當前狀態(tài)中
        ,具有焦點的窗口[或控件]就是了[這里當然是“開始”BUTTON了]。然后操作系統(tǒng)馬上向這個窗口發(fā)送一條消息到這個窗口所在進程的消息隊列,消息內(nèi)容應是消息本身的代號、附加參數(shù)、窗口句柄…等等了。那么,只有操作系統(tǒng)才有資格發(fā)送消息至某一窗口的消息隊列嗎?不然,其
        它程序也有資格。你可以在你的程序中調(diào)用:SendMessage
        、PostMessage。這樣,被單擊的窗口得到了一條由操作系統(tǒng)發(fā)送的包含CLICK的消息,操作系統(tǒng)已經(jīng)暫時不再管窗口的任何事,因為它還要忙于處理其它事務。你的程序得到一條消息后如何做呢?Windows對于你在“開始”BUTTON上的單擊事件做出如下反映:彈出一菜單??墒?,得到消息
        到做出反映這一過程是如何實現(xiàn)的呢?這就是本文討論的主要內(nèi)容[當然只是針對MFC了]。

          我首先簡要談一下SDI,然后會花更多文字描述模式對話框。

          對于SDI窗口,你的應用程序類的InitInstance()大約如下:

        BOOL CEx06aApp::InitInstance()
        {
          ……………
         CSingleDocTemplate* pDocTemplate;
         pDocTemplate = new CSingleDocTemplate(
          IDR_MAINFRAME,
          RUNTIME_CLASS(CEx06aDoc),
          RUNTIME_CLASS(CMainFrame), // main SDI frame window
          RUNTIME_CLASS(CEx06aView));
         AddDocTemplate(pDocTemplate);
         CCommandLineInfo cmdInfo;
         ParseCommandLine(cmdInfo);
         if (!ProcessShellCommand(cmdInfo))
          return FALSE;
         m_pMainWnd->ShowWindow(SW_SHOW);
         m_pMainWnd->UpdateWindow();
         return TRUE;
        }

          完成一些如動態(tài)生成相關文檔、視,顯示主框架窗口、處理參數(shù)行信息等工作。這些都是顯示在你工程中的“明碼”。我們現(xiàn)在把斷點設置到return TRUE;一句,跟入MFC源碼中,看看到底MFC內(nèi)部做了什么。

          程序進入SRCWinMain.cpp,下一個大動作應是:

        nReturnCode = pThread->Run();

          注意了,重點來了。F11進入

        int CWinApp::Run()
        {
         if (m_pMainWnd == NULL AfxOleGetUserCtrl())
         {
          // Not launched /Embedding or /Automation, but has no main window!
          TRACE0(Warning: m_pMainWnd is NULL in CWinApp::Run - quitting application. );
          AfxPostQuitMessage(0);
         }
         return CWinThread::Run();
        }

          再次F11進入:

        int CWinThread::Run()
        {
         ASSERT_VALID(this);

         // for tracking the idle time state
         BOOL bIdle = TRUE;
         LONG lIdleCount = 0;

         // acquire and dispatch messages until a WM_QUIT message is received.
         for (;;)
         {
          // phase1: check to see if we can do idle work
          while (bIdle !::PeekMessage(m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
          {
           // call OnIdle while in bIdle state
           if (!OnIdle(lIdleCount++))
           bIdle = FALSE; // assume no idle state
          }

          // phase2: pump messages while available
          do
          {
           // pump message, but quit on WM_QUIT
           if (!PumpMessage())
            return ExitInstance();

           // reset no idle state after pumping normal message
           if (IsIdleMessage(m_msgCur))
           {
            bIdle = TRUE;
            lIdleCount = 0;
           }

          } while (::PeekMessage(m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
         }

         ASSERT(FALSE); // not reachable
        }

        BOOL CWinThread::IsIdleMessage(MSG* pMsg)
        {
         // Return FALSE if the message just dispatched should _not_
         // cause OnIdle to be run. Messages which do not usually
         // affect the state of the user interface and happen very
         // often are checked for.

         // redundant WM_MOUSEMOVE and WM_NCMOUSEMOVE
         if (pMsg->message == WM_MOUSEMOVE || pMsg->message == WM_NCMOUSEMOVE)
         {
          // mouse move at same position as last mouse move?
          if (m_ptCursorLast == pMsg->pt pMsg->message == m_nMsgLast)
           return FALSE;

          m_ptCursorLast = pMsg->pt; // remember for next time
          m_nMsgLast = pMsg->message;
          return TRUE;
         }

         // WM_PAINT and WM_SYSTIMER (caret blink)
         return pMsg->message != WM_PAINT pMsg->message != 0x0118;
        }

          這是SDI處理消息的中心機構,但請注意,它覺對不是核心!

          分析一下,在無限循環(huán)FOR內(nèi)部又出現(xiàn)一個WHILE循環(huán)

        while (bIdle
        !::PeekMessage(m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
        {
         // call OnIdle while in bIdle state
         if (!OnIdle(lIdleCount++))
          bIdle = FALSE; // assume no idle state
        }

          這段代碼是當你程序進程的消息隊列中沒有消息時,會調(diào)用OnIdle做一些后備工作,臨時對象在這里被刪除。當然它是虛函數(shù)。其中的PeekMessage,是查看消息隊列,如果有消息返回TRUE,如果沒有消息返回FALSE,這里指定PM_NOREMOVE,是指查看過后不移走消息隊列中剛剛被查看
        到的消息,也就是說這里的PeekMessage只起到一個檢測作用,顯然返回FALSE時[即沒有消息],才會進入循環(huán)內(nèi)部,執(zhí)行OnIdle,當然了,你的OnIdle返回FLASE,會讓程序不再執(zhí)行OnIdle。你可能要問:

        當bidle=0或消息隊例中有消息時,程序又執(zhí)行到哪了呢?

        do
        {
         // pump message, but quit on WM_QUIT
         if (!PumpMessage())
          return ExitInstance();

         // reset no idle state after pumping normal message
         if (IsIdleMessage(m_msgCur))
         {
          bIdle = TRUE;
          lIdleCount = 0;
         }

        } while (::PeekMessage(m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));

          看啊,又進入一個循環(huán)!

          其中有個重要的函數(shù),PumpMessage,內(nèi)容如下:

        BOOL CWinThread::PumpMessage()
        {
         ASSERT_VALID(this);

         if (!::GetMessage(m_msgCur, NULL, NULL, NULL))
         {
          #ifdef _DEBUG
          if (afxTraceFlags traceAppMsg)
           TRACE0(CWinThread::PumpMessage - Received WM_QUIT. );
           m_nDisablePumpCount++; // application must die
           // Note: prevents calling message loop things in ’ExitInstance’
           // will never be decremented
          #endif
          return FALSE;
         }

         #ifdef _DEBUG
         if (m_nDisablePumpCount != 0)
         {
          TRACE0(Error: CWinThread::PumpMessage called when not permitted. );
          ASSERT(FALSE);
         }
         #endif

         #ifdef _DEBUG
         if (afxTraceFlags traceAppMsg)
          _AfxTraceMsg(_T(PumpMessage), m_msgCur);
         #endif

         // process this message

         if (m_msgCur.message != WM_KICKIDLE !PreTranslateMessage(m_msgCur))
         {
          ::TranslateMessage(m_msgCur);
          ::DispatchMessage(m_msgCur);
         }
         return TRUE;
        }

          如你所想,這才是MFC消息處理的核心基地[也是我個人認為的]。

          GetMessage不同于PeekMessae,它是不得到消息不罷體,PeekMessage如果發(fā)現(xiàn)消息隊列中沒有消息會返回0,而GetMessage如果發(fā)現(xiàn)沒有消息,等,直到有了消息,而且,GetMessage不同于PeekMessage,它會將消息移走[當然,PeekMessage也可以做到這點]。我想當你讀了這個函數(shù)后,
        你應明白PreTranslateMessage函數(shù)的用法了吧[我比較喜歡在程序中充分利用這個函數(shù)]。

        ::TranslateMessage(m_msgCur);
        ::DispatchMessage(m_msgCur);

          將消息發(fā)送到窗口的處理函數(shù)[它是由窗口類指定的],之后的動作一直到你的程序做出反映的過程,你可以在《深入》一書中得到完美的解釋。我們還是通過reurn
        TRUE;回到CWinThread::Run()中的Do{}while;循環(huán)。然后還是對IDLE的處理,即便剛才你的ONIDLE返回了FALSE,在這里你看到,你的程序還是有機會執(zhí)行它的。然后又是利用PeekMessage檢測消息隊列:

          如果有消息[這個消息不被移動的原因是因為它要為PumpMessage內(nèi)的GetMessage所利用。]再次進入PumpMessage[叫它“消息泵”吧]。

          如果沒有消息,退出DO循環(huán),但它還在FOR內(nèi)部,所以又執(zhí)行第一個While循環(huán)。

          這是CwinThread::Run的一個執(zhí)行過程。

          不用擔心退不出for(;;)如果你的消息隊列中有一條WM_QUIT,會使GetMessage返回0,然后PumpMessage返回0而RUN()內(nèi)部:

        if (!PumpMessage())
        return ExitInstance();

          SDI就說到這,下面我來談一下模式對話框。我分2種情況討論:

          一當你的工程以模式對話框為基礎時[沒父窗口,或為桌面]。

          與SDI不同處在于,在應用程序類的InItInstance內(nèi)部:

        BOOL CComboBoxApp::InitInstance()
        {
         AfxEnableControlContainer();
         // Standard initialization
         // If you are not using these features and wish to reduce the size
         // of your final executable, you should remove from the following
         // the specific initialization routines you do not need.
         #ifdef _AFXDLL
          Enable3dControls(); // Call this when using MFC in a shared DLL
         #else
          Enable3dControlsStatic(); // Call this when linking to MFC statically
         #endif
         this->m_nCmdShow = SW_HIDE;
         CComboBoxDlg dlg;
         m_pMainWnd = dlg;
         int nResponse = dlg.DoModal();
         if (nResponse == IDOK)
         {
          // TODO: Place code here to handle when the dialog is
          // dismissed with OK
         }
         else if (nResponse == IDCANCEL)
         {
          // TODO: Place code here to handle when the dialog is
          // dismissed with Cancel
         }
         // Since the dialog has been closed, return FALSE so that we exit the
         // application, rather than start the application’s message pump.
         return FALSE;
        }

          int nResponse = dlg.DoModal();一句使你的整個程序都在DoModal()內(nèi)部進行。而且,你退出DoMal()時[你一定結束了你的對話框],InitInstance返回的是False,我們知道,這樣,CwinThread::Run是不會執(zhí)行的。

          但對話框程序是在哪里進行消息處理的呢。

          原來,dlg.DoModal()內(nèi)部會調(diào)用CwinThread::RunModalLoop,它起到的作用和RUN()是一樣的[當然內(nèi)部有細小差別,請參考MSDN]!!!

          第二種情況,你是在SDI[或其它]程序中調(diào)用Dlg.DoModal() 產(chǎn)生了一模式對話框[有父窗口].

          這又是如何運作的呢?

          建了這樣一個工程做為例子。

          SDI,在View中處理LBUTTONDOWN:

        MyDLg.DoModal();

          MyDLg內(nèi)有按鈕,以憊后用.

          沒有顯示模式對話框前,消息處理一直在Cthread::Run()中進行.

          你單擊后,程序執(zhí)行點進入DoModal()內(nèi)部的RunModalLoop,這又是一個消息處理機制.

          不過DoModal()中調(diào)用RunModalLoop,前會Disable掉它的父窗口.從RunModalLoop中出來后,再 Enable它.

          模式對話框和非模式對話框都是通過調(diào)用CreateDialogIndirect()產(chǎn)生創(chuàng)建對話框.那它和非模式對話框區(qū)別是什么造成的呢?

          1 模式對話框?qū)⒏复翱贒ISABLE掉.

          我原以為被Disable的窗口是不接收消息的.但后來我馬上發(fā)現(xiàn)我是錯的.但,為什么你對被Disable的窗口進行KeyBorad,Mouse動作時,窗口沒反映呢,我想,這可能是操作系統(tǒng)從中搞的鬼.我在本文一開始,就寫出操作系統(tǒng)向窗口發(fā)送消息的過程,我想當它發(fā)現(xiàn)目標窗口處理Disabled狀態(tài)時,
        不會將消息發(fā)送給它,但這不能說窗口不接收消息,其它程序[或它本身]發(fā)送給它的消息還是可以接收并處理的.

          2 模式對話框本身有消息處理機制 RunModalLoop.

          對以上兩點加以實驗.

          我在我的剛才建的項目中的模式對話框中加上一個BUTTON,其中加入如下代碼:

        OnButton1()
        {
         GetParaent()->EnableWindow(1);
        }

          單擊,后我們發(fā)現(xiàn),此時它已經(jīng)不再表現(xiàn)為”模態(tài)”,我試著點擊菜單,還是會作出正常反映.

          我想這此消息[對于父窗口的,如:菜單動作]的處理也應是在模式對話框中的RunModalLoop中進行處理的吧[這點我不能確定].

        c++相關文章:c++教程




        關鍵詞: 消息機制

        評論


        技術專區(qū)

        關閉