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;
}