您的位置:首页 > 运维架构 > 网站架构

编程学习笔记之MFC内部组织架构

2016-04-22 18:59 1086 查看
      MFC全称是Microsoft Foundation Classes,意为微软基础类库,是一个C++的类库,里面封装了大量的windows API尤其是win32 API函数,因为我们在开发win32应用程序的时候,需要做很多重复的步骤,比如注册窗口类、初始化窗口、创造窗口、更新窗口等,所以为了省却不必要的麻烦,微软将这些步骤打包封装成一个框架,里面有win32所必需的组件,这个“框架”就叫MFC。

      MFC源于win32,要弄清它们之间的关系,我们首先要理解MFC object与windows object之间的区别

1):MFC object是由c++的CWnd或其派生类定义的,在程序执行时由类中的构造函数创建,然后在执行类中析构函数的时候销毁。而windows object是window系统的一个内部数据结构实例,它由一个窗口句柄来引用,window系统为它分配系统资源,它是在MFC窗口创建之后创建的,一般由CWnd类中的Create函数所创建,得到的窗口句柄保存在CWnd的m_hWnd成员变量中,它可以被一个程序或用户的动作销毁【调用相应的sdk系统函数】。

2):windows object是属于低层的,而MFC object是高层的,后者封装了前者大部分的功能,MFC object的使用者不需要直接应用windows object的句柄来使用win32 API,而是用对应的MFC object函数来代替。我们可以从MFC object那里得到一个对应的windows object句柄,比如使用GetSafeHandle函数,也可以直接拿windows object里的句柄来创建一个新的MFC object,如果使用MFC的FromHandle函数,得到的是一个临时的MFC
object对象,而如果使用的是Attach,则会得到一个永久性对象。

3):MFC object对系统的其它进程是不可见的,而windows object则是全局性的,后者一旦创建,那么它的句柄便可以被系统的其它进程所使用,比如,A进程如果想对B进程发送消息,便可以通过获取B进程的窗口句柄来完成。

【声明:以上内容“借鉴”自百科词条,说是抄袭也不为过,笑。。。】

      接下来我们谈谈如何创建一个简单的MFC应用程序,本文以visual studio 2013为开发平台,首先打开vs2013,选择文件->新建->项目,接着选择visual C++下的MFC应用程序,文件名称我们取名叫test,点击下一步,在向导里面我们选择单文档,点击完成。至此,我们就生成了一个自己的MFC应用程序。按下F5会出现如此界面:



这个就是我们自己的MFC应用程序。

      我们再来看一下它的组织架构:



我们可以看到,这里面一共有5个类,其中test.cpp、testDoc.cpp与testView.cpp名字里面的“test”都是根据我们生成MFC应用程序时所取的名字来命名的,而无论我们给项目取什么名字,MainFrm.cpp和stdafx.cpp这两个类的名字是不会变得!我们双击一下test.cpp类,进入它的定义,如图:



我们发现,CtestApp是继承自CWinApp的,并且在这里【第54行】声明了一个CtestApp类型的全局变量theApp,这样当我们按下F5运行的时候,程序会首先构造一个全局变量theApp,然后因为构造子类实例会先执行父类的构造函数这个原理,程序再去执行CWinApp的构造函数【在CWinApp之前还继承自CWinThread,然后CWinThread上面还有父类,因为关系太过复杂,这里不再展开】,在这些都完成之后,然后才由MainCRTStartUp调用程序的主函数_tWinMain【这个_tWinMain是一个宏定义,其本来面目就是WinMain】,再然后在这个主函数_tWinMain里面,会调用一个AfxWinMain,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())
{
if (pThread->m_pMainWnd != NULL)
{
TRACE0("Warning: Destroying non-NULL m_pMainWnd\n");
pThread->m_pMainWnd->DestroyWindow();
}
nReturnCode = pThread->ExitInstance();
goto InitFailure;
}
nReturnCode = pThread->Run();
InitFailure:
#ifdef _DEBUG
// Check for missing AfxLockTempMap calls
if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
{
TRACE1("Warning: Temp map lock count non-zero (%ld).\n",
AfxGetModuleThreadState()->m_nTempMapLock);
}
AfxLockTempMaps();
AfxUnlockTempMaps(-1);
#endif
AfxWinTerm();
return nReturnCode;
}

注意第6行和第7行的代码,程序首先声明了一个CWinThread类型的对象pThread,然后又声明了一个CWinApp的对象pApp,并分别调用AfxGetThread与AfxGetApp函数为它们赋值【所有带有前缀Afx的函数,都表示这是一个全局函数】,事实上,这两个函数所返回的都是我们前面那个theApp对象的指针,即一个CtestApp类型的对象指针。了解这点之后,再来后面的代码就容易理解了,程序就是利用pThread与pApp这两个对象,完成一个窗口类的设计、注册、创建、显示更新等步骤。先说注册,在18行代码中,通过pThread->InitInstance()调用了CWinThread类中的方法InitInstance,其实这个InitInstance是一个虚函数,这就意味着会回到theApp的InitInstance中执行,在这里面,它会利用一个叫AfxEndDeferRegisterClass()来设计注册窗口类,MFC预先为我们设计了一些窗口类,然后在这里根据我们的需要为我们注册一下。接下来就是创建窗口了,那么程序会在哪里创建这个注册好的窗口呢?答案是类CMainFrame中的PreCreateWindow(),再接着跳转到父类CFrameWnd中PreCreateWindow方法中,利用里面的Create调用CreateEx来创建窗口【用了两个CreateEx函数互相调用,它们是重载的关系,即参数列表不同】。再接着就是显示和更新窗口,分别通过theApp对象里面的InitInstance函数调用来完成。最后的最后,就是我们的消息循环,看第25行代码,通过调用pThread中的Run方法来实现对外部消息的循环响应,因为pThread实际是一个指向theAPP对象的指针,而在theApp的实际类型是CtestApp,可是在这个类型的定义中,并没有关于Run方法的定义,这是因为这个Run方法是若干个上层父类CWinThread中的虚函数,所以程序到这里就回到了CWinThread类中的Run方法中,让我们看一下Run方法的定义:



其中红框内的函数调用,就是有关消息路由等动作了。(未完待续)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: