【笔记】《深入浅出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. ...
随机推荐
- jquery和bootstrap获取checkbox选中的多行数据
在项目中,经常遇到,于是整理 引用bootstrap的js和css 代码解释: $("#dgFlowList").find(":checkbox:checked" ...
- 获取公网IP地址
https://ipip.yy.com/get_ip_info.php http://pv.sohu.com/cityjson?ie=utf-8 http://www.ip168.com/json.d ...
- 通过gevent实现【单线程】下的多socket并发
server import sys import socket import time import gevent from gevent import socket,monkey monkey.pa ...
- c语言 数组合并
#include<stdio.h> int main() { int m,n,i,j,k; printf("Enter no. of elements in array1:\n& ...
- Jmeter 爬Boss中注册和登录
图文验证码生成部分: Get请求到 https://m.zhipin.com/captcha/?randomKey=9dHY2lyVpxg0wFQRmzJqE5bpL4iRkhhR 每次访问新生成一个 ...
- list_01
双向链表 不支持随机存取([?] / at(?)) A.头尾 添加/移除 A.1.list::push_back(elemValue); A.2.list::pop_back(); A.3.list: ...
- 《F4+2—团队项目设计完善&编码测试》
1:根据OOD详细设计工作要点,修改完善团队项目系统设计说明书和详细设计说明 a.软件系统设计说明书的完善 将测试启动准则,测试结束准则,测试暂停/中止标准加到了测试计划中.将把在测试中会 ...
- ubuntu 安装 openssh-server,xinetd,vmware tools
●安装SSH服务 ●判断是否安装ssh服务,通过如下命令:ps -e|grep ssh 1, sudo apt-get update --->软件的更新地址变了,需要更新本机的sources.l ...
- 51nod 1682 中位数计数(前缀和)
51nod 1682 中位数计数 思路: sum[i]表示到i为止的前缀和(比a[i]小的记为-1,相等的记为0,比a[i]大的记为1,然后求这些-1,0,1的前缀和): hash[sum[i]+N] ...
- Unity如何判断一个对象是不是一件衣服
判断该对象及其子对象上是否有SkinnedMeshRenderer组价即可 public static bool IsCloth(Transform obj) { bool isCloth = fal ...