MFC内部结构剖析

//////////////////////////////////////////////////////////////////////////////////////////
MFC程序的执行顺序依次是:theApp全局对象定义处、TestApp构造函数、WinMain。
程序在加载main函数之前,会先为全局变量和全局对象分配内存空间。
对于MFC程序来说,通过产生一个应用程序类的对象来唯一标识应用程序的实例。每一个MFC程序实例有且仅有一个该派生类的实例化对象,也就是theApp全局对象,该对象就表示了应用程序本身。
theApp对象的构造函数CtestApp在调用之前,会调用其父类CWinApp的构造函数,从而就把我们程序自己创建的类与Microsoft提供的基类关联起来了。CWinApp的构造函数完成程序运行时的一些初始化工作。

AfxWinMain函数:WinMain函数实际上是通过调用AfxWinMain函数来完成它的功能的。
AfxWinMain调用AfxGetThread函数获得一个CWinTread类型的指针。
接着AfxWinMain调用AfxGetApp函数获得一个CWinApp类型的指针。
由以下代码可以看出:AfxGetThread函数返回的就是AfxGetApp函数的结果。

  1. CWinThread* AFXAPI AfxGetThread()
  2. {
  3.         // check for current thread in module thread state 
  4.         AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
  5.         CWinThread* pThread = pState->m_pCurrentWinThread;
  6.         // if no CWinThread for the module, then use the global app 
  7.         if (pThread == NULL)
  8.                 pThread = AfxGetApp();
  9.         return pThread;
  10. }

复制代码

因此,AfxWinMain函数中的pThread和pApp这两个指针是一致的。

AfxGetApp函数返回的是在CWinApp构造函数中保存的this指针(详见CWinApp类定义的源文件:appcore.cpp)。
对本Test程序来说,这个this指针实际上指向的是CTestApp的对象:theApp。也就是说,pThread和pApp所指向的都是CTestApp类的对象,即theApp全局对象。

InitInstance函数:
pThread和pApp调用了三个函数(InitApplication、InitInstance和Run)去完成Win32程序所需要的几个步骤:设计窗口类、注册窗口类、创建窗口、显示窗口、更新窗口、消息循环以及窗口过程函数。
pApp首先调用InitApplication函数完成MFC内部管理方面的工作。
接着,调用pThread的InitInstance函数(其实是调用从CWinApp派生的应用程序类CTestApp中的虚函数InitInstance)。

MFC框架窗口 
1.设计和注册窗口:MFC已经为我们预定义了一些默认的标准窗口类,只需呀选择所需的窗口类,然后注册就可以了。
窗口类的注册由AfxEndDeferRegisterClass函数完成(AfxEndDeferRegisterClass函数首先判断窗口类的类型,然后赋予其相应的类名,这些类名是MFC预定义的,然后调用AfxRegisterClass函数注册窗口类)。
AfxRegisterClass函数首先获得窗口类的信息,如果该窗口已经注册,则直接返回一个真值;如果尚未注册,就调用RegisterClass函数注册该窗口类(注册窗口类使用的函数其实和Win32 SDK编程中所使用的函数一致)。
我们所创建的这个MFC应用程序Test,实际上有两个窗口。
其中之一:CMainFrame:: PreCreateWindow,这是在窗口产生之前被调用的。CMainFrame:: PreCreateWindow函数又调用了AfxDeferRegisterClass,而AfxDeferRegisterClass实际上是一个宏,指向AfxEndDeferRegisterClass(前面提到,此函数的功能就是注册窗口类)。

2.创建窗口: 
窗口的创建是由CWnd类的CreateEx函数实现的。(声明:AFXWin.h实现:WINCORE.CPP)
(在MFC的底层代码中CFrameWnd::Create调用了上述的CreateEx函数,而CFrameWnd:: LoadFrame又调用CFrameWnd::Create函数。此过程请自行跟踪。)

CWnd::CreateEx调用CMainFrame:: PreCreateWindow(PreCreateWindow是一个虚函数,所以这里实际上调用的是子类,即CMainFrame:: PreCreateWindow。这里再次调用此函数是为了在产生窗口之前让程序员有机会修改程序的外观。例如,去掉窗口最大化按钮等)

3.显示和更新窗口 

CTestApp:: m_pMainWnd
m_pMainWnd是一个CWnd类型并且保存了应用程序框架窗口对象的指针,也就是说m_pMainWnd变量是一个指向CMainFrame对象的指针。
CTestApp::InitInstance函数实现内部有如下两行代码:
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
这两行代码实现了窗口的显示和更新。

消息循环 

CWinThread::Run函数完成消息循环。

该函数由AfxWinMain::pThread函数调用。
形式:pThread->Run();

CWinThread::Run函数主要是一个for循环,该循环在收到一个WM_QUIT消息时退出。在此循环中调用了一个PumpMessage函数。

窗口过程函数 

AfxEndDeferRegisterClass函数源程序:wndcls.lpfnWndProc = DefWindowProc
这里指定的一个默认窗口过程DefWindowProc。但实际上MFC程序并不是把所有的消息都交给DefWindowProc这一默认窗口过程来处理。而是采用了一种“消息映射机制”。

///////////////////////////////////////////////////////////////////////////////////////////
梳理全过程 

1.首先利用全局应用程序对象theApp启动应用程序。正是产生了这个全局对象,基类CWinApp中的this指针才能指向这个对象。如果没有这个全局对象,程序在编译的时候不会出错,但在运行时就出错。
2.调用全局应用程序对象的构造函数,从而就会先调用其基类CWinApp的构造函数。后者完成应用程序的一些初始化工作,并将应用程序对象的指针保存起来。
3.进入WinMain函数。在AfxWinMain函数中可以获取子类(对Test程序来说,就是CTestApp类)的指针,利用此指针调用虚函数:InitInstance,根据多态性原理,实际上调用的是子类(CTestApp)的InitInstance函数。后者完成一些应用程序的初始化工作,包括窗口类的注册、创建,窗口的显示和更新。期间会多次调用CreateEx函数,因为一个单文档MFC应用程序有多个窗口,包括框架窗口、工具条、状态条等。
4.进入消息循环。虽然也设置了默认的窗口过程函数,但是,MFC应用程序实际上采用消息影射机制来处理各种消息的。当收到WM_QUIT消息时,退出消息循环,程序结束。
///////////////////////////////////////////////////////////////////////////////////////////

时间: 2024-08-02 22:52:53

MFC内部结构剖析的相关文章

关于MFC内部结构实用的一点看法

我们在编写程序或是在看MFC类的书籍的时候,总会看到书上让我们在某个地方添加某某 函数,响应什么消息.那么,到底为什么要在这地方加呢?为什么不能在其他地方添加消息 响应函数呢? 接下来,我们就共同来讨论一下吧. 1.MFC的运行步骤:(这 是对于文档视图结构的应用程序的) theApp(theApp())->//应用程序全局对象 的构造和内存分配 WinMain()->//进入主函数 AfxWinMain()->//调用 API InitAplacation()(应用程序的内部管理)-&

VC MFC专题

MFC程序如何实现给对话框添加背景图片 MFC游戏开发笔记十 游戏中的碰撞检测进阶:地图类型&障碍物 MFC游戏开发笔记九 游戏中的碰撞判定初步&怪物运动简单AI MFC游戏开发笔记八 游戏特效的实现(二):粒子系统 MFC游戏开发笔记七 游戏特效的实现(一):背景滚动 MFC游戏开发笔记六 图像双缓冲技术:实现一个流畅的动画 MFC游戏开发笔记五 定时器和简单动画 MFC游戏开发笔记四 键盘响应和鼠标响应:让人物动起来 MFC游戏开发笔记三 游戏贴图与透明特效的实现 MFC游戏开发笔记二

现在IT行业那个编程语言最流行呢?

问题描述 我学了C#,Java也略懂,最近去面试了,可是人家说现在市场上用C#编程的不多,倍受打击,希望IT行业的前辈们给小弟指条明路,现在IT行业编程语言最流行也最具有前景的是那种呢?它跟其他语言(比如C#)相比好在哪里?谢谢 解决方案 解决方案二:ASP.NET(C#),腾迅要人,盛大要人,阿里巴巴要人.不知道你听谁说市场上用C#编码的不多.解决方案三:他不要当然说要的不多咯解决方案四:你学好了,你就会感觉都在招.解决方案五:C...解决方案六:那要看你在什么地方了,大城市(像北京,上海等)

孙鑫VC++讲座笔记-(4)MFC消息映射机制的剖析

孙鑫VC++讲座笔记-(4)MFC消息映射机制的剖析 一,消息映射机制 1,消息响应函数:(例:在CDrawView类响应鼠标左键按下消息) 1)在头文件(DrawView.h)中声明消息响应函数原型. //{{AFX_MSG(CDrawView) //注释宏 afx_msg void OnLButtonDown(UINT nFlags, CPoint point); //}}AFX_MSG //注释宏 说明: 在注释宏之间的声明在VC中灰色显示.afx_msg宏表示声明的是一个消息响应函数.

深入剖析MFC中Windows消息处理机制

本人对Windows系统.MFC谈不上有深入的了解,但对MFC本身包装API的机制很有兴趣,特别是读了候老师的<深入浅出MFC>后,感觉到Visual C++的Application FrameWork十分精制.在以前,我对SDI结构处理消息有一定的认识,但对于模式对话框的消息机制不了解,读了<深入>一书也没能得到解决,近日,通过在网友的帮助和查阅MSDN,自认为已经了解.一时兴起,写下这些文字,没有其它目的,只是希望让后来者少走弯路,也希望和我一样喜欢"钻牛角尖&quo

剖析MFC六大关键技术(五六)--消息映射与命令传递

说到消息,在MFC中,"最熟悉的神秘"可算是消息映射,那是我们刚开始接触MFC时就要面对的东西.有过SDK编程经验的朋友转到MFC编程的时候,一下子觉得什么都变了样.特别是窗口消息及对消息的处理跟以前相比,更是风马牛不相及的.如文档不是窗口,是怎样响应命令消息的呢? 初次用MFC编程,我们只会用MFC ClassWizard为我们做大量的东西,最主要的是添加消息响应.记忆中,如果是自已添加消息响应,我们应何等的小心翼翼,对BEGIN_MESSAGE_MAP()--END_MESSAGE

深入剖析MFC中对于Windows消息处理、运行机制

序:        本人对Windows系统.MFC谈不上有深入的了解,但对MFC本身包装API的机制很有兴趣,特别是读了候老师的<深入浅出MFC>后,感觉到VISUAL C++的Application FrameWork十分精制[不敢用"完美"一词].在以前,我对SDI结构处理消息有一定的认识,但对于模式对话框的消息机制不了解,读了<深入>一书也没能得到解决,近日,通过在CSDN上网友的帮助,和查阅MSDN,自认为已经了解.一时兴起,写下这些文字,没有其它目的

剖析SEO:搜索引擎优化“勿掉进SEO陷阱”(二)

在上一节<剖析SEO:搜索引擎优化"勿掉进SEO陷阱"(一)>中,我们分析了五条可能在搜索引擎优化中出现的优化盲点.如何进而有效的避免搜索引擎埋下的不透明"陷阱"呢?本章我们进一步加以总结: 一:nofollow优化 对于nofollow的定义在这里不做过多专业强调,普通站长只需知晓:nofollow可屏蔽搜索引擎索引链接就可以了.看到这里可能会有些站长要问:网站内链不是越多越好,为什么还要屏蔽链接呢?答案其实也很简单:无效的内部链接,只会稀释掉关键字链

深入分析MFC中的CArray类

我们在使用vc进行比较复杂的编程时,经常需要用到复杂的数组结构,并希望能实现动态 管理.由于C++并不支持动态数组,MFC提供了一个CArray类来实现动态数组的功能.有效的 使用CArray类,可以提高程序的效率. MFC提供了一套模板库,来实现一些比较常见的 数据结构如Array,List,Map.CArray即为其中的一个,用来实现动态数组的功能. CArray是从CObject派生,有两个模板参数,第一个参数就是CArray类数组元素的变量类型 ,后一个是函数调用时的参数类型. 我们有一