MFC的初始化过程:
一、首先看一下基本的类图:
1、从图中可以看出,最原始的基类是CObject;而常见的MFC类CWinThread、CDocument、CWnd都是从CObject的子类CCmdTraget派生而来,CWinApp是从CWinThread派生而来, CFrameWnd、CView从CWnd派生而来。
2、注意CWinApp是一个线程类(作为独立线程运行),有自己的虚函数InitApplication、同时重写父类CWinThread的虚函数InitInstance。同时又两个数据成员:CWinApp* m_pCurrentWinApp, CWnd* m_pMainWnd。
注意:m_pCurrentWinApp在CWinApp的构造函数中被初始化为this,(因此可以判断m_pCurrentWinApp总是指向当前对象),
m_pMainWnd用来实现CWnd(或其子类)与CWinApp(或其子类)之间的关联。
3、我们再来看CWnd类,它是窗口类,它实现了虚函数Create、PreCreateWindow;还有非虚函数CreaeEx,在CreateEx函数中调用PreCreateWindow
4、框架窗口CFrameWnd重写了父类CWnd的虚函数Create和PreCreateWIndow;值得注意的是,CFrameWnd::Create函数中调用了CreateEx函数(一般为父类的),此时将导致PreCreateWindow执行。
二、初始化过程
1、以MFC单文档程序为例:项目名为:XXX
根据项目向导生成的程序中主要包含:
CXXXApp : public CWinApp;
CXXXDoc : public CDocument;
CXXXView : public CView;
CMainFrame : public CFrameWnd;
同时在CXXXApp.cpp文件中定义了全局变量: CXXXApp theApp;
2、关于入口点WinMain
(1)、运行时启动代码调用 _tWinMain
extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow) { // call shared/exported WinMain return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow); }
(2)、由上述代码可知,_tWinMain调用AfxWinMain函数,其简化代码(仅为表述初始化而为)如下:
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow) { ASSERT(hPrevInstance == NULL); int nReturnCode = -1; 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()) { nReturnCode = pThread->ExitInstance(); goto InitFailure; } nReturnCode = pThread->Run(); InitFailure: AfxWinTerm(); return nReturnCode; }
(3)、下面来分析一下,AfxWinMain中执行的几个函数:
1**、首先是AfxGetThread
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; }
该函数首先获得当前线程的状态信息,然后将状态信息中的m_pCurrentWinThread指针赋给pThread;接着判断pThread,如果为NULL,则通过AfxGetApp函数来再次赋值。
2**、CWndApp* pApp = AfxGetApp();可以看出pThread与pApp的值,在“获取当前线程状态信息失败”的条件下,是相等的。
3**、接下来是AfxWinInit,做一些线程初始化
4**、然后就是我们熟悉的InitApplication 和 InitInstance,此处值得注意的是pApp->InitApplication和pThread->InitInstance函数,
从此处可以推断pApp与pThread的值在正常情况下应该是相等的。
5**、最后调用pThread的Run函数,从此处可以看出来,MFC的动力源就在此处,消息循环应该就在这个Run函数之中。
3、初始化过程
(1)、首先是InitApplication、然后是InitInstance,
(2)、调用CXXXApp::InitInstance的简化代码如下:
BOOL CMFC_6_15App::InitInstance() { //AfxEnableControlContainer();
CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CMFC_6_15Doc), RUNTIME_CLASS(CMainFrame), // main SDI frame window RUNTIME_CLASS(CMFC_6_15View)); 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; }
1**、首先是创建单文档模板,添加模板,
2**、然后是ParseCommandLine(cmdInfo)和ProcessShellCommand(cmdInfo);(初始化时)ParseCommandLine函数会cmdInfo的m_nShellCommand成员的值设置为:FileNew(枚举类型)。
在执行ProcessShellCommand(cmdInfo)时,调用CWinApp::OnFileNew()
ProcessShellCommand部分代码如下:
switch (rCmdInfo.m_nShellCommand) { case CCommandLineInfo::FileNew: if (!AfxGetApp()->OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL)) OnFileNew(); if (m_pMainWnd == NULL) bResult = FALSE; break;
CWinApp::OnFileNew()代码如下:
void CWinApp::OnFileNew() { if (m_pDocManager != NULL) m_pDocManager->OnFileNew(); }
CDocManager::OnFileNew()函数中调用“pTemplate->OpenDocumentFile(NULL)”函数;
因为此处创建的是单文档,根据多态性,该语句将执行CSingleDocTemplate::OpenDocumentFile函数;
CSingleDocTemplate::OpenDocumentFile中执行“pThread->m_pMainWnd = pFrame;”(也可以追踪pFrame,pFrame应该是CMainFrame的地址)。此过程中要创建CMainFrame对象,
(3)、CMainFrame的构造函数中会调用Create函数;是CFrameWnd::Create函数;
(4)、CFrame::Create函数中还会调用CreateEx,这里的CreateEx是其父类CWnd::CreateEx;
(5)、在CWnd::CreateEx中会调用PreCreateWindow。
4、MFC初始化过程总结
初始化过程可以简化描述为:
CWinApp* pApp = AfxGetApp();
pApp->InitApplication();
pApp->InitInstance();//在此过程中调用了PreCreateWindow和Create函数。
pApp->Run();
5、附上书中的仿真程序:
//MFC.h
#define BOOL int #define TRUE 1 #define FALSE 0 #include <iostream> using namespace std; class CObject { public: CObject() { cout<< "CObject Constructor"<<endl; } ~CObject() { cout<< "CObject Destructor"<<endl; } }; class CCmdTraget : public CObject { public: CCmdTraget() { cout<<"CCmdTraget Constructor"<<endl; } ~CCmdTraget() { cout<<"CCmdTraget Destructor"<<endl; } }; class CWinThread : public CCmdTraget { public: CWinThread() { cout<<"CWinThread Constructor"<<endl; } ~CWinThread() { cout<<"CWinThread Destructor"<<endl; } virtual BOOL InitInstance() { cout<<"CWinThread::InitInstance"<<endl; return TRUE; } virtual int Run() { cout<<"CWinThread::Run"<<endl; return 1; } }; class CWnd; class CWinApp : public CWinThread { public: CWinApp* m_pCurrentWinApp; CWnd* m_pMainWnd; public: CWinApp() { m_pCurrentWinApp = this; cout<<"CWinApp Constructor"<<endl; } ~CWinApp() { cout<<"CWinApp Destructor"<<endl; } virtual BOOL InitApplication() { cout<<"CWinApp::InitApplication"<<endl; return TRUE; } virtual BOOL InitInstance() { cout<<"CWinApp::InitInstance"<<endl; return TRUE; } virtual int Run() { cout<<"CWinApp::Run"<<endl; return CWinThread::Run(); } }; class CDocument : public CCmdTraget { public: CDocument() { cout<<"CDocument Constructor"<<endl; } ~CDocument() { cout<<"CDocument Destructor"<<endl; } }; class CWnd : public CCmdTraget { public: CWnd() { cout<<"CWnd Constructor"<<endl; } ~CWnd() { cout<<"CWnd Destructor"<<endl; } virtual BOOL Create(); BOOL CreateEx(); virtual BOOL PreCreateWindow(); }; class CFrameWnd : public CWnd { public: CFrameWnd() { cout<<"CFrame Constructor"<<endl; } ~CFrameWnd() { cout<<"CFrameWnd Destructor"<<endl; } BOOL Create(); virtual BOOL PreCreateWindow(); }; class CView : public CWnd { public: CView() { cout<<"CView Constructor"<<endl; } ~CView() { cout<<"CView Destructor"<<endl; } }; //global function CWinApp* AfxGetApp();
////////////////////////////////////////////////////////////////////
//MFC.cpp
#include "My.h" extern CMyWinApp theApp; CWinApp* AfxGetApp() { return theApp.m_pCurrentWinApp; } BOOL CWnd::Create() { cout<<"CWnd::Create"<<endl; return TRUE; } BOOL CWnd::CreateEx() { cout<<"CWnd::CreateEx"<<endl; PreCreateWindow(); return TRUE; } BOOL CWnd::PreCreateWindow() { cout<<"CWnd::PreCreateWindow"<<endl; return TRUE; } BOOL CFrameWnd::Create() { cout<<"CFrameWnd::Create"<<endl; CreateEx(); return TRUE; } BOOL CFrameWnd::PreCreateWindow() { cout<<"CFrameWnd::PreCreateWindow"<<endl; return TRUE; }
/////////////////////////////////////////////////////////////////////
//My.h #include <iostream> #include "MFC.h" using namespace std; class CMyWinApp : public CWinApp { public: CMyWinApp() { cout<<"CMyWinApp Constructor"<<endl; } ~CMyWinApp() { cout<<"CMyWinApp Destructor"<<endl; } virtual BOOL InitInstance(); }; class CMyFrameWnd : public CFrameWnd { public: CMyFrameWnd() { cout<<"CMyFrameWnd Constructor"<<endl; Create(); } ~CMyFrameWnd() { cout<<"CMyFrameWnd Destructor"<<endl; } BOOL PreCreateWindow() { cout<<"CMyFrameWnd::PreCreateWindow"<<endl; return CWnd::PreCreateWindow(); } };
////////////////////////////////////////////////////////////////////////
<pre class="cpp" name="code">//My.cpp #include "My.h" CMyWinApp theApp;//global object BOOL CMyWinApp::InitInstance() { cout<<"CMyWinApp::InitInstance"<<endl; m_pMainWnd = new CMyFrameWnd; return TRUE; } int main(int argc, char** argv) { cout<<"------------------------------"<<endl; CWinApp* pApp = AfxGetApp(); //CMyWinApp myApp; pApp->InitApplication(); pApp->InitInstance(); pApp->Run(); return 0; }
//My.cpp #include "My.h" CMyWinApp theApp;//global object BOOL CMyWinApp::InitInstance() { cout<<"CMyWinApp::InitInstance"<<endl; m_pMainWnd = new CMyFrameWnd; return TRUE; } int main(int argc, char** argv) { cout<<"------------------------------"<<endl; CWinApp* pApp = AfxGetApp(); //CMyWinApp myApp; pApp->InitApplication(); pApp->InitInstance(); pApp->Run(); return 0; }