//////////////////////////////////////////////////////////////////////////////////////////
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消息时,退出消息循环,程序结束。
///////////////////////////////////////////////////////////////////////////////////////////

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

  1. 我的MFC学习之路(一)

    因为项目需求,我开始应用MFC写程序.具体接触MFC的时间大概也有两个月了.现在的水平算是刚刚踏入了MFC大门的半只脚.目前能基本使用MFC Class Wizard,可以根据实例仿照完成需求,小范围 ...

  2. 让DB2跑得更快——DB2内部解析与性能优化

    让DB2跑得更快——DB2内部解析与性能优化 (DB2数据库领域的精彩强音,DB2技巧精髓的热心分享,资深数据库专家牛新庄.干毅民.成孜论.唐志刚联袂推荐!)  洪烨著 2013年10月出版 定价:7 ...

  3. pg 资料大全1

    https://github.com/ty4z2008/Qix/blob/master/pg.md?from=timeline&isappinstalled=0 PostgreSQL(数据库) ...

  4. <MFC_1>深入剖析MFC的WinMain和消息机制

    一.开篇引论 熟悉Win32开发的朋友,应该非常了解它的基本组成和流程 1. WinMain:书写窗口类(WNDCLASS) -> 注册窗口类 -> 创建窗口 -> 显示窗口和更新窗 ...

  5. MFC程序执行过程剖析

    一 MFC程序执行过程剖析 1)我们知道在WIN32API程序当中,程序的入口为WinMain函数,在这个函数当中我们完成注册窗口类,创建窗口,进入消息循环,最后由操作系统根据发送到程序窗口的消息调用 ...

  6. MFC程序执行过程剖析(转)

    一 MFC程序执行过程剖析 1)我们知道在WIN32API程序当中,程序的入口为WinMain函数,在这个函数当中我们完成注册窗口类,创建窗口,进入消息循环,最后由操作系统根据发送到程序窗口的消息调用 ...

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

    序: 本人对Windows系统.MFC谈不上有深入的了解,但对MFC本身包装API的机制很有兴趣,特别是读了候老师的<深入浅出MFC>后,感觉到VISUAL C++的Application ...

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

    说到消息,在MFC中,“最熟悉的神秘”可算是消息映射,那是我们刚开始接触MFC时就要面对的东西.有过SDK编程经验的朋友转到MFC编程的时候,一下子觉得什么都变了样.特别是窗口消息及对消息的处理跟以前 ...

  9. 第3章 MFC框架程序剖析

    参考: https://blog.csdn.net/u014162133/article/details/46573873 1. 2.MFC简介:MFC(Microsoft Foundation Cl ...

随机推荐

  1. Struts2 学习笔记20 类型转换part2 写自己的转换器

    之前说的是调用Struts2的默认转换器,现在我们来说以下写自己的转换器,这个一般不常用,在访问不是自己写的类中可能用到.我们一点点来,因为写自己的转换器需要注意的东西还是很多的. 我们还是用之前的项 ...

  2. 记userscripts.org

    发现一些Firefox用户脚本不起作用,userscripts.org访问不能有一个很长的一段时间,我还以为出了什么问题没出去检查.前几天有时间检查脚本,在路上,然后返回到userscripts.or ...

  3. iOS中Block介绍(二)内存管理与其他特性

    我们在前一章介绍了block的用法,而正确使用block必须要求正确理解block的内存管理问题.这一章,我们只陈述结果而不追寻原因,我们将在下一章深入其原因. 一.block放在哪里 我们针对不同情 ...

  4. String、StringBuffer和StringBuild的区别

    public class Test1 { public static void stringReplace (String text) { text = text.replace('j','i') ; ...

  5. iOS工程上传AppStore时遇到的问题“ERROR ITMS-90046”解析

    在我们将代码写完整,测试没有bug之后,我们就可以将它上传到AppStore了,上传的过程只要操作正确并不会有太大的问题,但是打包的过程中会出现一些小问题,导致打的包不能上传或者上传的时候会出现错误. ...

  6. Java如何实现对Mysql数据库的行锁

    场景如下:     用户账户有余额,当发生交易时,需要实时更新余额.这里如果发生并发问题,那么会造成用户余额和实际交易的不一致,这对公司和客户来说都是很危险的. 那么如何避免:     网上查了下,有 ...

  7. 跳出for循环

    如下面,有两个循环,break只能退出一个for循环,不能直接跳过第二个for循环 for (Type type : types) { for (Type t : types2) { if (some ...

  8. python自学笔记(二)python基本数据类型之字符串处理

    一.数据类型的组成分3部分:身份.类型.值 身份:id方法来看它的唯一标识符,内存地址靠这个查看 类型:type方法查看 值:数据项 二.常用基本数据类型 int 整型 boolean 布尔型 str ...

  9. java 显示视频时间--玩的

    1.显示视频时间 package view.time; import it.sauronsoftware.jave.Encoder; import it.sauronsoftware.jave.Mul ...

  10. js 中的bind函数

    bind是Function.prototype中内置函数 作用是指定函数作用域 代码参考 http://blog.csdn.net/load_life/article/details/7200381 ...