组件实现了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类来供我们简化实现过程。
分享到:
相关推荐
Android下数据持久化存储在自带内存与存储卡,具体可以参见博客:http://www.cnblogs.com/plokmju/p/Android_Storage.html
persistent, Haskell的持久化接口允许多种存储方法 了解更多: http://yesodweb.com/book/persistent Haskell数据存储数据存储通常被称为"orm"数据存储。 虽然'o'传统上是指对象,但概念可以概括为:avoidance of b
NULL 博文链接:https://ainn2006.iteye.com/blog/1543466
NULL 博文链接:https://374016526.iteye.com/blog/1156908
NULL 博文链接:https://dreamzhong.iteye.com/blog/1727761
StateStorage解决了常见问题,即持久存储对象的状态。 它允许在特定时刻保存状态(例如,在流程退出时),并在以后恢复状态(例如,在流程启动时)。 使用该模块可以跨平台使用,不要重复自己,而不必担心不用担心...
对于以数据为中心的程序来说,它们往往只在数据库中使用存储过程来实现商业逻辑,NHibernate可能不是最好的解决方案;对于那些在基于.NET的中间层应用中,它们实现面向对象的业务模型和商业逻辑的应用,NHibernate是最...
Redux持久加密的异步存储Redux持久存储引擎可在异步存储上提供加密层该项目提供什么该项目通过AsyncStorage提供了一个AES加密层(使用存储在密钥链/密钥库中的随机生成的安全密钥)用于本机项目。要在您的项目中安装...
使用几个小例子分别实现 归档NSKeyedArchiver、NSUserDefaults、plist文件数据存储,简单直观,代码地址https://github.com/fancyLi/data-store。
mail: lijinxing@gmail.com, shenzhe163@gmail.com 安装 redis-storage https://github.com/qiye/redis-storage 获取源码 make init make MALLOC=tcmalloc_minimal 这一步需要root权限 make install ...
d :newspaper: 清醒可观的API github上的inativanavegação。 :rocket: cn虫 :laptop: 科莫贝沙尔或普罗耶托 git clone https://github.com/felipeesc/nodejs-api cd nodejs-api npm install npm start
OPLib是一个基于ADO2.8和COM+技术的for VB6的对象持久层(Persistence Layer)框架,它实现了数据库和中间层的Broker功能,提供OR-Mapping,将关系数据库对象映射到Class,使中间层对数据库“无知”(Law of Demeter)。...
快递演示具有持久存储功能的网页的简单演示,使用: :结构 :样式 :功能 :DOM 操作 :版本控制 : 托管 :一切 :数据库 :模板 : HTML 表单解析:框架测试:测试:测试观看此项目。对这个项目的贡献这个项目是我...
NULL 博文链接:https://snv.iteye.com/blog/1901784
持久数据存储的抽象接口。 从存储库中尝试 git clone https://github.com/Wandalen/wPersistent cd wPersistent npm install node sample/trivial/Sample.s 添加到您的项目 npm add 'wpersistent@alpha'
用于发送日志记录数据以持久存储的API。 当前,持久性存储是MongoDB。 ###端点 GET / api-报告有关API的基本详细信息 GET / api / v1 POST / api / v1 / imports?type = [user]&exists = [1]&source = [生态位...
通过添加“粘性”和“持久”后端消息存储的框架。 这也支持在计算机到用户进程中向其他用户发送持久消息的概念。 储物柜 粘性储存 “粘性”消息是一条消息,用户必须单击关闭按钮才能在该会话中删除它。 对于某些...