【笔记】《深入浅出MFC》第6章 MFC程序的生死因果
一、头文件说明
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程序的生死因果的更多相关文章
- 深入浅出MFC——MFC程序的生死因果(三)
1. 本章主要目的:从MFC程序代码中检验出一个Windows程序原本该有的程序进入点(WinMain).窗口类注册(RegisterClass).窗口产生(CreateWindow).消息循环(Me ...
- [转]《深入浅出MFC》– MFC程序的生死因果
1.首先MFC程序需要哪些函数库? Windows C Runtime函数库 LIBC.LIB C Runtime函数库的静态链接版本 MSVCRT.LIB C Runtime函数 ...
- 深入浅出Win32多线程设计之MFC的多线程-线程与消息队列(经典)
1.创建和终止线程 在MFC程序中创建一个线程,宜调用AfxBeginThread函数.该函数因参数不同而具有两种重载版本,分别对应工作者线程和用户接口(UI)线程. 工作者线程 CWinThread ...
- C++MFC编程笔记day01 MFC介绍、创建MFC程序和重写消息处理
一.MFC概念和作用 1.全称Microsoft Foundation Class Library,我们称为微软基础类库,封闭了绝大部分的win32 Api函数,C++语法中的数据结构,程序的运行流程 ...
- MFC通过ODBC连接Mysql程序
分享到 一键分享 QQ空间 新浪微博 百度云收藏 人人网 腾讯微博 百度相册 开心网 腾讯朋友 百度贴吧 豆瓣网 搜狐微博 百度新首页 QQ好友 和讯微博 更多... 百度分享 MFC通过ODBC连接 ...
- MFC原理第一讲.MFC的本质.以及手工编写MFC的程序
MFC原理第一讲.MFC的本质.以及手工编写MFC的程序 PS: 这个博客属于复习知识.从头开始讲解. 在写这篇博客之前.已经写了3篇MFC的本质了.不过掌握知识点太多.所以从简重新开始. 一丶MFC ...
- VC++ MFC单文档应用程序SDI下调用glGenBuffersARB(1, &pbo)方法编译通过但执行时出错原因分析及解决办法:glewInit()初始化的错误
1.问题症状 在VC++环境下,利用MFC单文档应用程序SDI下开发OpenGL程序,当调用glGenBuffersARB(1, &pbo)方法编译通过但执行时出错,出错代码如下: OpenG ...
- MFC DLL 可以封装MFC的窗体 供别的MFC程序使用
MFC DLL 可以封装MFC的窗体 供别的MFC程序使用 在庞大程序分工里面 非常可取. 可以细分每个窗体就是单独的 模块. [后续不断完善]
- API、Win32 SDK、Win32项目、MFC、Windows窗体应用程序的区别
[原]API.Win32 SDK.Win32项目.MFC.Windows窗体应用程序的区别 首先来看一下每一个术语的定义: API:Application Programming Interface. ...
随机推荐
- C# 新Form各事件执行顺序
1. 构造函数 2. Load() 3. Show() 4. Acticated()
- 获取公网IP地址
https://ipip.yy.com/get_ip_info.php http://pv.sohu.com/cityjson?ie=utf-8 http://www.ip168.com/json.d ...
- BZOJ 4571 【SCOI2016】 美味
题目链接:美味 如果题目里面没有那个\(a_i\),这道题就可以直接在\(Trie\)树上走一走就做完了.现在多了个\(a_i\),\(Trie\)树就无能为力了. 我们考虑一下在\(Trie\)树上 ...
- 部署showdoc
1.下载 https://github.com/star7th/showdoc 2.解压 sudo tar -zvxf ~/showdoc-2.4.5.tar.gz -C /home/wwwroot/ ...
- Redis之列表类型命令
Redis 列表(List) Redis列表是简单的字符串列表,按照插入顺序排序.你可以添加一个元素到列表的头部(左边)或者尾部(右边) 一个列表最多可以包含 232 - 1 个元素 (4294967 ...
- C++STL1--set
C++STL1--set 一.说明 set的用法:单一元素,自动排序set的方法:用编译器的提示功能即可,不需要自己记 二.简单测试 /* 安迪的第一个字典 set的用法:单一元素,自动排序 set的 ...
- 手动添加 launcher 到 Ubuntu Unity
本来,启动程序之后,在左边的launcher bar点右键,[Lock to Launcher]就可以的. 但是,有时候因为某种原因,需要手工添加. 这时候,就要参考下面的文章了 http://ask ...
- Isotig & cDNA & gene structure & alternative splicing & gene loci & 表达谱
参考:高通量测序相关名词 Isotig 指在转录组de novo测序时,用454平台测序完成后组装出的结果,一个isotig可视为一个转录本. Isogroup 指转录组de novo测序中,用454 ...
- 【异常】Application failed to start due to an exception org.springframework.beans.factory.BeanCurrentlyInCreationException
一. 异常信息: 2018-05-17 18:03:22.224 -DEBUG [ restartedMain] o.s.b.d.LoggingFailureAnalysisReporter ...
- 请求和响应:类ActionController::Base ; 类ActionDispatch::Request
扩展:ActionController::Base < Metal 2个基本主题: Get and Show do and redirect Requests 每个请求,由router决定了co ...