www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁 > 嵌入式 > 嵌入式軟件
[導(dǎo)讀]Windows程序和DOS程序的主要不同點之一是:Windows程序是以事件為驅(qū)動、消息機(jī)制為基礎(chǔ)

Windows程序和DOS程序的主要不同點之一是:Windows程序是以事件為驅(qū)動、消息機(jī)制為基礎(chǔ)

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

正文:

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

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

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

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

對于SDI窗口,你的應(yīng)用程序類的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)生成相關(guān)文檔、視,顯示主框架窗口、處理參數(shù)行信息等工作。這些都是顯示在你工程中的“明碼”。我們現(xiàn)在把斷點設(shè)置到return TRUE;一句,跟入MFC源碼中,看看到底MFC內(nèi)部做了什么。

程序進(jìn)入SRCWinMain.cpp,下一個大動作應(yīng)是:

nReturnCode = pThread->Run();

注意了,重點來了。F11進(jìn)入

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進(jìn)入:

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處理消息的中心機(jī)構(gòu),但請注意,它覺對不是核心!

分析一下,在無限循環(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
}

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

當(dāng)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));

看啊,又進(jìn)入一個循環(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消息處理的核心基地[也是我個人認(rèn)為的]。

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

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

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

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

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

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

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

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

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

一當(dāng)你的工程以模式對話框為基礎(chǔ)時[沒父窗口,或為桌面]。

與SDI不同處在于,在應(yīng)用程序類的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)部進(jìn)行。而且,你退出DoMal()時[你一定結(jié)束了你的對話框],InitInstance返回的是False,我們知道,這樣,CwinThread::Run是不會執(zhí)行的。

但對話框程序是在哪里進(jìn)行消息處理的呢。

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

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

這又是如何運作的呢?

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

SDI,在View中處理LBUTTONDOWN:

MyDLg.DoModal();

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

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

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

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

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

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

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

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

對以上兩點加以實驗.

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

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

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

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

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

正文:

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

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

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

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

對于SDI窗口,你的應(yīng)用程序類的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)生成相關(guān)文檔、視,顯示主框架窗口、處理參數(shù)行信息等工作。這些都是顯示在你工程中的“明碼”。我們現(xiàn)在把斷點設(shè)置到return TRUE;一句,跟入MFC源碼中,看看到底MFC內(nèi)部做了什么。

程序進(jìn)入SRCWinMain.cpp,下一個大動作應(yīng)是:

nReturnCode = pThread->Run();

注意了,重點來了。F11進(jìn)入

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進(jìn)入:

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處理消息的中心機(jī)構(gòu),但請注意,它覺對不是核心!

分析一下,在無限循環(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
}

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

當(dāng)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));

看啊,又進(jìn)入一個循環(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消息處理的核心基地[也是我個人認(rèn)為的]。

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

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

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

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

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

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

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

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

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

一當(dāng)你的工程以模式對話框為基礎(chǔ)時[沒父窗口,或為桌面]。

與SDI不同處在于,在應(yīng)用程序類的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)部進(jìn)行。而且,你退出DoMal()時[你一定結(jié)束了你的對話框],InitInstance返回的是False,我們知道,這樣,CwinThread::Run是不會執(zhí)行的。

但對話框程序是在哪里進(jìn)行消息處理的呢。

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

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

這又是如何運作的呢?

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

SDI,在View中處理LBUTTONDOWN:

MyDLg.DoModal();

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

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

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

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

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

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

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

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

對以上兩點加以實驗.

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

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

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

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

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點: 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉