資料介紹
Windows程序和DOS程序的主要不同點之一是:Windows程序是以事件為驅動、消息機制為基礎
本人對Windows系統、MFC談不上有深入的了解,但對MFC本身包裝API的機制很有興趣,特別是讀了候老師的《深入淺出MFC》后,感覺到Visual C++的Application FrameWork十分精制。在以前,我對SDI結構處理消息有一定的認識,但對于模式對話框的消息機制不了解,讀了《深入》一書也沒能得到解決,近日,通過在網友的幫助和查閱MSDN,自認為已經了解。一時興起,寫下這些文字,沒有其它目的,只是希望讓后來者少走彎路,也希望和我一樣 喜歡“鉆牛角尖”的人共同討論、學習。如果你是牛人,那么你現在要慎重考慮有沒有充足的時間讀這些幼稚文字。
正文:
Windows程序和DOS程序的主要不同點之一是:Windows程序是以事件為驅動、消息機制為基礎。如何理解?
舉了例子,當你CLICK Windows “開始”BUTTON時,為什么就會彈出一個菜單呢?
當你單擊鼠標左鍵時,操作系統中與MOUSE相關的驅動程序在第一時間內得到這個信號[LBUTTONDOWN],然后它通知操作系統―――“嗨,鼠標左鍵被單擊了!”,操作系統得到這一信號后,馬上要判斷――用戶單擊鼠標左鍵,這是針對哪個窗口呢?如何判斷?這很簡單!當前狀態中,具有焦點的窗口[或控件]就是了[這里當然是“開始”BUTTON了]。然后操作系統馬上向這個窗口發送一條消息到這個窗口所在進程的消息隊列,消息內容應是消息本身的代號、附加參數、窗口句柄…等等了。那么,只有操作系統才有資格發送消息至某一窗口的消息隊列嗎?不然,其它程序也有資格。你可以在你的程序中調用:SendMessage、PostMessage。這樣,被單擊的窗口得到了一條由操作系統發送的包含CLICK的消息,操作系統已經暫時不再管窗口的任何事,因為它還要忙于處理其它事務。你的程序得到一條消息后如何做呢?Windows對于你在“開始”BUTTON上的單擊事件做出如下反映:彈出一菜單。可是,得到消息到做出反映這一過程是如何實現的呢?這就是本文討論的主要內容[當然只是針對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;
}
完成一些如動態生成相關文檔、視,顯示主框架窗口、處理參數行信息等工作。這些都是顯示在你工程中的“明碼”。我們現在把斷點設置到return TRUE;一句,跟入MFC源碼中,看看到底MFC內部做了什么。
程序進入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處理消息的中心機構,但請注意,它覺對不是核心!
分析一下,在無限循環FOR內部又出現一個WHILE循環
while (bIdle &&
?。。海篜eekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
{
// call OnIdle while in bIdle state
if (!OnIdle(lIdleCount++))
bIdle = FALSE; // assume “no idle” state
}
這段代碼是當你程序進程的消息隊列中沒有消息時,會調用OnIdle做一些后備工作,臨時對象在這里被刪除。當然它是虛函數。其中的PeekMessage,是查看消息隊列,如果有消息返回TRUE,如果沒有消息返回FALSE,這里指定PM_NOREMOVE,是指查看過后不移走消息隊列中剛剛被查看
到的消息,也就是說這里的PeekMessage只起到一個檢測作用,顯然返回FALSE時[即沒有消息],才會進入循環內部,執行OnIdle,當然了,你的OnIdle返回FLASE,會讓程序不再執行OnIdle。你可能要問:
當bidle=0或消息隊例中有消息時,程序又執行到哪了呢?
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));
看啊,又進入一個循環!
其中有個重要的函數,PumpMessage,內容如下:
BOOL CWinThread::PumpMessage()
{
ASSERT_VALID(this);
if (?。海篏etMessage(&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如果發現消息隊列中沒有消息會返回0,而GetMessage如果發現沒有消息,等,直到有了消息,而且,GetMessage不同于PeekMessage,它會將消息移走[當然,PeekMessage也可以做到這點]。我想當你讀了這個函數后,
你應明白PreTranslateMessage函數的用法了吧[我比較喜歡在程序中充分利用這個函數]。
?。海篢ranslateMessage(&m_msgCur);
::DispatchMessage(&m_msgCur);
將消息發送到窗口的處理函數[它是由窗口類指定的],之后的動作一直到你的程序做出反映的過程,你可以在《深入》一書中得到完美的解釋。我們還是通過reurn
TRUE;回到CWinThread::Run()中的Do{}while;循環。然后還是對IDLE的處理,即便剛才你的ONIDLE返回了FALSE,在這里你看到,你的程序還是有機會執行它的。然后又是利用PeekMessage檢測消息隊列:
如果有消息[這個消息不被移動的原因是因為它要為PumpMessage內的GetMessage所利用。]再次進入PumpMessage[叫它“消息泵”吧]。
如果沒有消息,退出DO循環,但它還在FOR內部,所以又執行第一個While循環。
本人對Windows系統、MFC談不上有深入的了解,但對MFC本身包裝API的機制很有興趣,特別是讀了候老師的《深入淺出MFC》后,感覺到Visual C++的Application FrameWork十分精制。在以前,我對SDI結構處理消息有一定的認識,但對于模式對話框的消息機制不了解,讀了《深入》一書也沒能得到解決,近日,通過在網友的幫助和查閱MSDN,自認為已經了解。一時興起,寫下這些文字,沒有其它目的,只是希望讓后來者少走彎路,也希望和我一樣 喜歡“鉆牛角尖”的人共同討論、學習。如果你是牛人,那么你現在要慎重考慮有沒有充足的時間讀這些幼稚文字。
正文:
Windows程序和DOS程序的主要不同點之一是:Windows程序是以事件為驅動、消息機制為基礎。如何理解?
舉了例子,當你CLICK Windows “開始”BUTTON時,為什么就會彈出一個菜單呢?
當你單擊鼠標左鍵時,操作系統中與MOUSE相關的驅動程序在第一時間內得到這個信號[LBUTTONDOWN],然后它通知操作系統―――“嗨,鼠標左鍵被單擊了!”,操作系統得到這一信號后,馬上要判斷――用戶單擊鼠標左鍵,這是針對哪個窗口呢?如何判斷?這很簡單!當前狀態中,具有焦點的窗口[或控件]就是了[這里當然是“開始”BUTTON了]。然后操作系統馬上向這個窗口發送一條消息到這個窗口所在進程的消息隊列,消息內容應是消息本身的代號、附加參數、窗口句柄…等等了。那么,只有操作系統才有資格發送消息至某一窗口的消息隊列嗎?不然,其它程序也有資格。你可以在你的程序中調用:SendMessage、PostMessage。這樣,被單擊的窗口得到了一條由操作系統發送的包含CLICK的消息,操作系統已經暫時不再管窗口的任何事,因為它還要忙于處理其它事務。你的程序得到一條消息后如何做呢?Windows對于你在“開始”BUTTON上的單擊事件做出如下反映:彈出一菜單。可是,得到消息到做出反映這一過程是如何實現的呢?這就是本文討論的主要內容[當然只是針對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;
}
完成一些如動態生成相關文檔、視,顯示主框架窗口、處理參數行信息等工作。這些都是顯示在你工程中的“明碼”。我們現在把斷點設置到return TRUE;一句,跟入MFC源碼中,看看到底MFC內部做了什么。
程序進入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處理消息的中心機構,但請注意,它覺對不是核心!
分析一下,在無限循環FOR內部又出現一個WHILE循環
while (bIdle &&
?。。海篜eekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
{
// call OnIdle while in bIdle state
if (!OnIdle(lIdleCount++))
bIdle = FALSE; // assume “no idle” state
}
這段代碼是當你程序進程的消息隊列中沒有消息時,會調用OnIdle做一些后備工作,臨時對象在這里被刪除。當然它是虛函數。其中的PeekMessage,是查看消息隊列,如果有消息返回TRUE,如果沒有消息返回FALSE,這里指定PM_NOREMOVE,是指查看過后不移走消息隊列中剛剛被查看
到的消息,也就是說這里的PeekMessage只起到一個檢測作用,顯然返回FALSE時[即沒有消息],才會進入循環內部,執行OnIdle,當然了,你的OnIdle返回FLASE,會讓程序不再執行OnIdle。你可能要問:
當bidle=0或消息隊例中有消息時,程序又執行到哪了呢?
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));
看啊,又進入一個循環!
其中有個重要的函數,PumpMessage,內容如下:
BOOL CWinThread::PumpMessage()
{
ASSERT_VALID(this);
if (?。海篏etMessage(&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如果發現消息隊列中沒有消息會返回0,而GetMessage如果發現沒有消息,等,直到有了消息,而且,GetMessage不同于PeekMessage,它會將消息移走[當然,PeekMessage也可以做到這點]。我想當你讀了這個函數后,
你應明白PreTranslateMessage函數的用法了吧[我比較喜歡在程序中充分利用這個函數]。
?。海篢ranslateMessage(&m_msgCur);
::DispatchMessage(&m_msgCur);
將消息發送到窗口的處理函數[它是由窗口類指定的],之后的動作一直到你的程序做出反映的過程,你可以在《深入》一書中得到完美的解釋。我們還是通過reurn
TRUE;回到CWinThread::Run()中的Do{}while;循環。然后還是對IDLE的處理,即便剛才你的ONIDLE返回了FALSE,在這里你看到,你的程序還是有機會執行它的。然后又是利用PeekMessage檢測消息隊列:
如果有消息[這個消息不被移動的原因是因為它要為PumpMessage內的GetMessage所利用。]再次進入PumpMessage[叫它“消息泵”吧]。
如果沒有消息,退出DO循環,但它還在FOR內部,所以又執行第一個While循環。
下載該資料的人也在下載
下載該資料的人還在閱讀
更多 >
- TI C64x+ DSP內核異常處理機制的應用
- 基于ARM核的嵌入式系統異常處理機制的設計
- 深度解析Asp.Net2.0中的Callback機制
- 總結:ARM的異常處理機制分析資料下載
- ZigBee CC2530串口的數據接收處理機制詳細資料講解
- MFC原理與方法 8次下載
- 基于MFC編程的圖像處理在核醫學中的應用_付興建 0次下載
- MFC編程基礎 0次下載
- 基于C++的Windows CE文件IO處理技術 0次下載
- TTNT數據鏈收發機消息處理機制的MATLAB仿真 0次下載
- VxWorks下MPC860的中斷處理機制及其應用
- iFix組態軟件中基于隊列的命令處理機制研究
- VxWorks下MPC860的中斷處理機制及其應用
- VxWorks下MPC860的中斷處理機制及其應用
- VxWorks下FMPC860的中斷處理機制及其應用
- 介紹C語言中錯誤處理和異常處理的一些常用的方法和策略 650次閱讀
- C語言中的錯誤處理機制解析 537次閱讀
- 西門子博圖:錯誤處理機制概覽 2994次閱讀
- S32K1xx的ECC錯誤處理機制 6685次閱讀
- C++程序異常處理機制是什么 894次閱讀
- ZWave中的消息隊列機制是什么 813次閱讀
- 一文詳解FIFO處理機制 3708次閱讀
- 嵌入式開發軟件中回調函數的使用 2305次閱讀
- 嵌入式Linux中進程調度怎樣來解析 730次閱讀
- PCIe掃盲—PCIe錯誤檢測機制的詳細資料概述 1.5w次閱讀
- mfc程序執行流程小結,MFC程序的執行順序 9579次閱讀
- mfc多線程編程實例及代碼,mfc多線程間通信介紹 1.7w次閱讀
- mfc基礎入門教程 6305次閱讀
- mfc71.dll是什么 2333次閱讀
- 微處理機控制的數字溫度計電路圖 2718次閱讀
下載排行
本周
- 1TC358743XBG評估板參考手冊
- 1.36 MB | 330次下載 | 免費
- 2開關電源基礎知識
- 5.73 MB | 6次下載 | 免費
- 3100W短波放大電路圖
- 0.05 MB | 4次下載 | 3 積分
- 4嵌入式linux-聊天程序設計
- 0.60 MB | 3次下載 | 免費
- 5基于FPGA的光纖通信系統的設計與實現
- 0.61 MB | 2次下載 | 免費
- 6基于FPGA的C8051F單片機開發板設計
- 0.70 MB | 2次下載 | 免費
- 751單片機窗簾控制器仿真程序
- 1.93 MB | 2次下載 | 免費
- 8基于51單片機的RGB調色燈程序仿真
- 0.86 MB | 2次下載 | 免費
本月
- 1OrCAD10.5下載OrCAD10.5中文版軟件
- 0.00 MB | 234315次下載 | 免費
- 2555集成電路應用800例(新編版)
- 0.00 MB | 33564次下載 | 免費
- 3接口電路圖大全
- 未知 | 30323次下載 | 免費
- 4開關電源設計實例指南
- 未知 | 21548次下載 | 免費
- 5電氣工程師手冊免費下載(新編第二版pdf電子書)
- 0.00 MB | 15349次下載 | 免費
- 6數字電路基礎pdf(下載)
- 未知 | 13750次下載 | 免費
- 7電子制作實例集錦 下載
- 未知 | 8113次下載 | 免費
- 8《LED驅動電路設計》 溫德爾著
- 0.00 MB | 6653次下載 | 免費
總榜
- 1matlab軟件下載入口
- 未知 | 935054次下載 | 免費
- 2protel99se軟件下載(可英文版轉中文版)
- 78.1 MB | 537796次下載 | 免費
- 3MATLAB 7.1 下載 (含軟件介紹)
- 未知 | 420026次下載 | 免費
- 4OrCAD10.5下載OrCAD10.5中文版軟件
- 0.00 MB | 234315次下載 | 免費
- 5Altium DXP2002下載入口
- 未知 | 233046次下載 | 免費
- 6電路仿真軟件multisim 10.0免費下載
- 340992 | 191185次下載 | 免費
- 7十天學會AVR單片機與C語言視頻教程 下載
- 158M | 183278次下載 | 免費
- 8proe5.0野火版下載(中文版免費下載)
- 未知 | 138040次下載 | 免費
評論
查看更多