闲来无事,来探究一下MFC的原理,先前看了好多前辈写的探究方法,这次站在个人菜鸟的角度,还说一下MFC的原理。
一个win32程序,主要由一下几个步骤组成:设计窗口,注册窗口,创建窗口,显示窗口,消息循环。
MFC程序的函数的入口函数Main()函数为WinMain(),位于appmodul.cpp中:
再次跟踪AfxWInMain()函数,进入到winmain.cpp中,
在这个函数中只看到了,消息循环,没有看到设计窗口,注册窗口,创建窗口,显示窗口等过程,那这些过程是在哪里调用的呢?
首先说明一下,以Afx开头的函数,都是框架类函数,都是一些儿全局函数。我们来看一下:
CWinApp* pApp = AfxGetApp();
该代码得到了一个CWinApp对象,那么该CWinApp对象时在哪里进行赋值的呢?
我们进入到CWinApp的构造函数:
ASSERT(AfxGetThread() == this);该行代码将当前的CWInApp赋给该值。由于这里使用了this指针,这个this指针也可能是派生类的。在这里赋值,然后在winmain函数中得到。
到目前为止,我们还没有看到设计窗口,注册窗口,创建窗口,显示窗口的操作;那这些儿操作会在哪里呢?我们在WinMain()函数,只发现了一个CWinApp(CWinApp从CWinThread派生,将他们看做一个对象)对象,那么这个对象会不会设计窗口,注册窗口,创建窗口,显示窗口这些造作在这个类中进行呢?
我们用VS(本人使用VS2010)建立一个单文档应用程序。
构建程序之后,我们会看到一个全局变量
这个是唯一的一个CWinApp全局变量。在进入WinMain()函数之前,程序会先构造全局变量(可以自己写程序验证)。因为会先进入CWinApp的构造函数中,因此将该theApp对象赋值给AfxGetThread()这个全局指针。
我们再看WinMain(0函数,可以看到,有一个pThread->InitInstance();由于CWinApp从CWinThread派生,因此,这个pThread也是指向一个CWinApp对象,即theApp对象。
他调用的InitInstance()函数,我们进入CTestMFCPrincipleApp的InitInstance()看一下,看到了
我们发现了显示窗口与更新窗口,m_pMainWnd是theApp的一个公有成员变量CWnd*类型,在单文档应用程序中,m_pMainWnd主要是指向CMainFrame类,即主框架类。
我们先来看一下,这个函数ProcessShellCommand()
可以看到一个OpenDocumentFile(),跟踪这个函数
可以看到一个m_pDocManager的成员变量,这个成员变量就是是文档管理的对象,在ProcessShellCommand()函数前,我们看到了AddDocTemplate(pDocTemplate);这个就是把这个单文档程序加入到这个文档管理中,我们跟踪m_pDocManager->OpenDocumentFile(lpszFileName);发现调用的其实是pDocTemplate的OpenDocumentFile(),即这个当文档模板的OpenDocumentFile()函数,我们进入到CSingleDocTemplate::OpenDocumentFile()查看代码:
发现这个CreateNewFrame()函数,跟踪这个函数
找到这个pFrame->LoadFrame()函数,发现跟踪pFrame函数就是刚才的CMainFrame函数。跟踪LoadFrame()函数,查看代码:
找到这个Create()函数,创建框架的函数,跟踪这个Create()函数
看到这个CreateEx函数,这个函数,这个函数熟悉了吧,其实是CWnd的创建函数,查看代码:
至此,我们已经找到了创建一个窗口的全部过程,设计窗口->注册窗口->创建窗口->显示窗口->消息循环。由于这个例子是基于一个单文档应用程序,所以步骤稍显复杂,不过原理都是一样的,MFC的封装增加了我们理解这个原理的难度。其主要思想,就是构建一个全局对象,根据一个全局对象来实现各个窗口创建过程,如果不理解C++多态的概念,理解起来会很复杂的。所以如果想理解MFC的原理,那么理解C++的多态是必须的。