每个MFC程序都有一个the全局对象,此对象代表了这个应用程序,程序从这里诞生。
1、因theApp是全局对象,所以比winmain更早初始化。
2、theApp的初始化,先引发了其构造函数。因theApp派生于CWinApp,则也引发了CWinApp的构造函数
3、CWinApp中的几条重要的初始化代码:
AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;
pThreadState->m_pCurrentWinThread = this;
pModuleState->m_pCurrentWinApp = this;
可以看到m_pCurrentWinThread与m_pCurrentWinApp现在都指向theApp。
4、CWinApp初始化后,进入winmain。winmain中进行了如下调用:
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
5、AfxWinMain中的重要代码:
CWinThread* pThread = AfxGetThread();//AfxGetThread其实就是取得了theApp的指针
CWinApp* pApp = AfxGetApp();//AfxGetApp其实就是取的了theApp的指针
AfxGetThread的定义:
CWinThread* AFXAPI AfxGetThread()
{
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
CWinThread* pThread = pState->m_pCurrentWinThread;
if (pThread == NULL)
pThread = AfxGetApp();
return pThread;//pThread指向theApp
}
AfxGetApp的定义:
_AFXWIN_INLINE CWinApp* AFXAPI AfxGetApp()
{ return afxCurrentWinApp; }
#define afxCurrentWinApp AfxGetModuleState()->m_pCurrentWinApp//AfxGetApp也返回了theApp的指针。
AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow);//内部的初始化操作
节选其中的一些重要代码:
// fill in the initial state for the application
CWinApp* pApp = AfxGetApp();
if (pApp != NULL)
{
// Windows specific initialization (not done if no CWinApp)
pApp->m_hInstance = hInstance;
pApp->m_hPrevInstance = hPrevInstance;
pApp->m_lpCmdLine = lpCmdLine;
pApp->m_nCmdShow = nCmdShow;
pApp->SetCurrentHandles();
}
pApp->InitApplication();
这里相当于调用了theApp的InitApplication,但因大多数情况下无需改写此虚函数,所以实际调用的是CWinApp::InitApplication.其中的操作是为MFC内部管理而做,与Document Template有关。
pThread->InitInstance();
这里相当于调用了theApp的InitInstance,因theApp中改写了这个虚函数,所以直接调用即可。节选其中的重要代码:
//new一个CMultiDocTemplate对象并初始化,用来管理Doccument/view/Frame三者之间的关系
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(
IDR_MDITYPE,
RUNTIME_CLASS(CMDIDoc),
RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CMDIView));
AddDocTemplate(pDocTemplate);
//主框架窗口的初始化
CMainFrame* pMainFrame = new CMainFrame;
//LoadFrame会触发WM_CREATE消息(中间一系列调用不详述了)
if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
return FALSE;
m_pMainWnd = pMainFrame;
CMainFrame::OnCreate中,主要实现工具栏、状态栏的初始化。
//显示主框架窗口,并发出更新窗口
pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();
pThread->Run();
这里相当于调用了theApp的Run,但是theApp通常不会改写这个虚函数,所以实际调用的是CWinApp的Run。节选一些代码:
int CWinApp::Run()
return CWinThread::Run();
int CWinThread::Run()
{
do
{
if (!PumpMessage())
return ExitInstance();//收到WM_QUIT消息
if (IsIdleMessage(&m_msgCur))
{
bIdle = TRUE;
lIdleCount = 0;
}
} while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
}
BOOL CWinThread::PumpMessage()
{
if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))
return FALSE;//如取得的消息是WM_QUIT,则返回FALSE
if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur))
{
::TranslateMessage(&m_msgCur);
::DispatchMessage(&m_msgCur);
}
return TRUE;
}
以上代码非常清楚的显示了,Run其实就是执行了消息循环.
通过以上框架的剖析,学到如下知识:
1、虚函数的应用。如子类没有改写了父类的虚函数,使用子类调用该函数时,调用的是父类的函数。
2、类的构造与析构顺序。类的构造,是先构造其父类(如果有),再构造自己。析构时,是先析构自己,在析构父类(如果有)。