MFC 串行化数据和 C++ 对象

合集下载

C#串行化——精选推荐

C#串行化——精选推荐

C#串⾏化1. 什么叫串⾏化?串⾏化(Serialize)是指将对象存储到介质(如⽂件、内存缓冲区等)中或是以⼆进制⽅式通过⽹络传输。

反串⾏化(Deserialize)指将这些连续的数据重新构建⼀个与原始对象状态相同的对象2. 串⾏化分类两种形式⼆进制串⾏化串⾏化时数据以⼆进制形式存⼊⽂件。

但是该⽅式不适合同其他⾮.NET程序交换数据。

XML串⾏化对象的公共属性以XML元素和特性表⽰。

该⽅式可以和其他⾮.NET程序交换数据。

该⽅法要引⽤命名空间using System.Xml.Serialization;另外,XML串⾏化器是不能针对枚举类型串⾏化操作的,如果有必要的话,可以将枚举型变量设置为私有变量,并且设置相应的简单类型变量进⾏操作。

3. 实例⾸先创建我们要串⾏化的类:public class Book{public string _title;public int _page;public string[] _Part;public string _author;public float _price;}串⾏化对象void SerializeObject(Book[] book){try{XmlSerializer ser = new XmlSerializer(typeof(Book[]), new XmlRootAttribute("Books"));//声明对象,并且添加根节点StreamWriter sw = new StreamWriter("book.prt");ser.Serialize(sw, book);sw.Close();}catch (Exception e){MessageBox.Show("串⾏化失败:" + e.Message.ToString());}}调⽤:调⽤串⾏化private void Serialize_Click(object sender, EventArgs e){Book book = new Book();book._title = "西游记";book ._author="吴承恩";book._page = 420;book._Part = new string[]{"第⼀章?", "第⼆章?", "第三章?", "..."};book._price = 55;。

C++中多线程的四种控制方法

C++中多线程的四种控制方法

C++中多线程的四种控制⽅法四种进程或线程同步互斥的控制⽅法1、临界区:通过对多线程的串⾏化来访问公共资源或⼀段代码,速度快,适合控制数据访问。

2、互斥量:为协调共同对⼀个共享资源的单独访问⽽设计的。

3、信号量:为控制⼀个具有有限数量⽤户资源⽽设计。

4、事件:⽤来通知线程有⼀些事件已发⽣,从⽽启动后继任务的开始。

临界区(Critical Section) 保证在某⼀时刻只有⼀个线程能访问数据的简便办法。

在任意时刻只允许⼀个线程对共享资源进⾏访问。

如果有多个线程试图同时访问临界区,那么在有⼀个线程进⼊后其他所有试图访问此临界区的线程将被挂起,并⼀直持续到进⼊临界区的线程离开。

临界区在被释放后,其他线程可以继续抢占,并以此达到⽤原⼦⽅式操作共享资源的⽬的。

临界区包含两个操作原语: EnterCriticalSection()进⼊临界区 LeaveCriticalSection()离开临界区 EnterCriticalSection()语句执⾏后代码将进⼊临界区以后⽆论发⽣什么,必须确保与之匹配的 LeaveCriticalSection()都能够被执⾏到。

否则临界区保护的共享资源将永远不会被释放。

虽然临界区同步速度很快,但却只能⽤来同步本进程内的线程,⽽不可⽤来同步多个进程中的线程。

MFC提供了很多功能完备的类,我⽤MFC实现了临界区。

MFC为临界区提供有⼀个 CCriticalSection类,使⽤该类进⾏线程同步处理是⾮常简单的。

只需在线程函数中⽤CCriticalSection类成员函数 Lock()和UnLock()标定出被保护代码⽚段即可。

Lock()后代码⽤到的资源⾃动被视为临界区内的资源被保护。

UnLock后别的线程才能访问这些资源。

互斥量(Mutex) 互斥量跟临界区很相似,只有拥有互斥对象的线程才具有访问资源的权限,由于互斥对象只有⼀个,因此就决定了任何情况下此共享资源都不会同时被多个线程所访问。

MFC教程(3)-- CObject类

MFC教程(3)-- CObject类

MFC教程(3)-- CObject类CObject是大多数MFC类的根类或基类。

CObject类有很多有用的特性:对运行时类信息的支持,对动态创建的支持,对串行化的支持,对象诊断输出,等等。

MFC从CObject 派生出许多类,具备其中的一个或者多个特性。

程序员也可以从CObject类派生出自己的类,利用CObject类的这些特性。

本章将讨论MFC如何设计CObject类的这些特性。

首先,考察CObject类的定义,分析其结构和方法(成员变量和成员函数)对CObject特性的支持。

然后,讨论CObject 特性及其实现机制。

CObject的结构以下是CObject类的定义:class CObject{public://与动态创建相关的函数virtual CRuntimeClass* GetRuntimeClass() const;析构函数virtual ~CObject(); // virtual destructors are necessary//与构造函数相关的内存分配函数,可以用于DEBUG下输出诊断信息void* PASCAL operator new(size_t nSize);void* PASCAL operator new(size_t, void* p);void PASCAL operator delete(void* p);#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)void* PASCAL operator new(size_t nSize, LPCSTR lpszFileName, int nLine);#endif//缺省情况下,复制构造函数和赋值构造函数是不可用的//如果程序员通过传值或者赋值来传递对象,将得到一个编译错误protected://缺省构造函数CObject();private://复制构造函数,私有CObject(const CObject& objectSrc); // no implementation//赋值构造函数,私有void operator=(const CObject& objectSrc); // no implementation// Attributespublic://与运行时类信息、串行化相关的函数BOOL IsSerializable() const;BOOL IsKindOf(const CRuntimeClass* pClass) const; // Overridablesvirtual void Serialize(CArchive& ar);// 诊断函数virtual void AssertValid() const;virtual void Dump(CDumpContext& dc) const;// Implementationpublic://与动态创建对象相关的函数static const AFX_DATA CRuntimeClass classCObject; #ifdef _AFXDLLstatic CRuntimeClass* PASCAL _GetBaseClass();#endif};。

mfc 知识点总结

mfc 知识点总结

mfc 知识点总结MFC库的基本组成包括以下几个部分:1. CObject类:是所有MFC类的基类,提供了对象的基本功能,包括内存管理、类型信息、对象的打印和序列化等。

2. CWnd类:是窗口类的基类,封装了Windows窗口的创建、显示、消息处理等功能。

3. CFrameWnd类:是框架窗口类,派生自CWnd类,封装了应用程序的主窗口,提供了菜单、工具栏、状态栏等UI组件。

4. CDocument类和CView类:分别是文档类和视图类,用于管理应用程序中的文档和视图。

文档类负责文档的打开、保存、关闭等操作,视图类负责文档内容的显示和交互。

5. CWinApp类:是应用程序类的基类,封装了应用程序的初始化、消息循环、资源管理等功能。

MFC库提供了丰富的类和函数,用于处理Windows应用程序的各个方面,下面将对MFC的一些重要知识点进行总结。

1. 消息处理在MFC应用程序中,窗口的消息处理是至关重要的。

MFC提供了消息映射机制来进行消息处理。

通过DECLARE_MESSAGE_MAP宏和BEGIN_MESSAGE_MAP/END_MESSAGE_MAP 宏,在类中声明消息处理函数并将消息与处理函数进行映射。

例如:```cpp// 声明消息处理函数afx_msg void OnMouseMove(UINT nFlags, CPoint point);// 映射消息到处理函数BEGIN_MESSAGE_MAP(CMyWnd, CWnd)ON_WM_MOUSEMOVE()END_MESSAGE_MAP()```2. 对话框对话框是Windows应用程序中常用的界面元素,用于与用户进行交互。

MFC提供了CDialog类和CDialogEx类来封装对话框。

开发者可以使用资源编辑器创建对话框模板,然后通过类向导生成对话框类。

对话框类中可以处理控件的事件,并通过DoModal函数或Create函数来显示对话框。

MFC原理结构说明

MFC原理结构说明

MFC原理结构说明MFC(Microsoft Foundation Classes)是一种在Windows平台上开发图形用户界面(GUI)的框架。

MFC提供了一组类、函数和宏,用于简化Windows应用程序开发过程。

本文将对MFC的原理和结构进行详细说明。

一、MFC的原理1. 类与对象:MFC使用面向对象的编程模型,所有的窗口、控件、消息处理程序等都是通过类来定义和创建的。

每个MFC应用程序都包含一个CWinApp类的对象,这个对象是整个应用程序的入口点。

2. 消息映射机制:在MFC中,消息是Windows事件的一种表示。

MFC使用消息映射机制来处理这些消息。

消息映射机制是程序员在类中定义的一种技术,它将特定消息与对应的消息处理函数关联起来。

当收到消息时,MFC会自动调用相应的消息处理函数进行处理。

3. 消息与事件:在MFC中,消息是Windows事件的抽象表示,而事件是用户界面中的交互行为。

MFC提供了一系列预定义的消息类型,如鼠标点击、按键、窗口关闭等,程序员只需要在类中覆盖对应的消息处理函数,就可以处理这些消息。

4. 窗口类和控件类:在MFC中,窗口类和控件类是界面元素的基础。

MFC提供了一组窗口类(如CWnd、CFrameWnd)和控件类(如CButton、CEdit),程序员可以通过继承这些类来创建自定义的窗口和控件。

5. 文档视图模型:MFC中引入了文档视图模型(Document-View Model)的概念,用于实现应用程序的数据和界面的分离。

文档类(CDocument)管理应用程序的数据,视图类(CView)用于显示数据,而框架窗口类(CFrameWnd)则用于协调文档和视图之间的交互。

二、MFC的结构1. 应用程序类(CWinApp):应用程序类是MFC应用程序的入口点,它派生自CWinApp类。

应用程序类负责初始化应用程序的环境,包括注册窗口类、创建主窗口、加载并运行消息循环等。

控件变量关联与CString类让MFC变成C语言

控件变量关联与CString类让MFC变成C语言

控件变量关联与CString类让MFC变成C语言控件变量关联与CString类让MFC变成C语言熟悉C语言的人都知道,用C语言编的程序是在DOS界面下运行的,在代码中我们可以用scanf 函数从屏幕获取数据再格式化传给变量,用printf函数将变量中的数据格式化(按照取定的格式)输出到屏幕,用起来很简单很方便。

但在DOS下运行的程序的最大缺点是:没有一个良好的人机交互界面,DOS界面全是一片漆黑,它无法给我们提供一个模板让我们像做填空题一样形象地提示我们在什么地方应该填入什么,它代表什么,没有一个完整的数学式子使我们清楚地知道我们在干什么。

而MFC可以开发基于框架的应用程序,它有良好的人机交互界面,可以产生对话框提供一个模板,让我们像做填空题一样清晰地知道在什么地方应该填入什么,它代表什么,并且最终呈现出的是一个完整的数学式子,与我们在纸上答题几乎完全一样。

所以C语言DOS最终被Windows取代,对应的C语言被C++取代。

假设现在我们已经有了一个对话框,上面有我们需要的控件,我们希望在对话框中输入数据,点击按钮运算结果输出到对话框上。

在C语言中,我们利用scanf和printf实现了将屏幕中输入的数据传给程序内部变量和将程序内变量的值输出到屏幕。

那么在MFC中我们如何将输入到对话框控件当中的数据传给内部变量呢?又如何将内部变量的值传给控件输出呢?虽然控件是一种资源,有标识该资源的句柄,为了对该资源进行操作可以用一个与该资源相关的类实例化一个对象与该资源取得关联,以后就可通过这个对象调用类中成员函数实现对资源的操作。

当然也可以通过获取指向该资源所关联对象(这个对象不一定存在,不一定是实际的对象)的指针来对资源操作。

但是这些都无法实现数据交换,怎么办呢?不必发愁,微软的工程师们给我们提供了一种最好的解决方案。

我们可以将一个控件与算法中所用到的变量相关联,然后调用数据交换函数实现变量与控件的数据交换。

MFC类库的基本类

MFC类库的基本类

MFC类库是一个层次结构,主要有CObject类、应用程序类、可视对象类、绘图和打印类、通用类、数据库类、Internet和网络类、OLE类。

(1)CObject类CObject类是MFC的抽象基类,MFC中的大多数类是从CObject类派生出来的。

它是MFC 中多数类和用户自定义的根类,该类为程序员提供了希望融入所编写程序的许多公共操作,包括对象的建立和删除、串行化支持、对象诊断输出、运行时信息以及集合类的兼容等。

CObject类的声明在Afx.h中。

(2)应用程序结构类该类主要用于构造框架应用程序的结构,提供了多数应用程序公用的功能.编写程序的任务是填充框架,添加应用程序专有的功能。

1.应用程序和线程支持类CWinThread类是所有线程的基类,窗口应用程序类CWinApp类就是从该类中派生来的。

每个应用程序有且只有一个应用程序对象,在运行程序中该对象和其他对象相互协调,该对象从CWinApp中派生出来。

该类封装了初始化、运行、终止应用程序的代码。

2.命令相关类CCmdTarget类是CObject的子类,它是MFC所有具有消息映射属性的基类。

消息映射规定了当一对象接收到消息命令时,应调用哪个函数对该消息进行处理。

程序员很少需要从CCmdTarget类中直接派生出新类,往往都是从它的子类中派生出新类。

如窗口类(CWnd)、应用程序类(CWinApp)、文档模板类(CDocTemplate)、视类(CView)及框架窗口类(CFrameWnd)等。

3.文档类文档对象由文档对象模板创建,用于管理应用程序的数据。

视图对象表示一个窗口的客户区,用于显示文档数据并允许读者与之交互。

有关文档/视结构的类如下:①CDocTemplate类:文档模板的基类。

文档模板用于协调文档、视图和框架窗口的创建。

②CSingleDocTemplate类:单文档界面(SDI)的文档模板。

③CMultiDocTemplate类:多文档界面(MDI)的文档模板。

mfc序列化底层原理

mfc序列化底层原理

mfc序列化底层原理哎,你问到mfc序列化底层原理,这可是个技术活儿啊。

说起这个,咱们先来聊聊啥是mfc序列化吧。

简单来说,mfc序列化就是把对象的状态信息转换成可以存储或传输的形式的过程,比如保存到文件或者通过网络发送。

咱们四川这边说这事儿,可能会说:“哎呀,mfc序列化,就像咱们把新鲜菜蔬晒干儿,留到冬天吃一样,把对象的状态信息给‘晒干’了,等到需要的时候再‘泡开’来用。

”虽然这比喻可能不太贴切,但大概就是这个意思。

再来说说陕西方言怎么讲。

在陕西那边,可能会说:“mfc序列化嘛,就像咱把面捏成各种形状,然后晒干保存,等到吃的时候再煮。

这序列化就是把对象的状态捏成个‘面团’,方便存储和传输。

”那么,说到这mfc序列化的底层原理,其实它主要是基于C++的流操作实现的。

咱们知道,C++中的流操作可以用来读写文件、网络传输等,而mfc 序列化就是利用了这种流操作,把对象的状态信息写入到一个流中,然后再从这个流中读取出来。

具体来说,当咱们要对一个对象进行序列化时,mfc会调用这个对象的Serialize函数。

这个函数会告诉mfc如何把这个对象的状态信息写入到一个流中。

同样的,当咱们要从一个流中读取一个对象的状态信息时,也是通过调用这个对象的Serialize函数来实现的。

这个过程其实挺复杂的,涉及到很多底层的细节。

但是咱们只要知道,mfc 序列化就是通过这种流操作的方式,把对象的状态信息转换成可以存储或传输的形式的。

总的来说,mfc序列化是个挺有用的技术,它可以让咱们方便地保存和传输对象的状态信息。

当然,要真正理解和掌握它,还得深入学习C++和mfc 的相关知识。

不过咱们今天就先聊到这儿吧,如果你还有啥问题,随时问我哈!。

四永久保存(串行化)

四永久保存(串行化)

四.永久保存(串行化)先用一句话来说明永久保存的重要:弄懂它以后,你就越来越像个程序员了!如果我们的程序不需要永久保存,那几乎可以肯定是一个小玩儿。

那怕我们的记事本、画图等小程序,也需要保存才有真正的意义。

对于MFC的很多地方我不甚满意,总觉得它喜欢拿一组低能而神秘的宏来故弄玄虚,但对于它的连续存储(serialize)机制,却是我十分钟爱的地方。

在此,可让大家感受到面向对象的幸福。

MFC的连续存储(serialize)机制俗称串行化。

“在你的程序中尽管有着各种各样的数据,serialize机制会象流水一样按顺序存储到单一的文件中,而又能按顺序地取出,变成各种不同的对象数据。

”不知我在说上面这一句话的时候,大家有什么反应,可能很多朋友直觉是一件很简单的事情,只是说了一个“爽”字就没有下文了。

要实现象流水一样存储其实是一个很大的难题。

试想,在我们的程序里有各式各样的对象数据。

如画图程序中,里面设计了点类,矩形类,圆形类等等,它们的绘图方式及对数据的处理各不相同,用它们实现了成百上千的对象之后,如何存储起来?不想由可,一想头都大了:我们要在程序中设计函数store(),在我们单击“文件/保存”时能把各对象往里存储。

那么这个store()函数要神通广大,它能清楚地知道我们设计的是什么样的类,产生什么样的对象。

大家可能并不觉得这是一件很困难的事情,程序有能力知道我们的类的样子,对象也不过是一块初始化了存储区域罢了。

就把一大堆对象“转换”成磁盘文件就行了。

即使上面的存储能成立,但当我们单击“文件/打开”时,程序当然不能预测用户想打开哪个文件,并且当打开文件的时候,要根据你那一大堆垃圾数据new出数百个对象,还原为你原来存储时的样子,你又该怎么做呢?试想,要是我们有一个能容纳各种不同对象的容器,这样,用户用我们的应用程序打开一个磁盘文件时,就可以把文件的内容读进我们程序的容器中。

把磁盘文件读进内存,然后识别它“是什么对象”是一件很难的事情。

MFC六大核心机制

MFC六大核心机制

MFC六大核心机制1.消息映射机制:MFC使用明确的消息映射机制来处理用户界面和系统事件。

应用程序通过重写消息映射函数来处理不同的消息事件,如鼠标点击、按键操作等。

消息映射机制使得开发者可以方便地响应和处理不同的用户交互动作。

2. 文档视图(Doc/View)体系:MFC采用了文档视图体系,将应用程序数据(文档)和用户界面(视图)分离。

文档表示应用程序的数据,视图代表用户界面,通过文档视图模式可以实现多视图的显示和操作。

开发者可以自定义文档类和视图类,通过它们来管理和展示数据。

3.对象序列化机制:对象序列化是指将对象的状态转换为可以存储或传输的格式,以便于在不同的环境中恢复对象的状态。

MFC提供了强大的对象序列化支持,可以方便地对应用程序的数据进行存储和加载。

开发者只需将需要序列化的成员变量标记为可序列化,并实现相关的序列化函数即可实现数据的持久化。

4.多线程支持:MFC提供了多线程支持,使得应用程序可以在多个线程中同时执行任务。

开发者可以使用MFC提供的线程类来创建和管理线程,并通过消息机制进行线程间的通信。

多线程支持有助于提高应用程序的性能和响应能力。

MFC的运行时类是一组用于封装常用功能的类,包括字符串操作、容器类、文件I/O等。

这些类提供了方便、高效的操作接口,减少了开发者对底层操作的依赖。

开发者可以直接使用MFC提供的运行时类来简化开发过程。

6.扩展性:MFC提供了丰富的扩展性机制,包括自定义控件、自定义对话框、自定义视图等。

开发者可以通过派生已有的MFC类来创建自定义的控件或界面,以满足特定的应用程序需求。

扩展性机制使得开发者可以充分发挥自己的创造力和想象力,实现更加个性化的应用程序。

总结:MFC六大核心机制为开发者提供了丰富的类和功能,使得开发Windows图形界面应用程序更加简单和高效。

通过消息映射机制、文档视图体系、对象序列化机制、多线程支持、运行时类和扩展性机制,开发者可以轻松地实现各种应用程序的需求,并提供更好的用户体验。

MFC类的序列化

MFC类的序列化

MFC 类的序列化MFC类的序列化又被称作串行化首先我们介绍下什么叫做序列化,简单说来序列化是将对象的状态信息转换为可以存储或传输的窗体的过程。

在序列化期间,对象将其当前状态写入到临时或持久性存储区。

以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

在向导创建的应用程序中,程序的默认菜单有"文件"、"编辑"、"视图"和"帮助"。

当运行程序后,打开"文件"菜单中的"打开"命令时,应用程序会自动打开相应的"打开"文件通用对话框。

之所以有这功能,是因为向导创建的应用程序框架中,自动将"打开"菜单命令与CWinApp的OnFileOpen成员函数相关联。

当用户在通用"打开"文件对话框中指定一个文件后,应用程序将调用文档对象的CDocument:OnOpenDocument虚成员函数。

该函数将打开文件,并调用DeleteContents清除文档对象的内容,然后创建一个CArchive(归档类)对象用于数据的读取,接着又自动调用Serialize函数。

之后便调用视图对象的CView:OnInitialUpdate虚成员函数。

上述的Serialize函数是一个很特别的函数,它既可以从中读取文档数据,也可以保存文档数据,称为"序列化"函数。

它被添加用户的文档类中,用来根据CArchive内部的一个标志来决定文档数据的流向(读或写),打开机制:可以看到消息映射ON_COMMAND(ID_FILE_OPEN,CWinApp:OnFileOpen),如果你没有映射ID_FILE_OPEN消息,就会调用CWinApp:OnFileOpen,否则调用你的消息映射函数。

在CWinApp:OnFileOpen中调用CDocManager:OnFileOpen(),这样函数完成以下任务:1。

mfc2019 类库参考手册

mfc2019 类库参考手册

mfc2019 类库参考手册MFC 2019 类库参考手册一、概述MFC(Microsoft Foundation Class)是微软公司为了简化Windows 应用程序开发而开发的类库。

本手册将详细介绍MFC 2019类库的各个模块,包括类的定义、成员函数、属性和示例等内容,为开发人员提供全面且准确的参考。

二、基础类1. CObject类CObject类是MFC类库的基类,所有MFC类都从该类派生。

本节将介绍CObject类的成员函数、构造函数和析构函数。

2. CWnd类CWnd类封装了Windows窗口的操作。

本节将介绍CWnd类的常用成员函数,如Create、ShowWindow和SendMessage等。

3. CWinApp类CWinApp类是一个应用程序对象类,每个MFC应用程序都必须拥有一个CWinApp类的派生类。

本节将介绍CWinApp类的初始化、消息循环和资源管理等功能。

三、窗口和控件类1. CFrameWnd类CFrameWnd类是MFC应用程序的主框架窗口类,它提供了标题栏、菜单、工具栏和状态栏等功能。

本节将介绍CFrameWnd类的创建和布局等操作。

2. CDialog类CDialog类是MFC应用程序中常用的对话框类,用于创建模态或非模态对话框。

本节将介绍CDialog类的创建和消息处理等方法。

3. CButton类CButton类封装了Windows中的按钮控件,提供了按钮的创建、属性设置和消息处理等功能。

本节将介绍CButton类的常用成员函数,如Create、SetCheck和EnableWindow等。

4. CEdit类CEdit类封装了Windows中的编辑框控件,可用于接受用户的输入和显示文本内容。

本节将介绍CEdit类的创建、文本操作和消息处理等方法。

四、绘图和界面类1. CDC类CDC类提供了对设备上下文的封装,用于进行绘图和界面操作。

本节将介绍CDC类的绘图函数,如LineTo、Rectangle和TextOut等。

串行化(Serialization)

串行化(Serialization)
saveArchive.m_pDocument = this;
saveArchive.m_bForceFlat = FALSE;
TRY
{
CWaitCursor wait;
return FALSE;
}
DeleteContents();
SetModifiedFlag(); // dirty during de-serialize
cout << i;
使用这种方式进行I/O的好处时,利用运算符重载功能,可以用一个语句完成对一系列的对象的读写,而不需要区分对象具体的类型。MFC提供了类CArchive,实现了运算符<<和>>的重载,希望按照前面cin和cout 的方式进行文件I/O。通过和CFile类的配合,不仅仅实现了对简单类型如int/float等的文件读写,而且实现了对可序列化对象(Serializable Objects,这个概念后面描述)的文件读写。
if (pFile == NULL)
{
ReportSaveLoadException(lpszPathName, &fe,
TRUE, AFX_IDP_INVALID_FILENAME);
Serialize(saveArchive); // save me
saveArchive.Close();
ReleaseFile(pFile, FALSE);
ar << obj1<<obj2<<obj3...<<objn;
ar.Flush();
//写完毕,关闭文件流
ar.Close();
file.Close();

MFC串口通信编程详解

MFC串口通信编程详解

MFC 串口通信编程介绍主要介绍了用CreateFile函数和WriteFile函数读写串口的实例以及设置串口属性的实例. 在工业控制中工控机一般都基于Windows 平台经常需要与智能仪表通过串口进行通信.串口通信方便易行应用广泛. 一般情况下工控机和各智能仪表通过RS485 总线进行通信.RS485 的通信方式是半双工的只能由作为主节点的工控PC 机依次轮询网络上的各智能控制单元子节点.每次通信都是由PC 机通过串口向智能控制单元发布命令智能控制单元在接收到正确的命令后作出应答. 在Win32 下可以使用两种编程方式实现串口通信其一是使用ActiveX 控件这种方法程序简单但欠灵活.其二是调用Windows 的API函数这种方法可以清楚地掌握串口通信的机制并且自由灵活.下面只介绍API 串口通信部分. 串口的操作可以有两种操作方式:同步操作方式和重叠操作方式又称为异步操作方式.同步操作时API 函数会阻塞直到操作完成以后才能返回在多线程方式中虽然不会阻塞主线程但是仍然会阻塞监听线程而重叠操作方式API 函数会立即返回操作在后台进行避免线程的阻塞. 无论哪种操作方式一般都通过四个步骤来完成: 1打开串口2配置串口3读写串口4关闭串口一打开串口Win32 系统把文件的概念进行了扩展.无论是文件、通信设备、命名管道、邮件槽、磁盘、还是控制台都是用API 函数CreateFile 来打开或创建的.该函数的原型为: HANDLE CreateFile LPCTSTR lpFileName DWORD dwDesiredAccess DWORD dwShareMode LPSECURITY_ATTRIBUTES lpSecurityAttributes DWORD dwCreationDistribution DWORD dwFlagsAndAttributes HANDLE hTemplateFile lpFileName:将要打开的串口逻辑名如“COM1” dwDesiredAccess:指定串口访问的类型可以是读取、写入或二者并列dwShareMode:指定共享属性由于串口不能共享该参数必须置为0 lpSecurityAttributes:引用安全性属性结构缺省值为NULL dwCreationDistribution:创建标志对串口操作该参数必须置为OPEN_EXISTING dwFlagsAndAttributes:属性描述用于指定该串口是否进行异步操作该值为FILE_FLAG_OVERLAPPED表示使用异步的I/O该值为0表示同步I/O 操作hTemplateFile:对串口而言该参数必须置为NULL同步I/O 方式打开串口的示例:HANDLE hCom//全局变量串口句柄hComCreateFilequotCOM1quot//串口名称GENERIC_READGENERIC_WRITE//允许读和写0//独占方式NULL OPEN_EXISTING//打开而不是创建0//同步方式NULLifhComHANDLE-1 MessageBoxquot?蚩?COM 失败quot return FALSEreturn TRUE重叠I/O 打开串口的示例:HANDLE hCom//全局变量串口句柄hCom CreateFilequotCOM1quot//串口名称GENERIC_READGENERIC_WRITE//允许读和写0//独占方式NULL OPEN_EXISTING//打开而不是创建FILE_ATTRIBUTE_NORMALFILE_FLAG_OVERLAPPED//重叠方式NULLifhComINVALID_HANDLE_VALUE MessageBoxquot打开COM 失败quot return FALSEreturn TRUE二配置串口在打开通讯设备句柄后常需要对串口进行一些初始化配置工作.这需要通过一个DCB 结构来进行.DCB 结构包含了诸如波特率、数据位数、奇偶校验和停止位数等信息.在查询或配置串口的属性时都要用DCB 结构来作为缓冲区. 一般用CreateFile 打开串口后可以调用GetCommState 函数来获取串口的初始配置.要修改串口的配置应该先修改DCB 结构然后再调用SetCommState 函数设置串口. DCB 结构包含了串口的各项参数设置下面仅介绍几个该结构常用的变量: typedef struct _DCB ……… //波特率指定通信设备的传输速率.这个成员可以是实际波特率值或者下面的常量值之一: DWORDBaudRate//CBR_110CBR_300CBR_600CBR_1200CBR_2400CBR_4800CBR_9600CB R_19200//CBR_38400//CBR_56000CBR_57600CBR_115200CBR_128000CBR_25600 0CBR_14400 DWORD fParity//指定奇偶校验使能.若此成员为1允许奇偶校验检查… BYTE ByteSize//通信字节位数4—8 BYTE Parity//指定奇偶校验方法.此成员可以有下列值: //EVENPARITY 偶校验NOPARITY 无校验//MARKPARITY 标记校验ODDPARITY 奇校验BYTE StopBits//指定停止位的位数.此成员可以有下列值: //ONESTOPBIT 1 位停止位TWOSTOPBITS 2 位停止位//ONE5STOPBITS 1.5 位停止位……… DCB 在winbase.h 文件中定义了以上用到的常量.如下所示: define NOPARITY 0 define ODDPARITY 1 define EVENPARITY 2 define ONESTOPBIT 0 define ONE5STOPBITS 1 define TWOSTOPBITS 2 define CBR_110 110 define CBR_300 300 define CBR_600 600 define CBR_1200 1200 defineCBR_2400 2400 define CBR_4800 4800 define CBR_9600 9600 define CBR_14400 14400 define CBR_19200 19200 define CBR_38400 38400 define CBR_56000 56000 define CBR_57600 57600 define CBR_115200 115200 define CBR_128000 128000 define CBR_256000 256000 GetCommState 函数可以获得COM 口的设备控制块从而获得相关参数: BOOL GetCommState HANDLE hFile //标识通讯端口的句柄LPDCB lpDCB //指向一个设备控制块DCB 结构的指针SetCommState 函数设置COM 口的设备控制块: BOOL SetCommState HANDLE hFile LPDCB lpDCB 除了在BCD 中的设置外程序一般还需要设置I/O 缓冲区的大小和超时.Windows用I/O 缓冲区来暂存串口输入和输出的数据.如果通信的速率较高则应该设置较大的缓冲区.调用SetupComm 函数可以设置串行口的输入和输出缓冲区的大小. BOOL SetupComm HANDLE hFile // 通信设备的句柄DWORD dwInQueue // 输入缓冲区的大小字节数DWORD dwOutQueue // 输出缓冲区的大小字节数在用ReadFile 和WriteFile 读写串行口时需要考虑超时问题.超时的作用是在指定的时间内没有读入或发送指定数量的字符ReadFile 或WriteFile 的操作仍然会结束. 要查询当前的超时设置应调用GetCommTimeouts 函数该函数会填充一个COMMTIMEOUTS 结构.调用SetCommTimeouts 可以用某一个COMMTIMEOUTS 结构的内容来设置超时. 读写串口的超时有两种:间隔超时和总超时.间隔超时是指在接收时两个字符之间的最大时延.总超时是指读写操作总共花费的最大时间.写操作只支持总超时而读操作两种超时均支持.用COMMTIMEOUTS 结构可以规定读写操作的超时. COMMTIMEOUTS 结构的定义为: typedef struct _COMMTIMEOUTS DWORD ReadIntervalTimeout//读间隔超时DWORD ReadTotalTimeoutMultiplier//读时间系数DWORD ReadTotalTimeoutConstant//读时间常量DWORD WriteTotalTimeoutMultiplier//写时间系数DWORD WriteTotalTimeoutConstant//写时间常量COMMTIMEOUTSLPCOMMTIMEOUTS COMMTIMEOUTS 结构的成员都以毫秒为单位.总超时的计算公式是:总超时=时间系数×要求读/写的字符数+时间常量例如要读入10 个字符那么读操作的总超时的计算公式为:读总超时=ReadTotalTimeoutMultiplier×10+ReadTotalTimeoutConstant 可以看出:间隔超时和总超时的设置是不相关的这可以方便通信程序灵活地设置各种超时. 如果所有写超时参数均为0那么就不使用写超时.如果ReadIntervalTimeout 为0那么就不使用读间隔超时.如果ReadTotalTimeoutMultiplier 和ReadTotalTimeoutConstant 都为0则不使用读总超时.如果读间隔超时被设置成MAXDWORD 并且读时间系数和读时间常量都为0那么在读一次输入缓冲区的内容后读操作就立即返回而不管是否读入了要求的字符. 在用重叠方式读写串口时虽然ReadFile 和WriteFile 在完成操作以前就可能返回但超时仍然是起作用的.在这种情况下超时规定的是操作的完成时间而不是ReadFile 和WriteFile 的返回时间.配置串口的示例:SetupCommhCom10241024//输入缓冲区和输出缓冲区的大小都是1024 COMMTIMEOUTS TimeOuts //设定读超时TimeOuts.ReadIntervalTimeout1000 TimeOuts.ReadTotalTimeoutMultiplier500 TimeOuts.ReadTotalTimeoutConstant5000 //设定写超时TimeOuts.WriteTotalTimeoutMultiplier500TimeOuts.WriteTotalTimeoutConstant2000 SetCommTimeoutshComampTimeOuts//设置超时DCB dcb GetCommStatehComampdcb dcb.BaudRate9600//波特率为9600 dcb.ByteSize8//每个字节有8 位dcb.ParityNOPARITY//无奇偶校验位dcb.StopBitsTWOSTOPBITS//两个停止位SetCommStatehComampdcb PurgeCommhComPURGE_TXCLEARPURGE_RXCLEAR 在读写串口之前还要用PurgeComm函数清空缓冲区该函数原型: BOOL PurgeComm HANDLE hFile//串口句柄DWORD dwFlags//需要完成的操作参数dwFlags 指定要完成的操作可以是下列值的组合: PURGE_TXABORT 中断所有写操作并立即返回即使写操作还没有完成. PURGE_RXABORT 中断所有读操作并立即返回即使读操作还没有完成. PURGE_TXCLEAR 清除输出缓冲区PURGE_RXCLEAR 清除输入缓冲区三读写串口使用ReadFile 和WriteFile 读写串口下面是两个函数的声明: BOOL ReadFile HANDLE hFile//串口的句柄//读入的数据存储的地址//即读入的数据将存储在以该指针的值为首地址的一片内存区LPVOID lpBuffer DWORD nNumberOfBytesToRead //要读入的数据的字节数//指向一个DWORD 数值该数值返回读操作实际读入的字节数LPDWORD lpNumberOfBytesRead //重叠操作时该参数指向一个OVERLAPPED 结构同步操作时该参数为NULL. LPOVERLAPPED lpOverlapped BOOL WriteFile HANDLE hFile//串口的句柄//写入的数据存储的地址//即以该指针的值为首地址的nNumberOfBytesToWrite //个字节的数据将要写入串口的发送数据缓冲区. LPCVOID lpBuffer DWORD nNumberOfBytesToWrite//要写入的数据的字节数//指向指向一个DWORD 数值该数值返回实际写入的字节数LPDWORD lpNumberOfBytesWritten //重叠操作时该参数指向一个OVERLAPPED 结构//同步操作时该参数为NULL. LPOVERLAPPED lpOverlapped 在用ReadFile 和WriteFile 读写串口时既可以同步执行也可以重叠执行.在同步执行时函数直到操作完成后才返回.这意味着同步执行时线程会被阻塞从而导致效率下降.在重叠执行时即使操作还未完成这两个函数也会立即返回费时的I/O 操作在后台进行. ReadFile 和WriteFile 函数是同步还是异步由CreateFile 函数决定如果在调用CreateFile 创建句柄时指定了FILE_FLAG_OVERLAPPED 标志那么调用ReadFile 和WriteFile 对该句柄进行的操作就应该是重叠的如果未指定重叠标志则读写操作应该是同步的.ReadFile 和WriteFile 函数的同步或者异步应该和CreateFile 函数相一致. ReadFile 函数只要在串口输入缓冲区中读入指定数量的字符就算完成操作.而WriteFile 函数不但要把指定数量的字符拷入到输出缓冲区而且要等这些字符从串行口送出去后才算完成操作. 如果操作成功这两个函数都返回TRUE.需要注意的是当ReadFile 和WriteFile返回FALSE 时不一定就是操作失败线程应该调用GetLastError 函数分析返回的结果.例如在重叠操作时如果操作还未完成函数就返回那么函数就返回FALSE而且GetLastError 函数返回ERROR_IO_PENDING.这说明重叠操作还未完成.下面是同步方式读写串口的示例://同步读串口charstr100DWORD wCount//读取的字节数BOOL bReadStatbReadStatReadFilehComstr100ampwCountNULLifbReadStat MessageBoxquot读串口失败quot return FALSEreturn TRUE//同步写串口char lpOutBuffer100DWORD dwBytesWrite100COMSTAT ComStatDWORD dwErrorFlagsBOOL bWriteStatClearCommErrorhComampdwErrorFlagsampComStatbWriteStatWriteFilehC omlpOutBufferdwBytesWriteamp dwBytesWriteNULLifbWriteStat MessageBoxquot写串口失败quotPurgeCommhComPURGE_TXABORTPURGE_RXABORTPURGE_TXCLEARPURGE_RXCLEAR 在重叠操作时操作还未完成函数就返回. 重叠I/O 非常灵活它也可以实现阻塞例如我们可以设置一定要读取到一个数据才能进行到下一步操作.有两种方法可以等待操作完成:一种方法是用象WaitForSingleObject 这样的等待函数来等待OVERLAPPED 结构的hEvent 成员另一种方法是调用GetOverlappedResult 函数等待后面将演示说明. 下面先简单介绍一下OVERLAPPED 结构和GetOverlappedResult 函数: OVERLAPPED 结构OVERLAPPED 结构包含了重叠I/O 的一些信息定义如下: typedef struct _OVERLAPPED DWORD Internal DWORD InternalHigh DWORD Offset DWORD OffsetHigh HANDLE hEvent OVERLAPPED 在使用ReadFile 和WriteFile 重叠操作时线程需要创建OVERLAPPED 结构以供这两个函数使用.线程通过OVERLAPPED 结构获得当前的操作状态该结构最重要的成员是hEvent.hEvent 是读写事件.当串口使用异步通讯时函数返回时操作可能还没有完成程序可以通过检查该事件得知是否读写完毕. 当调用ReadFile WriteFile 函数的时候该成员会自动被置为无信号状态当重叠操作完成后该成员变量会自动被置为有信号状态. GetOverlappedResult 函数BOOL GetOverlappedResult HANDLE hFile//串口的句柄//指向重叠操作开始时指定的OVERLAPPED 结构LPOVERLAPPED lpOverlapped //指向一个32 位变量该变量的值返回实际读写操作传输的字节数. LPDWORD lpNumberOfBytesTransferred //该参数用于指定函数是否一直等到重叠操作结束. //如果该参数为TRUE函数直到操作结束才返回. //如果该参数为FALSE函数直接返回这时如果操作没有完成//通过调用GetLastError函数会返回ERROR_IO_INCOMPLETE. BOOL bWait 该函数返回重叠操作的结果用来判断异步操作是否完成它是通过判断OVERLAPPED 结构中的hEvent 是否被置位来实现的.异步读串口的示例:char lpInBuffer1024DWORD dwBytesRead1024COMSTAT ComStatDWORD dwErrorFlagsOVERLAPPEDm_osReadmemsetampm_osRead0sizeofOVERLAPPEDm_osRead.hEventCreateEventN ULLTRUEFALSENULLClearCommErrorhComampdwErrorFlagsampComStatdwBytes ReadmindwBytesReadDWORDComStat.cbInQueifdwBytesReadreturn FALSEBOOL bReadStatusbReadStatusReadFilehComlpInBufferdwBytesReadampdwBytesReadampm _osReadifbReadStatus//如果ReadFile 函数返回FALSE ifGetLastErrorERROR_IO_PENDING //GetLastError函数返回ERROR_IO_PENDING表明串口正在进行读操作WaitForSingleObjectm_osRead.hEvent2000 //使用WaitForSingleObject 函数等待直到读操作完成或延时已达到2 秒钟//当串口读操作进行完毕后m_osRead 的hEvent 事件会变为有信号PurgeCommhCom PURGE_TXABORTPURGE_RXABORTPURGE_TXCLEARPURGE_RXCLEAR return dwBytesRead return 0PurgeCommhComPURGE_TXABORTPURGE_RXABORTPURGE_TXCLEARPURGE_RXCLEARreturn dwBytesRead 对以上代码再作简要说明:在使用ReadFile 函数进行读操作前应先使用ClearCommError 函数清除错误.ClearCommError 函数的原型如下: BOOL ClearCommError HANDLE hFile//串口句柄LPDWORD lpErrors//指向接收错误码的变量LPCOMSTAT lpStat//指向通讯状态缓冲区该函数获得通信错误并报告串口的当前状态同时该函数清除串口的错误标志以便继续输入、输出操作. 参数lpStat 指向一个COMSTAT 结构该结构返回串口状态信息.COMSTAT 结构COMSTAT 结构包含串口的信息结构定义如下: typedef struct _COMSTAT//cst DWORD fCtsHold : 1//Tx waiting for CTS signal DWORD fDsrHold : 1//Tx waiting for DSR signal DWORD fRlsdHold : 1//Tx waiting for RLSD signal DWORD fXoffHold : 1//Tx waitingXOFF char recd DWORD fXoffSent : 1//Tx waiting XOFF char sent DWORD fEof : 1//EOF character sent DWORD fTxim : 1//character waiting for Tx DWORD fReserved : 25//reserved DWORD cbInQue//bytes in input buffer DWORD cbOutQue//bytes in output buffer COMSTAT LPCOMSTAT 这里只用到了cbInQue 成员变量该成员变量的值代表输入缓冲区的字节数. 最后用PurgeComm 函数清空串口的输入输出缓冲区. 这段代码用WaitForSingleObject 函数来等待OVERLAPPED 结构的hEvent 成员.下面是调用GetOverlappedResult 函数等待的异步读串口示例:char lpInBuffer1024DWORD dwBytesRead1024BOOL bReadStatusDWORD dwErrorFlagsCOMSTAT ComStatOVERLAPPEDm_osReadClearCommErrorhComampdwErrorFlagsampComStatifComStat.cbInQue return0dwBytesReadmindwBytesReadDWORDComStat.cbInQuebReadStatusReadFilehCom lpInBufferdwBytesRead ampdwBytesReadampm_osReadifbReadStatus//如果ReadFile 函数返回FALSE ifGetLastErrorERROR_IO_PENDING GetOverlappedResulthComampm_osReadampdwBytesReadTRUE//GetOverlappedResult 函数的最后一个参数设为TRUE //函数会一直等待直到读操作完成或由于错误而返回. return dwBytesRead return 0return dwBytesRead异步写串口的示例:char buffer1024DWORD dwBytesWritten1024DWORD dwErrorFlagsCOMSTAT ComStatOVERLAPPED m_osWriteBOOL bWriteStatbWriteStatWriteFilehCombufferdwBytesWritten ampdwBytesWrittenampm_OsWriteifbWriteStat ifGetLastErrorERROR_IO_PENDING WaitForSingleObjectm_osWrite.hEvent1000 return dwBytesWritten return 0return dwBytesWritten四关闭串口利用API 函数关闭串口非常简单只需使用CreateFile 函数返回的句柄作为参数调用CloseHandle 即可: BOOL CloseHandle HANDLE hObject//handle to object to close 为了更好地理解串口编程下面分别编写两个实例这两个实例都实现了工控机与百特显示仪表通过RS485 接口进行的串口通信.其中第一个实例采用同步串口操作第二个实例采用异步串口操作.实例 1 打开VC6.0新建基于对话框的工程RS485Comm在主对话框窗口.。

mfc CObject类

mfc CObject类

3.CObject类CObject是大多数MFC类的根类或基类。

CObject类有很多有用的特性:对运行时类信息的支持,对动态创建的支持,对串行化的支持,对象诊断输出,等等。

MFC从CObject派生出许多类,具备其中的一个或者多个特性。

程序员也可以从CObject类派生出自己的类,利用CObject类的这些特性。

本章将讨论MFC如何设计CObject类的这些特性。

首先,考察CObject 类的定义,分析其结构和方法(成员变量和成员函数)对CObject特性的支持。

然后,讨论CObject特性及其实现机制。

1.CObject的结构以下是CObject类的定义:class CObject{public://与动态创建相关的函数virtual CRuntimeClass*GetRuntimeClass()const;析构函数virtual~CObject();//virtual destructors are necessary//与构造函数相关的内存分配函数,可以用于DEBUG下输出诊断信息void*PASCAL operator new(size_t nSize);void*PASCAL operator new(size_t,void*p);void PASCAL operator delete(void*p);#if defined(_DEBUG)&&!defined(_AFX_NO_DEBUG_CRT)void*PASCAL operator new(size_t nSize,LPCSTRlpszFileName,int nLine);#endif//缺省情况下,复制构造函数和赋值构造函数是不可用的//如果程序员通过传值或者赋值来传递对象,将得到一个编译错误protected://缺省构造函数CObject();private://复制构造函数,私有CObject(const CObject&objectSrc);//no implementation//赋值构造函数,私有void operator=(const CObject&objectSrc);//no implementation//Attributespublic://与运行时类信息、串行化相关的函数BOOL IsSerializable()const;BOOL IsKindOf(const CRuntimeClass*pClass)const;//Overridablesvirtual void Serialize(CArchive&ar);//诊断函数virtual void AssertValid()const;virtual void Dump(CDumpContext&dc)const;//Implementationpublic://与动态创建对象相关的函数static const AFX_DATA CRuntimeClass classCObject;#ifdef_AFXDLLstatic CRuntimeClass*PASCAL_GetBaseClass();#endif};由上可以看出,CObject定义了一个CRuntimeClass类型的静态成员变量:CRuntimeClass classCObject还定义了几组函数:构造函数析构函数类,诊断函数,与运行时类信息相关的函数,与串行化相关的函数。

MFC how to Serialize

MFC how to Serialize

MFC 怎样做Serialize(串行化/序列化) MFC的连续存储(serialize)机制俗称串行化。

在你的程序中尽管有着各种各样的数据,serialize 机制会象流水一样按顺序存储到单一的文件中,而又能按顺序地取出,变成各种不同的对象数据?那就要用到串行化。

一个类要支持串行化需要:∙该类必须要继承自CObject∙在该类的头文件中添加DECLARE_SERIAL宏∙在该类的实现文件中添加IMPLEMENT SERIAL宏∙为该类添加一个没有参数的构造函数,用于串行化时由磁盘文件创建对象的看,通过没有参数的构造函数,框架就可以在载入文档时,创建任何一个可序列化类的对象,然后再调用你的Serialize()函数来填充新创建的对象成员变量。

∙在该类中重写Serialize( CArchive& ar )函数之后,该类就可以被Serial izable。

让我们先看看MFC自动生成的CxxxDoc::Serialize(CArchive &ar)函数,CxxxDoc中xxx是你的程序.这段代码只是MFC给你做的一个基本框架,实际没有任何功能,但是从中可以看出是,保存数据是要想ar中写数据,从外读数据到程序中是从ar中读,ar 与外部文件建立联系,ar 是通过CArchive 的构造函数与外部文件建立联系的,如CArchive ar(&openfile,CArchive::load|CArchive::bNoFlushOnDelete)。

还是让我们开始通过例子说明吧。

如果我们要在MFC的View中画一些圆,然后保存到文件中,下一次程序启动后,再将这个文件打开,如同上一次保存那样,甚至还可以取消上一次画的圆。

让我们想象,我们肯定不是将View中客户区作为一个图形文件保存下来。

而是将画的动作如圆,矩形各制作一个类,这个类就要抽象出对象的特性出来,如圆的坐标,圆的直径,笔的颜色等等,我们只要保存这个就可以了。

vc++上的MFC的对象序列化和反序列化

vc++上的MFC的对象序列化和反序列化

vc++上的MFC的对象序列化和反序列化注意点:1. 必须类型序列化声明DECLARE_SERIAL( Person )2. 必须写出实现宏IMPLEMENT_SERIAL(Person, CObject, VERSIONABLE_SCHEMA | 2)3. 重写CObject中的Serialize函数void Person::Serialize( CArchive& ar ){CObject::Serialize(ar);//关键代码if(ar.IsStoring()) {//序列化ar << this->age << this->sex << this->name;} else {//反序列化ar >> this->age >> this->sex >> this->name;}}序列化后的数据[cpp]1. //Person.h2. #pragma once3. #include <afx.h>4. #include <string>5. #include <atlstr.h>6.7. using namespace std;8.9. class Person: public CObject10. {11. private:12. //注意MFC 不⽀持标准std:string对象序列化, boost库⽀持std:string13. CString name;14. int age;15. char sex;16. public:17. DECLARE_SERIAL( Person )18.19. Person(void);20.21. Person(CString name, int age, char sex);22.23. virtual ~Person(void);24.25. virtual void Serialize(CArchive& ar);26.27. void setName(CString pName);28.29. CString getName();30.31. void setAge(int age);32.33. int getAge();34.35. void setSex(char sex);36.37. char getSex();39.40. //Person.cpp41. #include "StdAfx.h"42. #include "Person.h"43. #include <afx.h>44. #include <string>45.46. //必须写出实现宏47. IMPLEMENT_SERIAL(Person, CObject, VERSIONABLE_SCHEMA | 2)48.49. Person::Person(void)50. {51. }52.53. Person::Person( CString name, int age, char sex )54. {55. this->name = name;56. this->age = age;57. this->sex = sex;58. }59.60. Person::~Person(void)61. {62. }63.64. void Person::setName( CString name)65. {66. this->name = name;67. }68.69. CString Person::getName()70. {71. return this->name;72. }73.74. void Person::setAge( int age )75. {76. this->age = age;77. }78.79. int Person::getAge()80. {81. return this->age;82. }83.84. void Person::setSex( char sex )85. {86. this->sex = sex;87. }88.89. char Person::getSex()90. {91. return this->sex;92. }93.94. void Person::Serialize( CArchive& ar )95. {96. CObject::Serialize(ar);97. //关键代码98. if(ar.IsStoring()) {99. //序列化100. ar << this->age << this->sex << this->name;101. } else {102. //反序列化103. ar >> this->age >> this->sex >> this->name;104. }105. }107. // main.cpp : 定义控制台应⽤程序的⼊⼝点。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

使用MFC 串行化数据和C++ 对象作者:JerryZ串行化数据——例子程序:Memo创建一个新的单文档SDI 应用,视图类选择CFormView,以便用户可以在窗口中输入。

在界面中创建三个编辑框,然后再添加三个相应的编辑框变量。

这三个变量是视图类的成员变量,为了交互数据,文档类中也要创建三个对应的变量。

然后,文档类和视图类都要对数据成员进行初始化操作,在文档类中这个工作通常都在OnNewDocument() 函数中进行。

因为下面任何一个操作发生时都触发文档类OnNewDocument()函数执行:∙当用户启动应用程序;∙当用户在“File”菜单中选择“New”选项;视图类的初始化通常由OnIn it ialUpdate() 负责,下面的任何一个操作发生时,代码都会触发视图类OnIn it ialUpdate()函数执行:∙当用户启动应用程序;∙当用户在“File”菜单中选择“New”选项;∙当用户从“File”菜单中选择“Open”选项;在视图类中获得文档类指针的方法是:CFooDoc* pDoc = GerDocument();用此文档指针便可以操作文档类数据:m_ViewData = pDoc->m_DocData;串行化的代码很简单,ar 是一个与用户选择的文件相对应的文档对象(CArch iv e 对象):// CFooDoc 序列化void CFooDoc::Serialize(CArchive& ar){if (ar.IsStoring()){// 将数据写入文件ar << m_DocData;}else{// 从文件中读取数据ar >> m_DocData;}}这样就将数据写入了文件,选择“File”菜单中的“Sav e”或者“Sav e as”即可完成数据的串行化。

如果没有保存数据,退出程序是会提示用户是否保存修改过的数据。

具体细节请参考源代码。

串行化C++对象——例子程序:PHN创建一个新的单文档SDI 应用,视图类选择CFormView,以便可以有窗口中用户可以输入。

声明一个要串行化的C++ 类。

如CPhone;文档类的处理:在文档类中声明一个MFC CObList 类对象,这个类很有用,功能也很强,用它可以很轻松地维护C++ 对象列表,例如添加、删除列表元素等。

在文档类的头文件中作如下声明:CObList m_PhoneList;上面的声明可以是public 类型,这样其它类可以直接访问它。

也可以是priv ate 类型,这样就必须声明一个公共的访问函数,比如:GetPhoneList(),这个函数能返回m_PhoneList 的地址。

通常可以在文档类的OnNewDocument()函数中进行数据初始化;// Create a CPhone ObjectCPhone* pPhone = new CPhone();pPhone->m_Name = "";pPhone->m_Phone = "";// Add new object to the m_PhoneList listm_PhoneList.AddHead(pPhone);在此CPhone 类的成员变量的初始化不是必须的,因为CPhone 的构造函数已经完成了这个工作。

AddHead()函数向m_PhoneList 列表添加刚创建的CPhone 对象。

所以,无论什么时候创建新文档(如启动应用程序)都会向m_PhoneList 列表中添加一个空的CPhone 对象。

注意类CObList 的成员函数AddHead() 是向列表的“头部”添加对象(列表的开始),所以参数是想要添加的对象的地址。

删除m_PhoneList 列表中的内容因为m_PhoneList 是在内存中维护的,所以要随时维护,只要下面三个事件中的任何一个事件发生,都需要从内存中删除m_PhoneList 列表中的对象:∙用户退出应用程序;∙用户开始一个新的文档,如从“File”菜单中选择“New”选项;∙用户打开一个已存在的文档,如从“File”菜单中选择“Open”选项;在文档类的头文件中声明删除操作的函数:virtual void DeleteContents();其实现如下:// 删除列表中的所有项目并释放列表对象占用的内存while ( ! m_PhoneList.IsEmpty() ){delete m_PhoneList.RemoveHead();}视图类处理:声明视图类的数据成员:POSITION m_position; // 在文档类列表中的当前位置CObList* m_pList; // 指向文档类的列表在OnIn it ialUpdate()函数中初始化视图类的数据成员POSITION m_position;CObList* m_pList;// 获取文档类指针CFooDoc* pDoc = (CFooDoc*) GetDocument();// 获得文档类m_PhoneList 的地址m_pList = &(pDoc->m_PhoneList);// 获得列表头位置m_position = m_pList->GetHeadPosition();// 用文档类数据更新视图类数据成员CPhone* pPhone = (CPhone*)m_pList->GetAt(m_position);m_Name = pPhone->m_Name;m_Phone = pPhone->m_Phone;// 用新的数据成员变量值更新屏幕显示UpdateData(FALSE);// 控制输入焦点((CDialog*) this)->GotoDlgCtrl(GetDlgItem(IDC_NAME));更新文档数据当用户修改了视图类的数据成员,即修改了窗体编辑框中的内容时,执行这些代码后也会修改文档类的数据成员。

void CFooView::OnEnChangeName(){// 用屏幕输入更新控件变量UpdateData(TRUE);// 获得文档指针CFooDoc* pDoc =(CFooDoc*)GetDocument();// 更新文档CPhone* pPhone = (CPhone*)m_pList->GetAt(m_position);pPhone->m_Name = m_Name;// 置修改标志为TRUEpDoc->SetModifiedFlag();在列表中移动记录,修改视图类中相应的函数。

// 声明一个临时的位置变量POSITION temp_pos;// 用当前的列表位置更新temp_postemp_pos = m_position;// 用前一个/或后一个位置更新temp_posm_pList->GetPrev(temp_pos);if ( temp_pos == NULL){// no previous elementMessageBox(_T("Bottom of fileencountered!"),_T("Phone for Windows"));}else{// 用列表前一个记录内容更新视图成员数据m_position = temp_pos;CPhone* pPhone =(CPhone*)m_pList->GetAt(m_position);m_Name = pPhone->m_Name;m_Phone = pPhone->m_Phone;UpdateData(FALSE);}// 控制输入焦点((CDialog*) this)->GotoDlgCtrl(GetDlgItem(IDC_NAME)); 添加和删除列表记录://添加记录// 清空屏幕输入控制m_Name = "";m_Phone = "";UpdateData(FALSE);// 创建一个新的CPhone 对象CPhone* pPhone = new CPhone();pPhone->m_Name = m_Name;pPhone->m_Phone = m_Phone;// 添加新的对象到列表尾部,并用新的位置更新m_positionm_position = m_pList->AddTail(pPhone);// 获得文档指针CFooDoc* pDoc = (CFooDoc*) GetDocument();// 置修改标志为TRUEpDoc->SetModifiedFlag();// 控制输入焦点((CDialog*)this)->GotoDlgCtrl(this->GetDlgItem(IDC_NAME));//删除记录// 删除前先保存旧的指针CObject* pOld;pOld = m_pList->GetAt(m_position);// 从列表中删除元素m_pList->RemoveAt(m_position);// 从内存中删除对象delete pOld;// 如果列表已经清空则添加一个空记录if ( m_pList->IsEmpty()){OnBnClickedAddButton();}// 获取文档指针CPHNDoc* pDoc = (CPHNDoc*) GetDocument();// 置修改标志为TRUEpDoc->SetModifiedFlag();// 显示列表的第一条记录OnInitialUpdate();串行化处理我们要串行化CPhone 对象,把C++对象写入文件,所以需要在CPhone 类的定义和实现文件中加入相应的串行化代码,首先要在CPhone 头文件中加入一个MFC 宏,这是串行化需要的宏,必须为它提供一个参数,也就是类的名字。

// 串行化宏定义DECLARE_SERIAL(CPhone)其次是声明串行化函数,这个原型是必须的,因为要串行化类CPhone 对象列表,所以CPhone 类必须有一个属于自己的Serializ e()函数:// 串行化函数Serialize()virtual void Serialize(CArchive& ar);在CPhone 实现文件中也要加入对应的代码,这个宏也是串行化需要的另一个宏,它有三个参数,第一个是类名,第二个是基类名,第三个是应用程序的版本号,可以将版本号定义为任何值,当串行化数据到文件时,此版本号也要写入文件。

相关文档
最新文档