1、MFC程序的main函数封装在库中,MFC程序内没有main函数。
对于C和C++来讲,程序以main函数作为入口函数,整个程序都是从入口函数进入的。一般来说,main函数是C程序的入口点,WinMain是Windows程序的入口点。当系统监测到用户欲执行一个Windows程序时,调用加载器把程序加载,然后调用C startup code,后者再调用WinMain,开始执行程序。WinMain的4个参数由操作系统传入。
但是MFC从表面上看是没有main函数的。那它的main函数是怎么样的呢?
具体来说呢,MFC的main函数是长这样的:
// export WinMain to force linkage to this module
extern int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,_In_ LPTSTR lpCmdLine, int nCmdShow);
这就是MFC整个程序的main函数,也就是整个程序的入口。
它藏在哪里呢?它藏在MFC的源文件appmodul.cpp中。
那main函数与MFC程序是如何联系起来的呢?
根据C++的规则,全局变量是先于main函数执行的。而在MFC程序中,有一个全局的对象,如下所示:
extern CTestMFCApp theApp;
这个全局的对象是一个继承于CWinApp类的对象。当操作系统将程序加载并激活后,这个全局对象获得配置及初始化,因此它的构造函数也会运行,而先于main函数。因此可以认为,MFC开始的地方是CWinApp子类对象的初始化。甚至可以说,CWinApp在MFC中替代了WinMain在SDK中的地位,做了主要的工作,而main函数只是简单的调用一下CWinApp的方法。CWinApp主要通过以下3个函数来完成对程序的创建:
virtual BOOL InitApplication(); // 窗口的注册
virtual BOOL InitInstance(); // 窗口的创建
virtual int Run(); // 消息的分发
在全局对象theApp初始化结束后,开始运行AfxWinMain函数。AfxWinMain函数的主要框架为:
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine, int nCmdShow)
{
CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp();
pApp->InitApplication();
pThread->InitInstance();
nReturnCode = pThread->Run();
return nReturnCode;
}
先通过全局函数获得CWinApp和CWinThread全局对象的指针,因为调用main之前已经初始化了这两个类。CTestMFCApp初始化时也会初始化他的父类CWinApp,及父类的父类CWinThread。
而接下来就调用CWinApp的3个主要函数完成程序的创建。
因此总结一下,MFC程序的执行顺序是:
a)theApp全局对象定义处
b)XApp构造函数
c)WinMain函数
因此全局对象分配空间要先于main函数,theApp全局对象表示程序本身,类似于hInstance。
2、那么,MFC中默认类的关系为:
App类中InitInstance()驱动Doc,View,MainFrame。
3、MFC默认程序有2个窗口:
其一为MainFrame对象所代表的应用程序框架窗口;
其二为CXView对象所代表的视类窗口。
其中,第一类为第二类的父窗口。
4、MFC运行机制与Win32 SDK一致,流程都是:
设计窗口类——注册窗口类——创建窗口——显示&更新窗口——消息循环
5、MFC基本类的继承结构图:
6、MFC消息响应机制
MFC消息响应是可以由MFC类向导自动添加的。它会在以下3个地方添加内容。以绘制命令为例:
a)头文件中消息响应函数的声明
afx_msg void OnPaint();
b)源文件中的消息映射宏
ON_WM_PAINT();
所有这些消息映射的宏都位于一对宏之中:
BEGIN_MESSAGE_MAP(CXView, CView)
ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CtobedeletedView::OnFilePrintPreview)
ON_WM_CONTEXTMENU()
ON_WM_RBUTTONUP()
ON_WM_PAINT()
END_MESSAGE_MAP()
c)源文件中的函数实现
void CXView::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: 在此处添加消息处理程序代码
}
MFC没有采用虚函数进行消息响应,因为虚函数表太大。它采用消息映射方式,在每个类中定义一个消息——消息函数的静态对照表(消息映射表)。在处理消息时,搜索此表,调用消息函数。
注:
1、这篇文章的内容主要是对前段时间做项目时做的笔记的总结。笔记来源于当时查阅的博客。在写此篇文章时,为了将内容串联起来,参考了著名的《深入浅出MFC》。
2、MFC确实是很老了,也很难用,理应被替代。但是很多时候还是会用到。《深入浅出MFC》这本书挺不错的,可以详细了解Windows编程的各种机制。