MFC內部結構剖析
睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接
//////////////////////////////////////////////////////////////////////////////////////////
MFC程序的執行順序依次是:theApp全局對象定義處、TestApp構造函數、WinMain。
程序在加載main函數之前,會先為全局變量和全局對象分配內存空間。
對于MFC程序來說,通過產生一個應用程序類的對象來唯一標識應用程序的實例。每一個MFC程序實例有且僅有一個該派生類的實例化對象,也就是theApp全局對象,該對象就表示了應用程序本身。
theApp對象的構造函數CtestApp在調用之前,會調用其父類CWinApp的構造函數,從而就把我們程序自己創建的類與Microsoft提供的基類關聯起來了。CWinApp的構造函數完成程序運行時的一些初始化工作。
AfxWinMain函數:WinMain函數實際上是通過調用AfxWinMain函數來完成它的功能的。
AfxWinMain調用AfxGetThread函數獲得一個CWinTread類型的指針。
接著AfxWinMain調用AfxGetApp函數獲得一個CWinApp類型的指針。
由以下代碼可以看出:AfxGetThread函數返回的就是AfxGetApp函數的結果。
AfxGetApp函數返回的是在CWinApp構造函數中保存的this指針(詳見CWinApp類定義的源文件:appcore.cpp)。
對本Test程序來說,這個this指針實際上指向的是CTestApp的對象:theApp。也就是說,pThread和pApp所指向的都是CTestApp類的對象,即theApp全局對象。
InitInstance函數:
pThread和pApp調用了三個函數(InitApplication、InitInstance和Run)去完成Win32程序所需要的幾個步驟:設計窗口類、注冊窗口類、創建窗口、顯示窗口、更新窗口、消息循環以及窗口過程函數。
pApp首先調用InitApplication函數完成MFC內部管理方面的工作。
接著,調用pThread的InitInstance函數(其實是調用從CWinApp派生的應用程序類CTestApp中的虛函數InitInstance)。
MFC框架窗口
1.設計和注冊窗口:MFC已經為我們預定義了一些默認的標準窗口類,只需呀選擇所需的窗口類,然后注冊就可以了。
窗口類的注冊由AfxEndDeferRegisterClass函數完成(AfxEndDeferRegisterClass函數首先判斷窗口類的類型,然后賦予其相應的類名,這些類名是MFC預定義的,然后調用AfxRegisterClass函數注冊窗口類)。
AfxRegisterClass函數首先獲得窗口類的信息,如果該窗口已經注冊,則直接返回一個真值;如果尚未注冊,就調用RegisterClass函數注冊該窗口類(注冊窗口類使用的函數其實和Win32 SDK編程中所使用的函數一致)。
我們所創建的這個MFC應用程序Test,實際上有兩個窗口。
其中之一:CMainFrame:: PreCreateWindow,這是在窗口產生之前被調用的。CMainFrame:: PreCreateWindow函數又調用了AfxDeferRegisterClass,而AfxDeferRegisterClass實際上是一個宏,指向AfxEndDeferRegisterClass(前面提到,此函數的功能就是注冊窗口類)。
2.創建窗口:
窗口的創建是由CWnd類的CreateEx函數實現的。(聲明:AFXWin.h實現:WINCORE.CPP)
(在MFC的底層代碼中CFrameWnd::Create調用了上述的CreateEx函數,而CFrameWnd:: LoadFrame又調用CFrameWnd::Create函數。此過程請自行跟蹤。)
CWnd::CreateEx調用CMainFrame:: PreCreateWindow(PreCreateWindow是一個虛函數,所以這里實際上調用的是子類,即CMainFrame:: PreCreateWindow。這里再次調用此函數是為了在產生窗口之前讓程序員有機會修改程序的外觀。例如,去掉窗口最大化按鈕等)
3.顯示和更新窗口
CTestApp:: m_pMainWnd
m_pMainWnd是一個CWnd類型并且保存了應用程序框架窗口對象的指針,也就是說m_pMainWnd變量是一個指向CMainFrame對象的指針。
CTestApp::InitInstance函數實現內部有如下兩行代碼:
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
這兩行代碼實現了窗口的顯示和更新。
消息循環
CWinThread::Run函數完成消息循環。
該函數由AfxWinMain::pThread函數調用。
形式:pThread->Run();
CWinThread::Run函數主要是一個for循環,該循環在收到一個WM_QUIT消息時退出。在此循環中調用了一個PumpMessage函數。
窗口過程函數
AfxEndDeferRegisterClass函數源程序:wndcls.lpfnWndProc = DefWindowProc
這里指定的一個默認窗口過程DefWindowProc。但實際上MFC程序并不是把所有的消息都交給DefWindowProc這一默認窗口過程來處理。而是采用了一種“消息映射機制”。
///////////////////////////////////////////////////////////////////////////////////////////
梳理全過程
1.首先利用全局應用程序對象theApp啟動應用程序。正是產生了這個全局對象,基類CWinApp中的this指針才能指向這個對象。如果沒有這個全局對象,程序在編譯的時候不會出錯,但在運行時就出錯。
2.調用全局應用程序對象的構造函數,從而就會先調用其基類CWinApp的構造函數。后者完成應用程序的一些初始化工作,并將應用程序對象的指針保存起來。
3.進入WinMain函數。在AfxWinMain函數中可以獲取子類(對Test程序來說,就是CTestApp類)的指針,利用此指針調用虛函數:InitInstance,根據多態性原理,實際上調用的是子類(CTestApp)的InitInstance函數。后者完成一些應用程序的初始化工作,包括窗口類的注冊、創建,窗口的顯示和更新。期間會多次調用CreateEx函數,因為一個單文檔MFC應用程序有多個窗口,包括框架窗口、工具條、狀態條等。
4.進入消息循環。雖然也設置了默認的窗口過程函數,但是,MFC應用程序實際上采用消息影射機制來處理各種消息的。當收到WM_QUIT消息時,退出消息循環,程序結束。
///////////////////////////////////////////////////////////////////////////////////////////RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
MFC程序的執行順序依次是:theApp全局對象定義處、TestApp構造函數、WinMain。
程序在加載main函數之前,會先為全局變量和全局對象分配內存空間。
對于MFC程序來說,通過產生一個應用程序類的對象來唯一標識應用程序的實例。每一個MFC程序實例有且僅有一個該派生類的實例化對象,也就是theApp全局對象,該對象就表示了應用程序本身。
theApp對象的構造函數CtestApp在調用之前,會調用其父類CWinApp的構造函數,從而就把我們程序自己創建的類與Microsoft提供的基類關聯起來了。CWinApp的構造函數完成程序運行時的一些初始化工作。
AfxWinMain函數:WinMain函數實際上是通過調用AfxWinMain函數來完成它的功能的。
AfxWinMain調用AfxGetThread函數獲得一個CWinTread類型的指針。
接著AfxWinMain調用AfxGetApp函數獲得一個CWinApp類型的指針。
由以下代碼可以看出:AfxGetThread函數返回的就是AfxGetApp函數的結果。
- CWinThread* AFXAPI AfxGetThread()
- {
- // check for current thread in module thread state
- AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
- CWinThread* pThread = pState->m_pCurrentWinThread;
- // if no CWinThread for the module, then use the global app
- if (pThread == NULL)
- pThread = AfxGetApp();
- return pThread;
- }
AfxGetApp函數返回的是在CWinApp構造函數中保存的this指針(詳見CWinApp類定義的源文件:appcore.cpp)。
對本Test程序來說,這個this指針實際上指向的是CTestApp的對象:theApp。也就是說,pThread和pApp所指向的都是CTestApp類的對象,即theApp全局對象。
InitInstance函數:
pThread和pApp調用了三個函數(InitApplication、InitInstance和Run)去完成Win32程序所需要的幾個步驟:設計窗口類、注冊窗口類、創建窗口、顯示窗口、更新窗口、消息循環以及窗口過程函數。
pApp首先調用InitApplication函數完成MFC內部管理方面的工作。
接著,調用pThread的InitInstance函數(其實是調用從CWinApp派生的應用程序類CTestApp中的虛函數InitInstance)。
MFC框架窗口
1.設計和注冊窗口:MFC已經為我們預定義了一些默認的標準窗口類,只需呀選擇所需的窗口類,然后注冊就可以了。
窗口類的注冊由AfxEndDeferRegisterClass函數完成(AfxEndDeferRegisterClass函數首先判斷窗口類的類型,然后賦予其相應的類名,這些類名是MFC預定義的,然后調用AfxRegisterClass函數注冊窗口類)。
AfxRegisterClass函數首先獲得窗口類的信息,如果該窗口已經注冊,則直接返回一個真值;如果尚未注冊,就調用RegisterClass函數注冊該窗口類(注冊窗口類使用的函數其實和Win32 SDK編程中所使用的函數一致)。
我們所創建的這個MFC應用程序Test,實際上有兩個窗口。
其中之一:CMainFrame:: PreCreateWindow,這是在窗口產生之前被調用的。CMainFrame:: PreCreateWindow函數又調用了AfxDeferRegisterClass,而AfxDeferRegisterClass實際上是一個宏,指向AfxEndDeferRegisterClass(前面提到,此函數的功能就是注冊窗口類)。
2.創建窗口:
窗口的創建是由CWnd類的CreateEx函數實現的。(聲明:AFXWin.h實現:WINCORE.CPP)
(在MFC的底層代碼中CFrameWnd::Create調用了上述的CreateEx函數,而CFrameWnd:: LoadFrame又調用CFrameWnd::Create函數。此過程請自行跟蹤。)
CWnd::CreateEx調用CMainFrame:: PreCreateWindow(PreCreateWindow是一個虛函數,所以這里實際上調用的是子類,即CMainFrame:: PreCreateWindow。這里再次調用此函數是為了在產生窗口之前讓程序員有機會修改程序的外觀。例如,去掉窗口最大化按鈕等)
3.顯示和更新窗口
CTestApp:: m_pMainWnd
m_pMainWnd是一個CWnd類型并且保存了應用程序框架窗口對象的指針,也就是說m_pMainWnd變量是一個指向CMainFrame對象的指針。
CTestApp::InitInstance函數實現內部有如下兩行代碼:
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
這兩行代碼實現了窗口的顯示和更新。
消息循環
CWinThread::Run函數完成消息循環。
該函數由AfxWinMain::pThread函數調用。
形式:pThread->Run();
CWinThread::Run函數主要是一個for循環,該循環在收到一個WM_QUIT消息時退出。在此循環中調用了一個PumpMessage函數。
窗口過程函數
AfxEndDeferRegisterClass函數源程序:wndcls.lpfnWndProc = DefWindowProc
這里指定的一個默認窗口過程DefWindowProc。但實際上MFC程序并不是把所有的消息都交給DefWindowProc這一默認窗口過程來處理。而是采用了一種“消息映射機制”。
///////////////////////////////////////////////////////////////////////////////////////////
梳理全過程
1.首先利用全局應用程序對象theApp啟動應用程序。正是產生了這個全局對象,基類CWinApp中的this指針才能指向這個對象。如果沒有這個全局對象,程序在編譯的時候不會出錯,但在運行時就出錯。
2.調用全局應用程序對象的構造函數,從而就會先調用其基類CWinApp的構造函數。后者完成應用程序的一些初始化工作,并將應用程序對象的指針保存起來。
3.進入WinMain函數。在AfxWinMain函數中可以獲取子類(對Test程序來說,就是CTestApp類)的指針,利用此指針調用虛函數:InitInstance,根據多態性原理,實際上調用的是子類(CTestApp)的InitInstance函數。后者完成一些應用程序的初始化工作,包括窗口類的注冊、創建,窗口的顯示和更新。期間會多次調用CreateEx函數,因為一個單文檔MFC應用程序有多個窗口,包括框架窗口、工具條、狀態條等。
4.進入消息循環。雖然也設置了默認的窗口過程函數,但是,MFC應用程序實際上采用消息影射機制來處理各種消息的。當收到WM_QUIT消息時,退出消息循環,程序結束。
///////////////////////////////////////////////////////////////////////////////////////////RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成