代码改变世界

com-复合文档存储及持久化

2011-07-19 19:39  Clingingboy  阅读(1691)  评论(0编辑  收藏  举报

 

参考:http://www.cnblogs.com/del/archive/2008/07/27/1252343.html

一.复合文档相关函数

1.StgCreateDocfile

The StgCreateDocfile function creates a new compound file storage object using the COM-provided compound file implementation for the IStorage interface.

const WCHAR fName[]=L"E:\\test.stg";
IStorage *stg;
StgCreateDocfile(fName, mode, 0, &stg);

2.StgIsStorageFile

const WCHAR fName[]=L"E:\\test.stg";
HRESULT hr= StgIsStorageFile(fName);

3.StgOpenStorage

The StgOpenStorage function opens an existing root storage object in the file system. Use this function to open compound files. Do not use it to open directories, files, or summary catalogs. Nested storage objects can only be opened using their parent IStorage::OpenStorage method.

const WCHAR fName[]=L"E:\\test.stg";
IStorage *stg;
if (StgOpenStorage(fName, NULL, mode, NULL, 0, &stg) != S_OK)
    return false;

二.在内存中创建复合文档

除了本地磁盘空间外,也可以是内存空间

  1. CreateILockBytesOnHGlobal
  2. GetHGlobalFromILockBytes
  3. CreateStreamOnHGlobal
  4. GetHGlobalFromStream
  5. StgCreateDocfileOnILockBytes
  6. StgOpenStorageOnILockBytes
  7. StgIsStorageILockBytes

2.1创建一个ILockBytes

  HGLOBAL    hMem = ::GlobalAlloc(GMEM_MOVEABLE,1024);
  CComPtr<ILockBytes> spLockBytes;
  HRESULT hr = ::CreateILockBytesOnHGlobal(hMem,FALSE,&spLockBytes);
  HGLOBAL    hMem2;
  GetHGlobalFromILockBytes(spLockBytes,&hMem2);
  //hMem==hMem2;

2.2根据ILockBytes创建复合文档

IStorage *stg;
StgCreateDocfileOnILockBytes(spLockBytes,STGM_SHARE_EXCLUSIVE | STGM_CREATE | STGM_READWRITE ,0,&stg);
hr =StgIsStorageILockBytes(spLockBytes);

2.3根据ILockBytes打开复合文档

IStorage *stg2;
StgOpenStorageOnILockBytes(spLockBytes,NULL,STGM_SHARE_EXCLUSIVE | STGM_READWRITE,NULL,0,&stg2);

三.IStorage && IStream

The IStorage interface supports the creation and management of structured storage objects

IStorage : public IUnknown
{
public:
    virtual HRESULT STDMETHODCALLTYPE CreateStream( 
        /* [string][in] */ __RPC__in_string const OLECHAR *pwcsName,
        /* [in] */ DWORD grfMode,
        /* [in] */ DWORD reserved1,
        /* [in] */ DWORD reserved2,
        /* [out] */ __RPC__deref_out_opt IStream **ppstm) = 0;
    
    virtual /* [local] */ HRESULT STDMETHODCALLTYPE OpenStream( 
        /* [string][in] */ const OLECHAR *pwcsName,
        /* [unique][in] */ void *reserved1,
        /* [in] */ DWORD grfMode,
        /* [in] */ DWORD reserved2,
        /* [out] */ IStream **ppstm) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE CreateStorage( 
        /* [string][in] */ __RPC__in_string const OLECHAR *pwcsName,
        /* [in] */ DWORD grfMode,
        /* [in] */ DWORD reserved1,
        /* [in] */ DWORD reserved2,
        /* [out] */ __RPC__deref_out_opt IStorage **ppstg) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE OpenStorage( 
        /* [string][unique][in] */ __RPC__in_opt_string const OLECHAR *pwcsName,
        /* [unique][in] */ __RPC__in_opt IStorage *pstgPriority,
        /* [in] */ DWORD grfMode,
        /* [unique][in] */ __RPC__deref_opt_in_opt SNB snbExclude,
        /* [in] */ DWORD reserved,
        /* [out] */ __RPC__deref_out_opt IStorage **ppstg) = 0;
    
    virtual /* [local] */ HRESULT STDMETHODCALLTYPE CopyTo( 
        /* [in] */ DWORD ciidExclude,
        /* [size_is][unique][in] */ const IID *rgiidExclude,
        /* [annotation][unique][in] */ 
        __RPC__in_opt  SNB snbExclude,
        /* [unique][in] */ IStorage *pstgDest) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE MoveElementTo( 
        /* [string][in] */ __RPC__in_string const OLECHAR *pwcsName,
        /* [unique][in] */ __RPC__in_opt IStorage *pstgDest,
        /* [string][in] */ __RPC__in_string const OLECHAR *pwcsNewName,
        /* [in] */ DWORD grfFlags) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE Commit( 
        /* [in] */ DWORD grfCommitFlags) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE Revert( void) = 0;
    
    virtual /* [local] */ HRESULT STDMETHODCALLTYPE EnumElements( 
        /* [in] */ DWORD reserved1,
        /* [size_is][unique][in] */ void *reserved2,
        /* [in] */ DWORD reserved3,
        /* [out] */ IEnumSTATSTG **ppenum) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE DestroyElement( 
        /* [string][in] */ __RPC__in_string const OLECHAR *pwcsName) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE RenameElement( 
        /* [string][in] */ __RPC__in_string const OLECHAR *pwcsOldName,
        /* [string][in] */ __RPC__in_string const OLECHAR *pwcsNewName) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE SetElementTimes( 
        /* [string][unique][in] */ __RPC__in_opt_string const OLECHAR *pwcsName,
        /* [unique][in] */ __RPC__in_opt const FILETIME *pctime,
        /* [unique][in] */ __RPC__in_opt const FILETIME *patime,
        /* [unique][in] */ __RPC__in_opt const FILETIME *pmtime) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE SetClass( 
        /* [in] */ __RPC__in REFCLSID clsid) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE SetStateBits( 
        /* [in] */ DWORD grfStateBits,
        /* [in] */ DWORD grfMask) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE Stat( 
        /* [out] */ __RPC__out STATSTG *pstatstg,
        /* [in] */ DWORD grfStatFlag) = 0;
    
};

其使用与c#中的storage是一个概念

IStream

MIDL_INTERFACE("0000000c-0000-0000-C000-000000000046")
IStream : public ISequentialStream
{
public:
    virtual /* [local] */ HRESULT STDMETHODCALLTYPE Seek( 
        /* [in] */ LARGE_INTEGER dlibMove,
        /* [in] */ DWORD dwOrigin,
        /* [annotation] */ 
        __out_opt  ULARGE_INTEGER *plibNewPosition) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE SetSize( 
        /* [in] */ ULARGE_INTEGER libNewSize) = 0;
    
    virtual /* [local] */ HRESULT STDMETHODCALLTYPE CopyTo( 
        /* [unique][in] */ IStream *pstm,
        /* [in] */ ULARGE_INTEGER cb,
        /* [annotation] */ 
        __out_opt  ULARGE_INTEGER *pcbRead,
        /* [annotation] */ 
        __out_opt  ULARGE_INTEGER *pcbWritten) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE Commit( 
        /* [in] */ DWORD grfCommitFlags) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE Revert( void) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE LockRegion( 
        /* [in] */ ULARGE_INTEGER libOffset,
        /* [in] */ ULARGE_INTEGER cb,
        /* [in] */ DWORD dwLockType) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE UnlockRegion( 
        /* [in] */ ULARGE_INTEGER libOffset,
        /* [in] */ ULARGE_INTEGER cb,
        /* [in] */ DWORD dwLockType) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE Stat( 
        /* [out] */ __RPC__out STATSTG *pstatstg,
        /* [in] */ DWORD grfStatFlag) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE Clone( 
        /* [out] */ __RPC__deref_out_opt IStream **ppstm) = 0;
    
};

四.读写CLSID

  1. WriteClassStg  WriteClassStg function stores the specified class identifier (CLSID) in a storage object.
  2. WriteClassStm The WriteClassStm function stores the specified CLSID in the stream.
  3. ReadClassStg  The ReadClassStg function reads the CLSID previously written to a storage object with the WriteClassStg function.
  4. ReadClassStm The ReadClassStm function reads the CLSID previously written to a stream object with the WriteClassStm function.
  5. WriteFmtUserTypeStg  The WriteFmtUserTypeStg function writes a clipboard format and user type to the storage object.
  6. ReadFmtUserTypeStg  The ReadFmtUserTypeStg function returns the clipboard format and user type previously saved with the WriteFmtUserTypeStg function.

WINOLEAPI WriteClassStg(
  __in  IStorage *
            pStg,
  __in  REFCLSID
            rclsid
);
         

WINOLEAPI ReadClassStg(
  __in   IStorage *
            pStg,
  __out  CLSID *
            pclsid
);

五.持久化

持久化是对上面复合文档的一些封装

IPersistStorage : public IPersist
{
public:
    virtual HRESULT STDMETHODCALLTYPE IsDirty( void) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE InitNew( 
        /* [unique][in] */ __RPC__in_opt IStorage *pStg) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE Load( 
        /* [unique][in] */ __RPC__in_opt IStorage *pStg) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE Save( 
        /* [unique][in] */ __RPC__in_opt IStorage *pStgSave,
        /* [in] */ BOOL fSameAsLoad) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE SaveCompleted( 
        /* [unique][in] */ __RPC__in_opt IStorage *pStgNew) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE HandsOffStorage( void) = 0;
    
};

我比较困惑的是com只提供接口,却不提供实现,幸好ATL提供了默认实现

如何在不是ActiveX控件的情况下实现持久化?

1.为类添加m_bRequiresSave变量

2.继承IPersistStreamInitImpl和IPersistStorageImpl接口

3.添加映射接口表

4.添加一个空的属性映射表

下面为简化版本

class ATL_NO_VTABLE CDuckDoer :
    public IPersistStreamInitImpl<CDuckDoer>,
    public IPersistStorageImpl<CDuckDoer> {

public:
    CDuckDoer()
    {
    }
    bool m_bRequiresSave;

    ~CDuckDoer()
    {
    }


public:
   

BEGIN_COM_MAP(CDuckDoer)
    COM_INTERFACE_ENTRY(IPersistStreamInit)
    COM_INTERFACE_ENTRY(IPersistStorage)

END_COM_MAP()

BEGIN_PROP_MAP(CDuckDoer)

END_PROP_MAP()

    // IDuckDoer
};
OBJECT_ENTRY_AUTO(CLSID_DuckDoer, CDuckDoer)

客户端的调用

IPersistStorage* pPersistStorage=NULL;
hr = pUnk->QueryInterface(IID_IPersistStorage, (void**)&pPersistStorage);
CLSID id;
pPersistStorage->GetClassID(&id);
const WCHAR fName[]=L"E:\\test.stg";
IStorage *stg=NULL;
StgOpenStorage(fName, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
hr=pPersistStorage->InitNew(stg);
hr=pPersistStorage->IsDirty();
hr=pPersistStorage->Save(stg,true);
hr=pPersistStorage->Load(stg);

个人认为实用价值不大,居然要自己传入IPersistStorage对象,并为带来任何的方便,应该内部默认实现一个
注意点:内部Stream的字段名为Contents,所以在Load之前调用Save创建一个Stream(奇怪的是这个Save方法总是创建新的Stream…)