二.MFC應用程序結構
在《明明白白看MFC之程序框架(一)》中我分析了一個經典的應用程序的結構,現在可是要進入主題"MFC應用程序結構"了.應用程序有好多種,為了能夠更清楚地與前面的文章形成對比,我們在這裡看一個SDI的應用程序,當然例子還是經典的Hello World了。在使用向導生成應用程序後,會發現有好幾個文件,首先我們不管有哪些文件,按照程序執行得主線抽取主要的源程序分析一下再說(因為MFC生成的應用程序不是很方便閱讀,所以在這裡我將他們重新編輯了)。
CHelloWorldApp theApp;
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp();
// AFX internal initialization
if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
goto InitFailure;
// App global initializations (rare)
if (pApp != NULL && !pApp->InitApplication())
goto InitFailure;
// Perform specific initializations
if (!pThread->InitInstance())
{
if (pThread->m_pMainWnd != NULL)
{
TRACE0("Warning: Destroying non-NULL m_pMainWnd\n");
pThread->m_pMainWnd->DestroyWindow();
}
nReturnCode = pThread->ExitInstance();
goto InitFailure;
}
nReturnCode = pThread->Run();
InitFailure:
……………………
AfxWinTerm();
return nReturnCode;
}
BOOL CWinApp::InitApplication()
{
if (CDocManager::pStaticDocManager != NULL)
{
if (m_pDocManager == NULL)
m_pDocManager = CDocManager::pStaticDocManager;
CDocManager::pStaticDocManager = NULL;
}
if (m_pDocManager != NULL)
m_pDocManager->AddDocTemplate(NULL);
else
CDocManager::bStaticInit = FALSE;
return TRUE;
}
BOOL CHelloWorldApp::InitInstance()
{
AfxEnableControlContainer();
………………………………
// Change the registry key under which our settings are stored.
// TODO: You should modify this string to be something appropriate
// such as the name of your company or organization.
SetRegistryKey(_T("Local AppWizard-Generated Applications"));
LoadStdProfileSettings(); // Load standard INI file options (including MRU)
// Register the application's document templates. Document templates
// serve as the connection between documents, frame windows and views.
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CHelloWorldDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CHelloWorldView));
AddDocTemplate(pDocTemplate);
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// Dispatch commands specified on the command line
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// The one and only window has been initialized, so show and update it.
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
return TRUE;
}
BOOL CWinApp::InitInstance()
{
return TRUE;
}
MFC應用程序之Hello World
咋一眼看上去,好像這個程序無從下手分析,甚至連程序的入口點都找不到。其實,上面的程序還是經過整理後才有如此模樣。好了,一樣的來看看這個程序是怎麼運行的吧(要注意的事上面的程序來自於不同的文件,這裡排版在一起只是為了更清楚地表示程序的結構,至於MFC的文件組織我會在下面一個話題中具體的分析,這裡可以暫時不考慮)。
首先,在程序的開始處,首先定義了一個全局變量theApp,我們現在只需要知道他代表了整個程序的存在,然後程序開始介入入口點。有沒有搞錯,入口點在哪裡?不及,其實int AFXAPI AfxWinMain()就是這個程序的入口點,奇怪吧!不過沒有關系,就好像我們第一次看到C語言中的main()函數一樣,只要了解就可以了。在AfxWinMain()中分別調用了一些類的成員函數,仿照前面的分析方法,也可以畫出一個程序執行路徑圖。入口點----〉AfxGetThread()------〉AfxGetApp()-------àAfxWinInit()-------àpApp->InitApplication()-----àpThread->InitInstance()------àpThread->Run()。可以看到,程序一樣有一個執行的線索可循,但是,相對於SDK來說,如今已經面目全非了,過去的那種清晰的程序結構在這些程序中也有嗎?答案是肯定的,只不過他們的具體實現在MFC中都進行了包裝而已,那麼,還是來看看這個應用程序是如何啟動並且運行的吧。
程序由AfxWinMain()開始運行後,首先調用了AfxGetApp()來獲取應用程序的對象指針pApp,然後通過這個指針調用有關的成員函數來完成初始化和啟動工作,最後就調用了Run()函數,在這裡,Run()函數就是代表了SDK中的消息循環。
事情的發展在預料中進行著,但是似乎還遺漏了一點什麼似的?不錯,在上面我們的確是還有一樣工作沒有完成,這就是我們需要的”Hello World”好像還沒有輸出來!這不是我的疏忽,而是故意的安排,因為MFC中采用了一種全新(當然是相對於SDK來說的了)的消息處理機制,至少在表面上來說是這樣的。然而,在這裡我不打算一下子就把問題解決掉,畢竟這有點復雜,等我們明白了MFC的文件之間的關系後我會在回答這個問題。我沒有想到這篇文章會這麼長,剛剛開始的時候我以為我可以一下子就把這個問題說清楚地,但是事實上我寫作的思路也像我分析程序時一樣,竟然是一個漫長的過程!所以我也有必要提醒一下自己以及讀這篇文章的朋友,應該休息一下了。我現在都開始慶幸我把這個問題分成好幾個小問題來解決了,我會在接下來的話題中繼續討論的事MFC程序所生成的文件以及它們之間的調用關系.