COM持久存储

来源:互联网 发布:半球面车削编程 编辑:程序博客网 时间:2024/04/24 01:40
 
COM持久存储... 1
持久存储的一般顺序... 1
IStream接口应用... 1
使用内存中预定义的IStream接口形式----. 1
使用复文件形式----. 2
IPersistStreamInit接口... 2
 
持久存储的一般顺序
       组件实现了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;
}
 
使用复合文件形式----
       。。。
IPersistStreamInit接口
       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类来供我们简化实现过程。
 
原创粉丝点击