
如何看MFC 程序代码 看下面内容之前,建议你学学《深入浅出MFC》,这本书强烈推荐! 现在只是做个了解。不妨做个知识备份! 在MFC 程序中,我们并不经常直接调用Windows API,而是从MFC 类创建对象并调用属于这些对象的成员函数也就是说MFC 封装了Windows API 你说你喜欢C++而MFC 换一种说法就是一个用C++写的一个函数库然后你来调用只不过这个类不是你写的MFC 提供数百个类,最重要的、也是编写任何VC++应用程序都必不可少的两个类CWinApp 和CFrameWnd,这两个类是编写复杂庞大应用程序的基石。1 封装特性:构成MFC 框架的是MFC 类库而MFC 类库又是C++的一个类库。这些类封装WIN32 应用程序编程接口,OLE(Object Link Embed 对象链接嵌入) 特性,ODBC 和DAO 数据访问的功能。2 继承特性:MFC 抽象出了众多类的共同特性,并设计出一些基类作为实现其他类的基础,这些类中最重要的类是 CObject 类和CCmdTarget 类,程序员可以从适当的MFC 类中派生出自己的类,实现特定的功能达到编程的目的。3 虚拟和消息映射:MFC 是以C++为基础,当然支持虚函数,但作为一个编程框架必须要解决的是效率问题:如果MFC 仅仅通过虚函数来支持动态约束必然会产生大量的虚函数表这样编程框架过于臃肿而且消耗更多的内存。但是MFC 建立了消息映射机制这样降低了内存的使用却大大提高了效率消息映射是一个将消息和成员函数相互关联的表,当应用程序的框架窗口接收到一个消息时,MFC 将搜索该窗口的消息映射,如果存在一个处理消息的处理程序,那么就调用该处理程序它通过宏来实现消息到成员函数的映射,而且这些函数不必是虚拟的成员函数,这样不需要为消息映射函数生成一个很大的虚拟函数表(V 表),节省内存。MFC 消息映射机制:将消息与消息处理函数联系起来,形成一一对应的机制。消息映射宏声明:DECLARE_MESSAGE_MAP 定义:BEGIN_MESSAGE_MAP ON_COMMAND ON_CONTROL ON_MESSAGE END_MESSAGE_MAP MFC 主要组成部分:类、宏和全局函数。类是MFC 中最主要的内容。MFC 类是以层次结构方式组织起来的。MFC 中的类分成两部分,除了一些辅助类,大多数的MFC 类是直接或间接从根类CObject 派生而来。MFC 宏主要功能:消息映射、运行时对象类型服务、诊断服务、异常处理。MFC 约定:全局函数以"Afx"为前缀,全局变量以"afx"为前缀MFC 类的层次关系CObject 项目类)-CCmdTarget(消息响应类)-{CWinThread(线程类)-CWinApp(Window 应用程序类)CDocument(文档类)CWnd(窗体类)-[CFrameWnd(框架类)CView(视图类)]}CObject 类由于MFC 中大部分类是从CObject 类继承而来的,CObject 类描述了几乎所有的MFC 类的一些公共特性,CObject 类为程序员提供了对象诊断、运行时类型识别和序列化等功能。CCmdTarget 类由CObject 类直接派生而来,它负责将消息发送到能够响应这些消息的对象。它是所有能进行消息映射的MFC 类的基类。CWinApp 类在任何MFC 应用程序中有且仅有一个CWinApp 派生类的对象,它代表了程序中运行的主线程,也代表了应用程序本身。CWinApp 类取代了WinMain()主函数在SDK 应用程序中的地位。传统SDK 应用程序 WinMain()函数完成的工作。现在由类CWinApp 的InitApplication(), InitInstance()和Run()三个成员函数承担。CWnd 类由CCmdTarget 类直接派生而来,该类及其派生类的实例是一个窗口。CWnd 类代表了MFC 中最基本的GUI 对象,它是一个功能最完善、成员函数最多的MFC 类。CFrameWnd 类是CWnd 类的派生类,主要用来掌管一个窗口,它取代了SDK 应用程序中窗口函数 WndProc()的地位。CFrameWnd 类的对象是一个框架窗口,包括边框、标题栏、菜单、最大化按钮、最小化按钮和一个激活的视图。CDocument 类在应用程序中作为用户文档类的基类,它代表了用户存储或打开的一个文件。CView 类是 MFC 中一个很基本的类,它作为其它MFC 视图类和用户视图派生类的基类。从 API 编程到MFC 编程的过渡:WinMain(){初始化WNDCLASS 注册窗体结构创建窗口-应用程序类CWinApp 显示窗口消息循环}WndProc(){switch(…){case:…}- 框架窗口类CFrameWnd}MFC Object 和Windows Object 的对应关系:描述 Windows 句柄MFC Object 窗口HWND CWnd 设备上下文HDC CDC 菜单HMENU CMenu 笔HPEN CPen 刷子HBRUSH CBrush 字体HFONT CFont 位图HBITMAP CBitmap 套接字SOCKET CSocket 三、手工创建一个MFC 应用程序:注意:创建 MFC 程序,要创建一个Win32 空项目,并要选择项目属性中的"在共享DLL 文件中使用MFC,然后新建我们的文件例子:在"helloh"头文件中添写如下代码: class CMyApp:public CWinApp{public:virtual BOOL InitInstance();// 虚函数};class CMainWindow:public CFrameWnd{public:CMainWindow(); protected:afx_msg void OnPaint();DECLARE_MESSAGE_MAP();//声明消息映射};在"hellocpp"源文件中添写如下代码:#include afxwinh#include"helloh"CMyApp myApp;BOOL CMyApp: InitInstance(){m_pMainWnd=new CMainWindow;m_pMainWnd- ShowWindow(m_nCmdShow);m_pMainWnd-UpdateWindow();return TRUE;}BEGIN_MESSAGE_MAP(CMainWindow,CFrameWnd)ON_WM_PAINT()END_MESSA GE_MAP()//消息映射CMainWindow:CMainWindow()//构造函数初始化 {Create(NULL,"我的第一个MFC 应用程序");//创建窗体}void CMainWindow: OnPaint(){CPaintDC dc(this);CRect rect;GetClientRect(&rect); dcDrawText("Hello MFC",- 1,&rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);}CWinApp 是应用程序类,在MFC 应用程序中必须从这个类派生出一个类,该派生类是MFC 应用程序的入口必须定义这个派生类的对象,并且只能有一个这个对象代表整个应用程序。成员函数:InitInstance()功能:初始化应用程序实例和窗口实例,虚函数 CWinApp:InitInstance 必须在派生类中重写。在InitInstance 函数中,编写初始化代码,如:创建一个窗口显示一个窗口CFrameWnd 类作用:为应用程序提供一个窗口,同时实现消息处理功能。成员函数:Create()功能:创建窗体, 将之赋于CFrameWnd 对象上。BOOL Create(窗口类型,窗口标题,显示风格,显示区域,符窗口句柄,菜单,扩展显示风格,上下文对象)共有8 个参数,前两个必须给出,后6 个可以默认。MFC 应用程序的核心就是基于CWinApp 类的应用程序对象,CWinApp 提供了消息循环来检索消息并将消息调度给应用程序的窗口我们在编写MFC 应用程序时,要包含afxwinh,一个MFC 应用程序可以有且仅有一个应用程序对象,对象必须声明为在全局范围内有效(也就是全局对象), 以便它在程序开始时即在内存中被实例化我们的Hello MFC 的应用程序类被命名为CMyApp,它在hellocpp 中用如下语句进行了实例化:CMyApp myApp; CMyApp 的类声明在helloh 中代码如下:class CMyApp:public CWinApp{public:virtual BOOL InitInstance();};CMyApp 没有声明任何的数据成员,只是重写了一个从CWinApp 类中继承来的函数,在应用程序的生存期内InitInstance 的调用比较早,是在应用程序开始运行以后而窗口创建之前,除非InitIstance 创建一个窗口,否则应用程序是不会有窗口,这正是为什么即使最小的MFC 应用程序也必须从CWinApp 派生出一个类并重写CWinApp: InitIstance 的原因InitInstance 函数:CWinApp:InitInstance 是一个虚函数,其默认 *** 作仅包含一条语句:return TRUE;InitInstance 是用来执行程序每次开始时都需要进行的初始化工作最好的地方在hellocpp 中,CMyApp 的 InitInstance 通过实例化hello 的CMainWindow 类来创建hello 窗口,语句: m_pMainWnd=new CMainWindow;构造了一个CMainWindow 对象指针,并将其地址复制到了应用程序对象的m_pMainWnd 数据成员中,窗口创建以后,InitInstance 就会通过CMainWindow 指针调用ShowWindow 和UpdateWindow 函数显示它: m_pMainWnd-ShowWindow(m_nCmdShow);m_pMainWnd-UpdateWindow(); ShowWindow 和UpdateWindow 是所有窗口对象共用的CWnd 成员函数其中包括 CFrameWnd 类的对象,CMainWindow 就是从CFrameWnd 派生出来的要从MFC 程序调用一个常规的Windows API 函数,需要在函数名称前添加一个全局运算符:例如::UpdateWindow();通过生成窗口对象并调用其Create 函数,MFC 应用程序可以创建一个窗口,在CMyApp:InitInstance 中,hello 创建了一个 CMainWindow 对象,CMainWindow 的构造函数生成在屏幕上看到的窗口: Create(NULL,"我的第一个MFC 应用程序");CPaintDC dc(this);MFC 的 CPaintDC 类是从MFC 的CDC 类派生的,CDC 类封装了Windows 设备环境,以及包含了绘制到屏幕、打印机和其他设备的几十个成员函数在MFC 中如何处理消息呢在SDK 中我们利用的是消息循环和窗口过程函数对消息进行消息处理在 MFC 中我们用的是消息映射机制下面是将消息映射添加到一个类中需要做的全部工作1 通过将DECLARE_MESSAGE_MAP 语句添加到类声明中,声明消息映射2 通过放置标识消息的宏来执行消息映射,相应的类将在对BEGIN_MESSAGE_MAP 和 END_MESSAGE_MAP 的调用之间处理消息3 添加成员函数来处理消息1、构造 CWinApp 派生类的对象2、系统调用WinMain()3、WinMain 调用InitInstance, 在该函数中创建CFrameWnd 派生类对象,调用Create 函数创建窗口、调用 ShowWindow 函数显示窗口。4、之后内部机制调用Run,接受用户的消息,并将消息导向默认的处理函数。当接收到WM_QUIT 消息时,Run 内部调用 ExitInstance,退出程序。MFC 采用消息映射(Message Map)机制取代C/C++语言中的switch-case 结构来处理消息。消息映射:在MFC 中把消息处理函数和它所要处理的特定的消息连接起来的一种机制。它通过宏来实现消息到成员函数的映射,而且这些函数不必是虚拟的成员函数,这样不需要为消息映射函数生成一个很大的虚拟函数表(V 表),节省内存。MFC 消息映射机制包括一组消息映射宏。一条消息映射宏把一个Windows 消息和其消息处理函数联结起来。MFC 应用程序框架提供了消息映射功能。在类的实现源文件中用 BEGIN_MESSAGE_MAP()和END_MESSAGE_MAP()宏来定义消息映射。在类定义的结尾用DECLARE_MESSAGE_MAP()宏来声明使用消息映射。
如果你保存的是数值型变量,那么这个所谓“乱码”很可能是正确的内容,因为:数值型直接保存后,显示的不是可视化文本,就是一堆“乱码”。
只有字符串在序列化保存后,是可显示的文本。
数值型保存,以int为例:
int i = 5000;
那么保存后是十六进制如下:88 13 00 00 数值会以16进制形式保存并且高低位置换。这样的存储,显然不会变成可显示字符,如果希望直观显示文本,需要将数值转换成字符串后再保存。
MFC(Microsoft Foundation Classes),是微软公司提供的一个类库(class libraries),以C++类的形式封装了Windows的API,并且包含一个应用程序框架,以减少应用程序开发人员的工作量。其中包含的类包含大量Windows句柄封装类和很多Windows的内建控件和组件的封装类。
中文名微软基础类库外文名Microsoft Foundation Classes开发公司微软公司编译平台C++ SDK
编程语言C++
适用平台
Windows
1简单
MFC:微软基础类(Microsoft Foundation Classes),同VCL类似,是一种应用程序框架,随微软Visual C++开发工具发布。目前最新版本为100(截止2011年3月),并且发布了中文版。该类库提供一组通用的可重用的类库供开发人员使用,大部分类均从CObject 直接或间接派生,只有少部分类例外。[1]
MFC应用程序的总体结构通常由开发人员从MFC类派生的几个类和一个CWinApp类对象(应用程序对象)组成。MFC 提供了MFC AppWizard 自动生成框架
Windows 应用程序中,MFC 的主包含文件为Afxwinh
此外MFC的部分类为MFC/ATL 通用,可以在Win32 应用程序中单独包含并使用这些类。
由于它的易用性,初学者常误认为VC++开发必须使用MFC,这种想法是错误的。作为Application Framework,MFC的使用只能提高某些情况下的开发效率,只起到辅助作用,而不能替代整个Win32 程序设计。
2特点编辑
[1] MFC实际上是微软提供的,用于在C++环境下编写应用程序的一个框架和引擎。VC++是Windows下开发人员使用的专业C++ SDK(SDK,Standard SoftWare Develop Kit,专业软件开发平台),MFC就是挂在它之上的一个辅助软件开发包。MFC作为与VC++血肉相连的部分(注意C++和VC++的区别:C++是一种程序设计语言,是一种大家都承认的软件编制的通用规范;而VC++只是一个编译器,或者说是一种编译器+源程序编辑器的IDE(IDE的英文全称为“Integrated Development Environment”,即“集成开发环境”),WSPlatForm,这跟Pascal和Delphi的关系一个道理。Pascal是Delphi的语言基础,Delphi使用Pascal规范来进行Win下应用程序的开发和编译,却不同于Basic语言和VB的关系。Basic语言在VB开发出来被应用的年代已经成了Basic语言的新规范,VB新加的Basic语言要素,如面向对象程序设计的要素,是一种性质上的飞跃,使VB既是一个IDE,又成长成一个新的程序设计语言)。MFC同VC++集成的VCL一样是一个非外挂式的软件包类库,只不过MFC类是微软为VC++专配的。
MFC是WinAPI与C++的结合。API,即微软提供的Windows下应用程序的编程语言接口,是一种软件编程的规范,但不是一种程序开发语言本身,可以允许用户使用各种各样的第三方(如我是一方,微软是一方,Borland就是第三方)的编程语言来进行对Windows下应用程序的开发,使这些被开发出来的应用程序能在Windows下运行,比如VB、VC++、Java、Delhpi。编程语言函数本质上全部源于API,因此用它们开发出来的应用程序都能工作在Windows的消息机制和绘图里,遵守Windows作为一个 *** 作系统的内部实现,这其实也是一种必要。微软如果不提供API,这个世上对Windows编程的工作就不会存在,微软的产品就会迅速从时尚变成垃圾。上面说到MFC是微软对API函数的专用C++封装,这种结合一方面让用户使用微软的专业C++ SDK来进行Windows下应用程序的开发变得容易,因为MFC是对API的封装,微软做了大量的工作,隐藏了好多程序开发人员在Windows下用C++ & MFC编制软件时的大量内节,如应用程序实现消息的处理、设备环境绘图,这种结合是以方便为目的的,必定要付出一定代价(这是微软的一向作风),因此就造成了MFC对类封装中的一定程度的的冗余和迂回,但这是可以接受的。
最后要明白MFC不只是一个功能单纯的界面开发系统,它提供的类绝大部分用来进行界面开发,关联一个窗口的动作,但它提供的类中有好多类不与一个窗口关联,即类的作用不是一个界面类,不实现对一个窗口对象的控制(如创建、销毁),而是一些在Windows(用MFC编写的程序绝大部分都在Windows中运行)中实现内部处理的类,如数据库的管理类等。学习中最应花费时间的是消息和设备环境,对C++和MFC。
MFC是微软封装了的API。什么意思呢?Windows作为一个提供功能强大的应用程序接口编程的 *** 作系统,的确方便了许多程序员,传统的win32开发(直接使用Windows的接口函数API)对于程序员来说非常的困难,因为,API函数实在太多了,而且名称很乱,从零构架一个窗口动辄就是上百行的代码。MFC是面向对象程序设计与Application framework的完美结合,它将传统的API进行了分类封装,并且为你创建了程序的一般框架。
MFC是对WindowsAPI的封装,大大简化了我们的工作;学VC主要就是要学MFC,大约有100多个类,但常用的也就二三十个。应该象背4级单词一样将这些常用类搞懂;当然不要死记,要通过看帮助、看例子、动手练习来学会它们;而且,并非每个类的内部的所有函数都要学会,要日积月累。如果真的想成为高手,做个笔记本把自己认为重要的类、函数记下来,随时学习,也是很好的突击方法。
3关键技术编辑
MFC程序的初始化过程
建立一个MFC窗口很容易,只用两步:一是从CWinApp派生一个应用程序类(这里是MyApp),,然后建立应用程序对象(theApp),就可以产生一个自己需要的窗口(即需要什么样就在InitInstance()里创建就行了)[2] 。
运行时类型识别(RTTI)
运行时类型识别(RTTI)即是程序执行过程中知道某个对象属于某个类,我们平时用C++编程接触的RTTI一般是编译器的RTTI,即是在新版本的VC++编译器里面选用“使能RTTI”,然后载入typeinfoh文件,就可以使用一个叫typeid()的运算子,它的地位与在C++编程中的sizeof()运算子类似的地方(包含一个头文件,然后就有一个熟悉好用的函数)。typeid()关键的地方是可以接受两个类型的参数:一个是类名称,一个是对象指针。
动态创建
动态创建就是运行时创建指定类的对象,在MFC中大量使用。如框架窗口对象、视对象,还有文档对象都需要由文档模板类对象来动态的创建。我觉得这是每个MFC的学习者很希望理解的问题。
初次接触MFC的时候,很容易有这样的迷惘。MFC的几大类不用我们设计也就罢了,但最疑惑的是不用我们实例化对象。本来最直观的理解就是,我们需要框架的时候,亲手写上CFrameWnd myFrame;需要视的时候,亲自打上CView myView;……但MFC不给我们这个机会,致使我们错觉窗口没有实例化就d出来了!就象画了张电视机的电路图就可以看电视一样令人难以置信。但大伙想了一下,可能会一拍脑门,认为简单不过:MFC自动帮我们完成CView myView之流的代码不就行了么!!!其实不然,写MFC程序的时候,我们几乎要对每个大类进行派生改写。换句话说,MFC并不知道我们打算怎样去改写这些类,当然也不打算全部为我们“静态”创建这些类了。即使静态了创建这些类也没有用,因为我们从来也不会直接利用这些类的实例干什么事情。我们只知道,想做什么事情就往各大类里塞,不管什么变量、方法照塞,塞完之后,我们似乎并未实例化对象,程序就可以运行
永久保存
MFC的连续存储(serialize)机制俗称串行化。“在你的程序中尽管有着各种各样的数据,serialize机制会象流水一样按顺序存储到单一的文件中,而又能按顺序地取出,变成各种不同的对象数据。”不知我在说上面这一句话的时候,大家有什么反应,可能很多朋友直觉是一件很简单的事情,只是说了一个“爽”字就没有下文了。
消息映射
消息映射与命令传递体现了MFC与SDK的不同。在SDK编程中,没有消息映射的概念,它有明确的回调函数中,通过一个switch语句去判断收到了何种消息,然后对这个消息进行处理。所以,在SDK编程中,会发送消息和在回调函数中处理消息就差不多可以写SDK程序了。
在MFC中,看上去发送消息和处理消息比SDK更简单、直接,但可惜不直观。举个简单的例子,如果我们想自定义一个消息,SDK是非常简单直观的,用一条语句:SendMessage(hwnd,message/一个大于或等于WM_USER的数字/,wparam,lparam),之后就可以在回调函数中处理了。但MFC就不同了,因为你通常不直接去改写窗口的回调函数,所以只能亦步亦趋对照原来的MFC代码,把消息放到恰当的地方。这确实是一样很痛苦的劳动。
消息传递
有了消息映射表之后,我们得讨论到问题的关键,那就是消息发生以后,其对应的响应函数如何被调用。大家知道,所有的MFC窗口,都有一个同样的窗口过程——AfxWndProc(…)。在这里顺便要提一下的是,看过MFC源代码的朋友都知道,从AfxWndProc函数进去,会遇到一大堆曲折与迷团,因为对于这个庞大的消息映射机制,MFC要做的事情很多,如优化消息,增强兼容性等,这一大量的工作,有些甚至用汇编语言来完成,对此,我们很难深究它。所以我们要省略大量代码,理性地分析它。[2]
4重要MFC编辑
CWnd:窗口,它是大多数“看得见的东西”的父类(Windows里几乎所有看得见的东西都是一个窗口,大窗口里有许多小窗口),比如视图CView、框架窗口CFrameWnd、工具条CToolBar(现为CMFCToolBar)、对话框CDialog、按钮CButton等等;一个例外是菜单(CMenu)不是从窗口派生的。该类很大,一开始也不必学,知道就行了。
CDocument文档,负责内存数据与磁盘的交互。最重要的是OnOpenDocument(读入),OnSaveDocument(写盘),Serialize(序列化读写)。
CView视图,负责内存数据与用户的交互。包括数据的显示、用户 *** 作的响应(如菜单的选取、鼠标的响应等等)。最重要的是OnDraw(重画窗口),通常用CWnd::Invalidate()来启动它。另外,它通过消息映射表处理菜单、工具条、快捷键和其他用户消息。你自己的许多功能都要加在里面,你打交道最多的就是它。
CDC设备文本。无论是显示器还是打印机,都是画图给用户看。这图就抽象为CDC。CDC与其他GDI(图形设备接口)一起,完成文字和图形、图像的显示工作。把CDC想象成一张纸,每个窗口都有一个CDC相联系,负责画窗口。CDC有个常用子类CClientDC(窗口客户区),画图通常通过CClientDC完成。
CDialog对话框
MFC相关编辑
有趣的是,MFC使用“Afx”作为所有的全局函数的前缀,“afx”作为全局变量的前缀。因为在MFC的早期开发阶段它叫“Application Framework Extensions”缩写为“AFX”。AFX提供了对Windows API的高度抽象,建立了全新的面向对象的AFX API,但它对于新手来说太复杂了,所以AFX小组不得不重新开始。后来他们创建了一组C++类,这就是MFC。MFC这个名字被采用得太晚了以至于没来得及修改这些引用。
MFC80和Visual Studio 2005一起发布了;MFC90和Visual Studio 2008一起发布。在免费的Express版本的Visual Studio 2005/2008中没有包含MFC。
MFC作为一个强有力的竞争对手,为Borland的Turbo C++编译器设计OWL(Object Windows Library)在同一时间也发布了。但最后,Borland停止了对OWL的继续开发并且不久就从Microsoft那里购买了MFC头文件,动态链接库等的授权,微软没有提供完整的MFC的集成支持。之后Borland发布了VCL(Visual Component Library)来替换OWL框架。
随着编程语言的推陈出新,MFC一些缺点日益突出。最重要的就是入门门槛相对其他语言要高,而且同样完成一个任务代码量相对较多。而原有的优势如运行速度快等,也因为其他编程语言的日臻完善和个人电脑的运算速度增加而显得不那么突出。MFC似乎江河日下。
但是MFC真的没有任何优势了吗?不是,面对底层程序,它能很轻松的与Windows API或驱动程序结合,就是在自己的代码中直接使用API函数,而API和驱动程序的资料都是以C语言为基础的,这使得VC程序员能够更轻松的使用Windows API。这样造成了一个很有意思的现象,即入门时VC程序员要付出更多的努力来学习,但是一旦掌握后,开发其他领域的程序或使用第三方软件时,如工业控制类的程序,由于底层的程序都是用C语言编写,反倒是VC程序员能够更快的掌握该领域的编程技术。而很多其他的编程语言甚至找不到相关的资料。这就说明VC(MFC)实际上是一种入门困难,但是扩展学习却很轻松的语言框架。如果局限于某一领域的话VC毫无优势可言,但是如果开发一个新的领域的应用程序或者该程序涉及多个应用领域的话,可减少重复学习的频率和难度,VC(MFC)的优势会立刻显现出来。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)