组件实现了IPersistStream、IPersistStorage、IPersistPropertyBag接口。这些接口都提供了Load和Save方法。这些接口统称为IPersistMedium。
当需要保存组件的属性时------
1)客户查询组件的IPersistMedium接口;
2)调用IPersistMedium::GetClassID方法,然后将CLSID保存到永久介质上;
3)调用IPersistMedium::Save方法将对象属性保存到永久介质中。
当需要恢复组建对象时------
1)客户从介质中读取CLSID,创建组件对象
2)查询组件实现的接口IPersistMedium
3)调用IPersistMedium::Load方法装载对象状态
IPersistMedium均派生自IPersist接口,由组件实现。但是他们保存/恢复数据的方式依赖于客户传递进来的IMedia接口。IMedia接口包括:IStream、IStorage、IPropertyBag接口。也就是说,使客户决定了何时、以什么方式保存或者恢复组件对象状态,而组件对象只提供或者接受状态数据。
IStream接口将数据抽象为二进制的字节流。我们可以在自己的对象中实现IStream接口,COM提供了两种形式的IStram接口的实现,一种是以内存形式,一种是通过复合文件。下面分别举例:
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
::CoInitialize(NULL);
CComPtr<IStream> pStream;
HRESULT hr=CreateStreamOnHGlobal(NULL,TRUE,&pStream);
BYTE Buffer[1024];
memset(Buffer,1,1024);
ULONG Size=0;
hr=pStream->Write(Buffer,1024,&Size);
BYTE Buffer2[1024];
memset(Buffer2,0,1024);
ULONG Size2=0;
LARGE_INTEGER x;
x.LowPart=-1024;
x.HighPart=0;
hr=pStream->Seek(x,STREAM_SEEK_CUR ,0);//从当前位置回退1024个字节
hr=pStream->Read(Buffer2,1024,&Size2);
pStream.Release();
::CoUninitialize();
return 0;
}
。。。
IPersistStramInit是对IPersistStream接口的增强,但是两者不能在同一个组件中实现。组件要实现自己的IPersistStreamInit接口。客户要提供IStream接口的有效指针,IPersistStramInit接口的Load和Write方法是通过客户提供的ISream接口完成工作的。
下面的例子中,我们将实现进程内组件B,然后实现进城外组件A,B实现了IPersistStreamInit接口。A创建了IStram接口(通过复合文件的方式)。A通过调用B实现的IPersistStreamInit接口的方法实现B对象的属性永久保存和属性恢复。
下面是组件CB类的源代码,后面有注释符的就是我们手工添加的代码:
// B.h : CB 的声明
#pragma once
#include "resource.h" // 主符号
#include "StreamObject.h"
// CB
class ATL_NO_VTABLE CB :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CB, &CLSID_B>,
public IPersistStreamInit,/////////////////////
public IDispatchImpl<IB, &IID_IB, &LIBID_StreamObjectLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
CB()
{
m_Dirty=true;
}
DECLARE_REGISTRY_RESOURCEID(IDR_B)
BEGIN_COM_MAP(CB)
COM_INTERFACE_ENTRY(IB)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IPersistStreamInit)//////////////////////////////
COM_INTERFACE_ENTRY2(IPersist,IPersistStreamInit)///////////////////
END_COM_MAP()
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
return S_OK;
}
void FinalRelease()
{
}
public:
STDMETHODIMP GetClassID(CLSID* pClassID)///////////////////
{
return S_OK;
}
STDMETHODIMP IsDirty()////////////////////
{
return m_Dirty ? S_OK:S_FALSE;
}
STDMETHODIMP InitNew()///////////////////////
{
m_Value=L"default";
return S_OK;
}
STDMETHODIMP Load(IStream* pStream)///////////////////////
{
return m_Value.ReadFromStream(pStream);
}
STDMETHODIMP Save(IStream* pStream,BOOL fClearDirty)///////////////////////
{
if(fClearDirty)
{
m_Dirty=false;
}
return m_Value.WriteToStream(pStream);
}
STDMETHODIMP GetSizeMax(ULARGE_INTEGER* pCBSize)////////////////////////
{
if(pCBSize==NULL)
return E_POINTER;
pCBSize->QuadPart=sizeof(ULONG);
pCBSize->QuadPart+=SysStringByteLen(m_Value);
return S_OK;
}
private:
CComBSTR m_Value;
bool m_Dirty;
};
OBJECT_ENTRY_AUTO(__uuidof(B), CB)
现在我们来开发客户程序,客户程序要创建流对象,并把流接口指针传递给
组件。
// StreamClient.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#import "StreamObject.tlb" no_namespace raw_interfaces_only named_guids
int _tmain(int argc, _TCHAR* argv[])
{
::CoInitialize(NULL);
CComPtr<IB> spB;
HRESULT hr=spB.CoCreateInstance(CLSID_B);
CComPtr<IPersistStreamInit> spPersistStreamInit;
hr=spB->QueryInterface(&spPersistStreamInit);
hr=spPersistStreamInit->InitNew();
CComPtr<IStream> pStream;
hr=CreateStreamOnHGlobal(NULL,TRUE,&pStream);
hr=spPersistStreamInit->Save(pStream,TRUE);
LARGE_INTEGER x;
x.QuadPart=0;
hr=pStream->Seek(x,STREAM_SEEK_SET,0);
CComBSTR str;
hr=str.ReadFromStream(pStream);
pStream.Release();
spPersistStreamInit.Release();
spB.Release();
::CoUninitialize();
return 0;
}
ATL对实现IPersistStreamInit接口的支持
刚才我们的组件B实现IPersistStreamInit接口的时候,采用了传统的com继承方式,繁琐而且容易出错。ATL提供了IPersistStreamInitImpl类来供我们简化实现过程。
分享到:
相关推荐
**Go-moss:Go语言实现的简单快速有序可持久化Key-Value存储库** Go-moss是一个用Golang编写的Key-Value存储库,它的设计目标是提供简单、快速、有序且可持久化的数据存储解决方案。这个库适用于需要高效、可靠的...
在iOS开发中,数据持久化是一项重要的技术,它允许应用程序在用户关闭或设备重启后仍然保存和恢复数据。本教程将深入探讨如何使用Keychain这一安全的持久化存储方法来保存密码和其他敏感信息。Keychain是苹果提供的...
在iOS开发中,数据持久性存储是至关重要的,它允许应用程序在用户关闭或重新启动应用后仍然能够保留数据。本文将深入探讨iOS中的属性列表(Property List)存储方式,这是一种简单且常用的数据保存机制。 属性列表...
"ClusterHQ & DevOps.com Container Market Adoption 2016"的数据显示,持久化存储是容器部署中最难克服的挑战之一。SmartX的方案通过其SMTX OS,使Docker和Kubernetes(K8s)能够在虚拟机上运行,并直接对接SMTX OS...
而"nacos持久化数据库"指的是Nacos如何将服务数据和配置信息存储到数据库中,以确保在系统重启或故障后能够恢复这些关键数据。在Nacos中,默认情况下使用的是内存存储,但为了数据可靠性,通常会配置数据持久化到...
根据ClusterHQ & DevOps.com的调查,企业在部署容器时面临的最大挑战是持久化存储、网络和安全性问题。 SmartX的解决方案旨在克服这些挑战,通过提供带有持久化存储的超融合架构,使得数据能够在容器间持久保存。其...
在生产环境中,为了保证消息的可靠性,通常会使用持久化存储来保存消息,即使在服务重启后也能恢复数据。本主题主要探讨如何将ActiveMQ配置为使用MySQL 8作为其持久化存储方式,以及在这个过程中所需的Jar包。 1. *...
ASP仿J2EE持久层是针对ASP开发的一种模拟Java J2EE平台中持久层技术的实现。在J2EE环境中,持久层主要负责数据库的交互,包括数据的存取、对象关系映射(ORM)以及事务管理等。ASP,虽然在功能上不及J2EE强大,但...
persistent, Haskell的持久化接口允许多种存储方法 了解更多: http://yesodweb.com/book/persistent Haskell数据存储数据存储通常被称为"orm"数据存储。 虽然'o'传统上是指对象,但概念可以概括为:avoidance of b
在iOS开发中,数据持久化是一项重要的任务,它允许应用程序保存和恢复数据,即使应用关闭或设备重启。这个名为“ios-一行代码持久化网络数据.zip”的资源提供了一个简单而高效的解决方案,通过GitHub项目...
数据持久化是指将程序中的数据以某种形式存储于持久性存储介质中(如硬盘或数据库等)。这种操作使得即使应用程序关闭后重新启动,先前存储的数据依然可以被访问。例如,在用户管理系统中,当管理员添加了一个新用户...
在本文中,我们将深入探讨如何在Spring Boot 2.3版本中集成Quartz定时任务,并实现其持久化到数据库,以便支持集群环境。这个过程的关键在于配置Quartz Scheduler,设置数据库连接,以及确保任务在多节点环境中能够...
为了实现持久化,OSWorkflow提供了一个核心接口`com.opensymphony.workflow.spi.WorkflowStore`,该接口定义了一系列方法来管理持久化操作,如存储、检索、更新工作流实例的状态等。 #### 4. 通过 ibatis 实现 ...
将 Sentinel-Dashboard 的配置持久化到 Nacos,意味着所有的流控规则、降级策略等都可以存储在 Nacos 上,这样不仅方便了配置的管理,还能实现实时更新和多环境共享。 Sentinel-Dashboard 与 Nacos 集成的过程中,...
你可以通过修改`activemq.xml`配置文件来设置持久化存储,比如将消息存储到MySQL数据库。在配置中指定数据源,如下所示: ```xml ${activemq.data} <driverClassName>...
在Java编程领域,持久层是应用系统中负责数据存储与检索的部分,它的主要任务是将对象的状态保存到数据库中,并能从数据库中恢复这些状态。本文将深入探讨如何利用反射机制来实现一个简单的持久层工具类,以供学习和...
数据持久化通常通过关系数据库来实现,但也可能涉及其他持久存储方式。 1. Java持久化技术 在Java世界里,数据持久化是企业级应用开发的关键技术。JPA出现前,Java社区尝试了多种解决方案,如: 1.1 序列化...