我是荔园微风,作为一名在IT界整整25年的老兵,今天总结一下微软MFC技术运行机制。
很多初学者误以为VC++开发必须使用MFC,其实不一定的。MFC的使用只能是提高程序在某些情况下的开发效率,而不能替代整个Win32程序设计。我认为我们有必须再来好好讲讲MFC的本质、MFC中的消息是以何种形式存在、懂得MFC中消息的存储方式消息队列、明白MFC程序运行的原理消息响应、MFC运行流程。
我在上一篇关于MFC的文章中说过,MFC是微软公司提供的类库,它以C++的形式封装了Windows的接口函数API。类库中包含大量的Windows句柄类、Windows控件类、Windows组件类。
直接使用Windows的API函数来开发产品,对于程序员来说很困难。因为API函数的数量十分多,而且名称上有时很难看出来是什么意思。如果用win32开发一个窗口至少也得100多行的代码,而一个软件系统做出来后,那代码量更是大的惊人。本质上来说,MFC就是win32开发与Application framework的组合。这个组合为程序员创建了程序的一般框架模型,减少了应用程序开发程序员的工作量。
为了方便大家理解MFC,现在我们做一个比喻。我们把MFC程序比喻为空调。
首先,威利斯·开利发明了世界上第一台空调,是下图这个样子的,于是空调的整个设计思想和原理被固定下来,形成了第一代空调,相当于我们这里的Win32的Application framework。
而最新的空调就是在第一代空调的基础上不断迭代发展而来。现代空调是在第一代空调的基础上不断完善而来,增加入不少新的技术,这种增加的新技术类似于我们这里的各类Windows的接口函数API,然后对第一代空调的设计思想原理结合后来的新技术进行了一次次的融合,而且更加模块化组件化,形成了现代空调产品,也就是我们这里的MFC。如下图这些工业用空调。
MFC的实质就是对Win32程序的封装,第一台空调与后来各种技术的结合 就是现代空调发展的一个模板,Win32的Application framework与函数API的结合 就是MFC框架。
你如果想在现代空调上加入新技术,就必须了解空调的原理。对于程序员来说,也必须了解MFC架构。MFC程序的结构一般是由一个CWinApp类对象和几个从MFC派生的类组成。
我们以一个基于单文档的MFC工程为例进行讲解,工程名为KongTiao。我们一建立KongTiao就会有如下图几个类,其中常用的是CMainFrame、CKongTiaoApp、CKongTiaoDoc、CKongTiaoView这4个类。
1.应用程序类CKongTiaoApp
先在KongTiao.h通过下面代码定议CKongTiaoApp类
class CKongTiaoApp : public CWinApp //派生类:public 基类
{
public:
CKongTiaoApp(); //构造函数,用于初始化
public:
virtual BOOL InitInstance(); //实例化虚函数
afx_msg void OnAppAbout(); //函数声明
DECLARE MESSAGE_MAP()
从第01行可看出它是从CWinApp类派生,它有且只有一个应用程序对象,负责应用程序的初始化、运行和结束。
2.文档类CKongTiaoDoc
先在KongTiaoDoc.h通过下面代码定义CKongTiaoDoc类
class CKongTiaoDoc : public CDocument //派生类:public基类
{
protected: //以下为保护成员函数
CKongTiaoDoc(); //构造函数,用于初始化
DECLARE DYNCREATE(CMessageDoc)
...
public:
virtual ~CKongTiaoDoc(); //析构函数
...
};
从它的第01行可看出它是从CDocument类派生,用来管理数据,实现数据的变化、存取。
3.视图类CMessageView
同时文档类还可以和视图类合作,访问和更新数据。先在KongTiaoView.h通过下面代码定义4-3是CKongTiaoView视图类的定义。
class CKongTiaoview : public CView //派生类:public基类
{
protected: //以下为保护成员函数
CKongTiaoView(); //构造函数,用于初始化
DECLARE DYNCREATE(CKongTiaoview)
...
public:
virtual void OnDraw(CDC* pDC); //画视图
virtual BOOL PreCreateWindow(CREATESTRUCT& cs); //创建窗口
...
public:
virtual ~CKongTiaoView(); //析构函数
...
protected:
DECLARE MESSAGE MAP()
public:
afx msg void OnMouseMove(UINT nFlags, CPoint point); //鼠标移动的消息函数
};
从第01行可看出它是从CView类派生。视图和文档联系在一起,在文档和用户之间起中介作用,即:在屏幕上显示文档的内容,并把用户输入转换成对文档的操作。
4.主框架窗口类CMainFrame
代码MainFrm.h是CMainFrame框类的定义。
class CMainFrame : public CFrameWnd //派生类:public基类
{
protected: //以下为保护成员函数
CMainFrame(); //构造函数,用于初始化
DECLARE DYNCREATE(CMainFrame)
...
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs); //创建窗口
public:
virtual ~CMainFrame(); //析构函数
...
protected:
CStatusBar m_wndStatusBar; //声明一个状态栏对象
CToolBar m_wndToolBar; //声明一个工具栏对象
protected:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); //用于创建窗口各种属性
DECLARE_MESSAGE MAP()
};
从第01行可看出它是从CFrameWnd类派生,负责创建和控制菜单、工具栏、状态栏等界面元素。
5.MFC类的底部派生关系
前面大家已经看到很多类的派生关系,这4个默认生成的类都是从CWinApp、CDocument 等类派生而来,这就需要大家了解MFC类的底部派生关系,如图所示。
第 1行的 CObject 类是大多数 MFC 类的根类或基类。 CObject派生出CCmdTarget。类 CCmdTarget 是MFC类库中消息映射体系的一个基类,是MFC处理命令消息的基础核心。而CCmdTarget类又派生出了如图中所示4种不同的类,即CWinThread、CDocTemplate、 CDocument、CWnd。
作者简介:荔园微风,1981年生,高级工程师,浙大工学硕士,软件工程项目主管,做过程序员、软件设计师、系统架构师,早期的Windows程序员,Visual Studio忠实用户,C/C++使用者,是一位在计算机界学习、拼搏、奋斗了25年的老将,经历了UNIX时代、桌面WIN32时代、Web应用时代、云计算时代、手机安卓时代、大数据时代、ICT时代、AI深度学习时代、智能机器时代,我不知道未来还会有什么时代,只记得这一路走来,充满着艰辛与收获,愿同大家一起走下去,充满希望的走下去。