一、MFC的结构
一个标准的MFC程序外貌
二、 MFC程序的启动与死亡顺序
那么 ,现在来经历一个MFC程序的完整生命过程
1、创建Application theApp
下图所示,创建一个MFC工程,在MFCApplication1.cpp中有个全局变量CMFCApplication1App theApp;这个全局对象一产生,便执行其构造函数。CWinApp之中的成员变量将因为theApp这个全局对象的诞生而获得配置与初值。
2、WinMain登场
用SDK编程序时,程序的入口点是WinMain函数,而在MFC程序里我们并没有看到WinMain函数,哦!~ 原来它是被隐藏在MFC代码里面了。当theApp配置完成后,WinMain登场,慢!细看程序,并没连到WinMain函数的代码啊!这个我也不知道,MFC早已准备好并由链接器直接加到应用程序代码中了,原来它在APPMODUL.CPP里面,好,我们就认为当theApp配置完成后,程序就转到APPMODUL.CPP来了。那执行什么呢?看看下面从APPMODUL.CPP摘出来的代码:
extern "C" int WINapi
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
_tWinMain函数的“_t”是为了支持Unicode而准备的一个宏。
_tWinMain函数返回值是AfxWinMain函数的返回值,AfxWinMain函数定义于WINMAIN.CPP第21行,稍加整理,去芜存菁,就可以看到这个“程序进入点”主要做些什么事:
nt AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
int nReturnCode = -1;
CWinApp* pApp = AfxGetApp();
AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
pApp->InitApplication();
pApp->InitInstance()
nReturnCode = pApp->Run();
AfxWinTerm();
return nReturnCode;
}
AfxGetApp()函数是取得CMyWinApp对象指针,故上面函数第6至8行相当于调用:
CMyWinApp::InitApplication();
CMyWinApp::InitInstance()
CMyWinApp::Run();
3、AfxWinInit——AFX内部初始化操作
AfxWinInit是继CWinApp构造函数之后的第一个操作,主要做的是AFX内部初始化操作,该函数定义于APPINIT.CPP第24行,这里就不掏出来了,你自己搜出来啃吧!
4、执行CWinApp::InitApplication
AfxWinInit之后的操作是pApp->InitApplication,我们已知道pApp指向CMyWinApp对象,当调用:
pApp->InitApplication();
相当于调用:
CMyWinApp::InitApplication();
但是你要知道,CMyWinApp继承自CWinApp,而InitApplication又是CWinApp的一个虚拟函数,我们并没有改写它(大部分情况下不需改写它),所以上述操作相当于调用:
CWinApp::InitApplication();
此函数定义于APPCORE.CPP第125行,你自己搜出来看吧!我就不搬出来了,里面的操作都是MFC为了内部管理而做的(其实我也看不懂,知道有这回事就好了)。
5、执行CWinApp::InitInstance
继InitApplication函数之后,AfxWinMain调用pApp->InitInstance。当程序调用:
pApp->InitInstance();
相当于调用:
CMyWinApp::InitInstance();
但是你要知道,CMyWinApp继承自CWinApp,而InitInstance又是CWinApp的一个虚拟函数。由于我们改写了它,所以上述操作就是调用我们自己(CMyWinApp)的这个InitInstance函数。
6、CFrameWnd::Create产生主窗口(并先注册窗口类)
在已经来到CWinApp::InitInstance了,该函数先new一个CMyFrameWnd对象,从而产生主窗口。在创建CMyFrameWnd对之前,要先执行构造函数CMyFrameWnd::CMyFrameWnd(),该函数用Create函数产生窗口:
CMyFrameWnd::CMyFrameWnd()
{
Create(NULL, "Hello MFC", WS_OVERLAPPEDWINDOW, rectDefault, NULL, "MainMenu");
}
7、窗口显示与更新
CMyFrameWnd::CMyFrameWnd结束后,窗口已经诞生出来;程序流程又回到CMyWinApp::InitInstance,于是调用ShowWindow函数令窗口显示出来,并调用UpdateWindow函数令程序送出WM_PAINT消息。在SDK程序中,消息是通过窗口函数来处理,而现在窗口函数在哪里、又如何送到窗口函数手中呢?那要从CWinApp::Run说起了。
8、执行CWinApp::Run——程序生命的活水源头
在执行完CMyWinApp::InitInstance函数后,程序的脚步到了AfxWinMain函数的pApp->Run了,现在我们已知道这将执行CWinApp::Run函数,该函数定义于APPCORE.CPP第391行,下面是程序代码:
int CWinApp::Run()
{
if (m_pMainWnd == NULL && AfxOleGetUserCtrl())
{
// Not launched /Embedding or /Automation, but has no main window!
TRACE0("Warning: m_pMainWnd is NULL in CWinApp::Run - quitting application.n");
AfxPostQuitMessage(0);
}
return CWinThread::Run();
}
9、把消息与处理函数连接在一起——Message Map机制
到此,主窗口已经产生,等待的就是各种消息了,然后调用相应的处理函数,然而消息和处理函数怎样连接在一起呢?MFC采用了Message Map机制(消息映射机制),提供给应用程序使用的“很方便的接口”的两组宏,这里就不细讲了。
所以,总的调用结构就是
三、 总结
参考: