MFC六大核心機制之一:MFC程式的初始化流程
1,手動編寫MFC
下面就是我們要手寫MFC的程式碼,
class CMyApp:public CWinApp { public: virtual BOOL InitInstance(); }; class CMainWnd:public CFrameWnd { public: CMainWnd(); }; CMyApp theApp; BOOL CMyApp::InitInstance() { //建立視窗 m_pMainWnd=new CMainWnd; m_pMainWnd->ShowWindow(m_nCmdShow); m_pMainWnd->UpdateWindow(); return TRUE; } CMainWnd::CMainWnd() { Create(NULL,TEXT("Hell MFC")); }
MFC程式的入口是WinMain而我們並沒有提供入口而上面這段程式卻能創建出一個窗口出來。
當我們沒有提供入口的時候,實際上MFC已經幫我準備了入口,對於這段程式執行在vc6.0上,按下F10即可進入到函式入口:
進入到AfxWinMain函式中:
這個就是MFC為我們準備好的入口,實際上已經做了很多的事情。
這裡面有幾個重要的函式:AfxGetThread,pThread->InitInstance,pThread->Run()
在AFXWIN.H中是這麼定義的:
CWinApp* AFXAPI AfxGetApp();
那麼AfxGetApp是怎麼獲取當前App的CWinApp類指標呢?
AfxGetApp是一個行內函數,其實現如下(在AFXWIN1.INL):
AFXWIN_INLINE CWinApp *AFXAPI AfxGetApp()
{ return afxCurrentWinApp;}
而afxCurrentWinApp是一個巨集,定義在AFXWIN.H中:
#define afxCurrentWinApp AfxGetModuleState()->m_pCurrentWinApp
AfxGetModuleState返回的是一個:AFX_MODULE_STATE類的指標(AFXSTAT
AFX_MODULE_STATE* AFXAPI AfxGetModuleState();
在AFX_MODULE_STATE類中定義瞭如下的成員變數:
CWinApp* m_pCurrentWinApp;
HINSTANCE m_hCurrentInstanceHandle;
HINSTANCE m_hCurrentResourceHandle;
LPCTSTR m_lpszCurrentAppName;
BYTE m_bDLL; // TRUE if module is a DLL, FALSE if it is an EXE
BYTE m_bSystem; // TRUE if module is a “system” module, FALSE if not
BYTE m_bReserved[2]; // padding
DWORD m_fRegisteredClasses; // flags for registered window classes
AFX_MODULE_STATE是在什麼時候進行的初始化呢?最可能就是在theApp初始化的時候,
theApp繼承了CWinApp,所以CWinApp的建構函式會執行。下面就是CWinApp建構函式的原始碼,建立了2個指標:AFX_MODULE_STATE和AFX_MODULE_THREAD_STATE分別指向了CWinApp和它的父類。
CWinApp的建構函式
CWinApp::CWinApp(LPCTSTR lpszAppName)
{
if (lpszAppName != NULL)
m_pszAppName = _tcsdup(lpszAppName);
else
m_pszAppName = NULL;
// initialize CWinThread state 建立了一個AFX_MODULE_STATE指標
AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
建立了一個AFX_MODULE_THREAD_STATE的指標
AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;
ASSERT(AfxGetThread() == NULL);
pThreadState->m_pCurrentWinThread = this;
ASSERT(AfxGetThread() == this);
m_hThread = ::GetCurrentThread();
m_nThreadID = ::GetCurrentThreadId();
// initialize CWinApp state
ASSERT(afxCurrentWinApp == NULL); // only one CWinApp object please
pModuleState->m_pCurrentWinApp = this;
ASSERT(AfxGetApp() == this);
// in non-running state until WinMain
m_hInstance = NULL;
m_pszHelpFilePath = NULL;
m_pszProfileName = NULL;
m_pszRegistryKey = NULL;
m_pszExeName = NULL;
m_pRecentFileList = NULL;
m_pDocManager = NULL;
m_atomApp = m_atomSystemTopic = NULL;
m_lpCmdLine = NULL;
m_pCmdInfo = NULL;
// initialize wait cursor state
m_nWaitCursorCount = 0;
m_hcurWaitCursorRestore = NULL;
// initialize current printer state
m_hDevMode = NULL;
m_hDevNames = NULL;
m_nNumPreviewPages = 0; // not specified (defaults to 1)
// initialize DAO state
m_lpfnDaoTerm = NULL; // will be set if AfxDaoInit called
// other initialization
m_bHelpMode = FALSE;
m_nSafetyPoolSize = 512; // default size
}
有一個知識點一定要知道:
在main函式中沒有寫任何程式,但是仍然會列印Hello出來
class BB
{
void BB()
{
printf("Hello");
}
};
BB b;
int main(int argc, char* argv[])
{
}
所以CMyApp theApp;會先於程式入口執行,初始化的時候會寫填寫好
AFX_MODULE_STATE和AFX_MODULE_THREAD_STATE這兩個指標,於是我們可以考慮在記憶體中有一份AFX_MODULE_STATE和AFX_MODULE_THREAD_STATE的全域性變數,不然AfxGetApp怎麼得到這些資料。
然後我們進入到pThread->InitInstance函式中就得到下面的函數了,為什麼會得到下面的函式呢,首先InitInstance是一個虛擬函式,被我們寫的子類重寫了,而pThread是Cwinapp的父類,cwinapp是Cmyapp的父類,虛擬函式被覆蓋了,所以呼叫的是cmyapp的InitInstance函式。
然後我們進入到pThread->Run()中,再進入到CWinThread::Run()中,就發現了我們非常熟悉的東西,訊息迴圈。