`
yangyou230
  • 浏览: 1652589 次
文章分类
社区版块
存档分类

COM持久存储

阅读更多
组件实现了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接口将数据抽象为二进制的字节流。我们可以在自己的对象中实现IStream接口,COM提供了两种形式的IStram接口的实现,一种是以内存形式,一种是通过复合文件。下面分别举例:
使用内存中预定义的IStream接口形式----
#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类来供我们简化实现过程。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics