//////////////////////////////////////////////////////////////////////////////////////////
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. std::map中函数用法集合

    1 STL的map表里有一个erase方法用来从一个map中删除掉指令的节点  2 eg:  3 map<string,string> mapTest;  4 typedef map< ...

  2. Linux下并发网络设计之I/O复用

    I/O 流: 首先我们来定义流的概念,一个流可以是文件,socket,pipe等等可以进行I/O操作的内核对象. 不管是文件,还是套接字,还是管道,我们都可以把他们看作流. 之后我们来讨论I/O的操作 ...

  3. CSS hank

    CSS hank CSS hank是为了让CSS代码兼容不同浏览器,也可以通过CSS hank为不同的浏览器设置不同的CSS样式. CSS hank的3种表现形式: 类内部hank IE6能识别下划线 ...

  4. SPOJ 7001 VLATTICE - Visible Lattice Points(莫比乌斯反演)

    题目链接:http://www.spoj.com/problems/VLATTICE/ 题意:求gcd(a, b, c) = 1    a,b,c <=N 的对数. 思路:我们令函数g(x)为g ...

  5. MySQL 事物

    BEGIN DECLARE result INTEGER DEFAULT 0; -- 标记是否出错 DECLARE t_error INTEGER DEFAULT 0; -- 如果出现sql异常,则将 ...

  6. 简单十步让你全面理解SQL

    很多程序员认为SQL是一头难以驯服的野兽.它是为数不多的声明性语言之一,也因为这样,其展示了完全不同于其他的表现形式.命令式语言. 面向对象语言甚至函数式编程语言(虽然有些人觉得SQL 还是有些类似功 ...

  7. jackson的简单实用实例(json)

    一个json格式的字符串比如: {"status":10001,"code":"HDkGzI","pubkey":&qu ...

  8. Java "==和equals区别" 示例

    import java.util.Calendar; import java.util.Date; import java.util.Locale; public class test { publi ...

  9. poj 2653 计算几何

    #include <iostream> #include <cstring> #include <algorithm> #include <cmath> ...

  10. How to configure connectingstrings in Web.config

    先来看一下默认的连接SQL Server数据库配置<connectionStrings>   <add name="LocalSqlServer" connect ...