一、头文件说明

STDAFX.H

这个文件用来作为Precompile header file,其内只是载入其他的MFC头文件。应用程序通常会准备自己的头STDAFX.H。

AFXWIN.H

每一个Windows MFC程序都必须载入它,因为它以及它所载入的文件声明了所有的MFC类。

在WINDEF.H中有CALLBACK的定义

#define CALLBACK _stdcall     //是一种函数调用习惯

在AFXWIN.H中有afx_msg的定义

#define afx_msg        //故意安排一个空位置,也许以后版本会用到。

所有MFC头文件均置于\MSVC\MFC\INCLUDE中。这些文件在编译过程中耗费大量时间,所以有必要设定Precompiled header。一个应用程序在常需要不断地编译。Windows程序载入的.H文件非常巨大但内容不变,编译器浪费在上面的时间非常多。Precompiled header就是将.H文件第一次编译后的结果存储起来,第二次再编译时就可以直接从磁盘中取出来用。

二、MFC程序的来龙去脉

CWinApp代表程序本体。CFrameWnd代表一个主框架窗口。必须以这两个类为基础,派生自己的类,并改写其中一部分成员函数。

全局对象theAPP,就是application object。每一个应用程序都应该改写CWinApp::InitInstance()函数。

MFC把有着相当固定行为的WinMain内部操作封装在CWinApp中,把有着相当固定行为的WinProc内部操作封装在CFrameWnd中。

传统SDK程序WinMain完成的工作,现在由CWinApp的三个函数完成。

Virtual BOOL InitApplication();

Virtual BOOL InitInstance();

Virtual int Run();

CWinApp继承CWinThread了成员变量m_pMainWnd,代表主窗口。CFrameWnd主要用来掌握一个窗口,它是用来取代SDK程序中的窗口函数的地位。

我们并未写WinMain程序代码,这是MFC早已准备好并由链接器直接加到应用程序代码中的。_tWinMain函数的_t是为了支持UniCode而准备的一个宏。

下面是AfxWinMain代码。

将以上代码整理一下就得到下面这段代码。

AfxGetApp 是一个全局函数,它取得CMyWinApp 对象指针。AfxWinInit 是继CWinApp 构造式之后的第一个动作。AfxWinInit 之后的动作是pApp->InitApplication。

以上代码这些动作都是MFC 为了内部管理而做的。继InitApplication 之后, AfxWinMain 调用pApp->InitInstance。

一般而言,CMyWinApp只改写CWinApp中的InitInstance,通常它不改写InitApplication和Run。

注意:应用程序一定要改写虚拟函数InitInstance,因为它在CWinApp 中只是个空函数,没有任何内建(预设)动作。

CMyWinApp::InitInstance 一开始new 了一个CMyFrameWnd 对象,准备用作主框窗口的C++ 对象。CFrameWnd::Create 在产生窗口之前,会先引发窗口类别的注册动作。

下面是CreateEx代码。

调用的PreCreateWindow 是虚拟函数, CWnd 和CFrameWnd 之中都有定义。由于this 指针所指对象的缘故,这里应该调用的是CFrameWnd::PreCreateWindow。

利用AfxDeferRegisterClass宏注册窗口类。不同类别的PreCreateWindow 成员函数都是在窗口产生之前一刻被调用,准备用来注册窗口类别。

CMyFrameWnd::CMyFrameWnd 结束后, 窗口已经诞生出来;程序流程又回到CMyWinApp::InitInstance ,于是调用ShowWindow 函数令窗口显示出来,并调用UpdateWindow 函数令Hello 程序送出WM_PAINT 消息。

窗口类别注册好了,窗口诞生并显示出来了, UpdateWindow 被调用,使得消息队列中出现了一个WM_PAINT 消息,等待被处理。现在,执行pApp->Run。

Message Map 机制是为了提供更方便的程序接口(例如宏或表格),让程序员很方便就可以建立起消息与处理例程的对应关系。

MFC 提供给应用程序使用的「很方便的接口」是两组宏。以Hello 的主窗口为例,第一个动作是在HELLO.H 的CMyFrameWnd 加上DECLARE_MESSAGE_MAP:

第二个动作是在HELLO.CPP 的任何位置(当然不能在函数之内)使用宏如下:

MFC 把消息主要分为三大类, Message Map 机制中对于消息与函数间的对映关系也明定以下三种:

1、标准Windows 消息(WM_xxx)的对映规则:

2、命令消息( WM_COMMAND)的一般性对映规则是:ON_COMMAND(<id>,<memberFxn>)

例如:

ON_COMMAND(IDM_ABOUT, OnAbout)

ON_COMMAND(IDM_FILENEW, OnFileNew)

ON_COMMAND(IDM_FILEOPEN, OnFileOpen)

ON_COMMAND(IDM_FILESAVE, OnFileSave)

3、Notification 消息(由控制组件产生,例如BN_xxx)的对映机制的宏分为好几种(因为控制组件本就分为好几种),以下各举一例做代表:

各个消息处理函数均应以afx_msg void 为函数类型。如果某个消息在Message Map 中找不到对映记录,它会往基础类别流窜,这个消息流窜动作称为Message Routing。如果一直窜到最基础的类别仍找不到对映的处理例程,由默认函数来处理。

【总结】

凡是由你设计而却由Windows 系统调用的函数,统称为callback 函数。这些函数都有一定的类型,以配合Windows的调用动作。

callback 函数是给Windows 调用的, Windows 并不经由任何对象调用这个函数,也就没有传递this 指针给callback 函数,于是导至堆栈中有一个随机变量会成为this 指针,而其结果当然是程序的崩溃了。

要把某个函数用作callback 函数,两个方法可以做到这一点:

(1)不要使用类的成员函数(也就是说,要使用全局函数)做为callback 函数。

(2)使用static 成员函数。也就是在函数前面加上static 修饰词。

【笔记】《深入浅出MFC》第6章 MFC程序的生死因果的更多相关文章

  1. 深入浅出MFC——MFC程序的生死因果(三)

    1. 本章主要目的:从MFC程序代码中检验出一个Windows程序原本该有的程序进入点(WinMain).窗口类注册(RegisterClass).窗口产生(CreateWindow).消息循环(Me ...

  2. [转]《深入浅出MFC》– MFC程序的生死因果

    1.首先MFC程序需要哪些函数库? Windows C Runtime函数库 LIBC.LIB       C Runtime函数库的静态链接版本 MSVCRT.LIB     C Runtime函数 ...

  3. 深入浅出Win32多线程设计之MFC的多线程-线程与消息队列(经典)

    1.创建和终止线程 在MFC程序中创建一个线程,宜调用AfxBeginThread函数.该函数因参数不同而具有两种重载版本,分别对应工作者线程和用户接口(UI)线程. 工作者线程 CWinThread ...

  4. C++MFC编程笔记day01 MFC介绍、创建MFC程序和重写消息处理

    一.MFC概念和作用 1.全称Microsoft Foundation Class Library,我们称为微软基础类库,封闭了绝大部分的win32 Api函数,C++语法中的数据结构,程序的运行流程 ...

  5. MFC通过ODBC连接Mysql程序

    分享到 一键分享 QQ空间 新浪微博 百度云收藏 人人网 腾讯微博 百度相册 开心网 腾讯朋友 百度贴吧 豆瓣网 搜狐微博 百度新首页 QQ好友 和讯微博 更多... 百度分享 MFC通过ODBC连接 ...

  6. MFC原理第一讲.MFC的本质.以及手工编写MFC的程序

    MFC原理第一讲.MFC的本质.以及手工编写MFC的程序 PS: 这个博客属于复习知识.从头开始讲解. 在写这篇博客之前.已经写了3篇MFC的本质了.不过掌握知识点太多.所以从简重新开始. 一丶MFC ...

  7. VC++ MFC单文档应用程序SDI下调用glGenBuffersARB(1, &pbo)方法编译通过但执行时出错原因分析及解决办法:glewInit()初始化的错误

    1.问题症状 在VC++环境下,利用MFC单文档应用程序SDI下开发OpenGL程序,当调用glGenBuffersARB(1, &pbo)方法编译通过但执行时出错,出错代码如下: OpenG ...

  8. MFC DLL 可以封装MFC的窗体 供别的MFC程序使用

    MFC DLL  可以封装MFC的窗体 供别的MFC程序使用 在庞大程序分工里面 非常可取. 可以细分每个窗体就是单独的 模块. [后续不断完善]

  9. API、Win32 SDK、Win32项目、MFC、Windows窗体应用程序的区别

    [原]API.Win32 SDK.Win32项目.MFC.Windows窗体应用程序的区别 首先来看一下每一个术语的定义: API:Application Programming Interface. ...

随机推荐

  1. 【入门教程】kafka环境搭建以及基础教程

    问题导读 1.Kafka独特设计在什么地方?2.Kafka如何搭建及创建topic.发送消息.消费消息?3.如何书写Kafka程序?4.数据传输的事务定义有哪三种?5.Kafka判断一个节点是否活着有 ...

  2. [Shiro] - Shiro之进阶

    上一个知识点ssm, 哪里需要权限,哪里写注解@RequirePermission就行. 但是,真正项目开发的时候, 这种方式就很有局限性了, 当权限配置关系发生变化, 每次都要修改代码, 编译打包重 ...

  3. 【java工具类】java做的一个xml转Excel工具,基于maven工程

    说明:适合数据库导出为xml时转成Excel 本工具将上传至GitHub:https://github.com/xiaostudy/xiaostudyAPI3 doc4j的maven依赖 <!- ...

  4. HDU 5873 Football Games(竞赛图兰道定理)

    http://acm.hdu.edu.cn/showproblem.php?pid=5873 题意: 现在有比赛,所有队伍两两进行比赛,赢的积2分,输的积0分,如果平局的话就各自都积1分,现在给出每只 ...

  5. 51nod 1042 数字0-9的数量 数位dp

    1042 数字0-9的数量 基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题  收藏  关注 给出一段区间a-b,统计这个区间内0-9出现的次数.   比如 10-1 ...

  6. vue-cli 组件运用

    // components ----- helloworld.vue <script> export default { name: 'Hellowworld', props: { //接 ...

  7. 装B必备之 快捷键配置

    作为一个程序员 所有程序都用快捷来这是装B必备的无形装B 最为致命.... 开始搞起 第一步配置环境变量 在系统D盘新建一个文件夹  D:\cache; 然后把这个路径 配置上 D:\cache; 最 ...

  8. 在centos下解决 “致命错误:curses.h:没有那个文件或目录”

    当在centos下编译带有头文件<curses.h> 的程序时,出现以下错误: “致命错误:curses.h:没有那个文件或目录” ,最后在“https://zhidao.baidu.co ...

  9. Android 获取本地外网IP、内网IP、计算机名等信息

    一.获取本地外网IP public static String GetNetIp() { URL infoUrl = null; InputStream inStream = null; try { ...

  10. 寻找重复的子树 Find Duplicate Subtrees

    2018-07-29 17:42:29 问题描述: 问题求解: 本题是要求寻找一棵树中的重复子树,问题的难点在于如何在遍历的时候对之前遍历过的子树进行描述和保存. 这里就需要使用之前使用过的二叉树序列 ...