| 一、復合文件的特點(diǎn) |
|
| 示例一:建立一個(gè)復合文件,并在其下建立一個(gè)子存儲,在該子存儲中再建立一個(gè)流,寫(xiě)入數據。 |
void SampleCreateDoc() { ::CoInitialize(NULL); // COM 初始化 // 如果是MFC程序,可以使用AfxOleInit()替代 HRESULT hr; // 函數執行返回值 IStorage *pStg = NULL; // 根存儲接口指針 IStorage *pSub = NULL; // 子存儲接口指針 IStream *pStm = NULL; // 流接口指針 hr = ::StgCreateDocfile( // 建立復合文件 L"c:\\a.stg", // 文件名稱(chēng) STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, // 打開(kāi)方式 0, // 保留參數 &pStg); // 取得根存儲接口指針 ASSERT( SUCCEEDED(hr) ); // 為了突出重點(diǎn),簡(jiǎn)化程序結構,所以使用了斷言。 // 在實(shí)際的程序中則要使用條件判斷和異常處理 hr = pStg->CreateStorage( // 建立子存儲 L"SubStg", // 子存儲名稱(chēng) STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0,0, &pSub); // 取得子存儲接口指針 ASSERT( SUCCEEDED(hr) ); hr = pSub->CreateStream( // 建立流 L"Stm", // 流名稱(chēng) STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0,0, &pStm); // 取得流接口指針 ASSERT( SUCCEEDED(hr) ); hr = pStm->Write( // 向流中寫(xiě)入數據 "Hello", // 數據地址 5, // 字節長(cháng)度(注意,沒(méi)有寫(xiě)入字符串結尾的\0) NULL); // 不需要得到實(shí)際寫(xiě)入的字節長(cháng)度 ASSERT( SUCCEEDED(hr) ); if( pStm ) pStm->Release();// 釋放流指針 if( pSub ) pSub->Release();// 釋放子存儲指針 if( pStg ) pStg->Release();// 釋放根存儲指針 ::CoUninitialize() // COM 釋放 // 如果使用 AfxOleInit(),則不調用該函數 } |
| 示例二:打開(kāi)一個(gè)復合文件,枚舉其根存儲下的所有對象。 |
#include |
| 二、持續性原理 |
| 持續性,也叫永久性。組件方提供 IPersistXXX 接口,調用者(容器)提供存儲介質(zhì),比如文件啦、內存啦、注冊表啦、流啦、文本啦......啦啦拉。需要保存的時(shí)候,調用者通過(guò) IPersistXXX::Save() 接口函數讓組件去自己存儲屬性信息,而調用者根本不用關(guān)心存儲格式和存儲內容;需要還原狀態(tài)的時(shí)候,調用者打開(kāi)存儲介質(zhì),然后同樣調用 IPersistXXX::Load() 接口函數讓組件自己去讀取屬性信息并完成初始化的設置。 |
| 持續性接口組件的實(shí)現 |
| 1、建立一個(gè) ATL 工程項目。 2、增加 ATL 組件類(lèi),vc.net 使用者注意不要選擇“屬性化編程”方式,其它的設置全部使用默認方法。當然你愿意適當地改變選擇也無(wú)所謂。 3、設計完成你的組件功能。 示例程序中,實(shí)現了一個(gè)接口函數 GetNext() 負責計算下一個(gè)素數。 4、添加IPersistStreamInit 接口。 |
class ATL_NO_VTABLE Cxxx : public CComObjectRootEx<...>, public CComCoClass<...>, ...... public IPersistStreamInit // 手工添加持續性接口 { ...... BEGIN_COM_MAP(Cxxx) ...... // 手工添加接口映射表入口 COM_INTERFACE_ENTRY(IPersistStreamInit) // 表示如果要取得 IPersistStream 指針,則返回 IPersistStreamInit 指針 COM_INTERFACE_ENTRY_IID(IID_IPersistStream, IPersistStreamInit) // 表示如果要取得 IPersist 指針,則返回 IPersistStremInit 指針 COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersistStreamInit) END_COM_MAP() |
| 5、完成 IPersistStreamInit 接口函數。 手工在 h 頭文件中增加函數聲明: |
public: // IPersist STDMETHOD(GetClassID)(/*[out]*/CLSID * pClassID); // IPersistStream STDMETHOD(IsDirty)(void); STDMETHOD(Load)(/*[in]*/IStream *pStm); STDMETHOD(Save)(/*[in]*/IStream *pStm,/*[in]*/BOOL fClearDirty); STDMETHOD(GetSizeMax)(/*[out]*/ULARGE_INTEGER *pcbSize); // IPersistStreamInit STDMETHOD(InitNew)(void); |
| 手工在 cpp 文件中增加函數實(shí)現: |
// IPersist STDMETHODIMP Cxxx::GetClassID(/*[out]*/CLSID * pClassID) { *pClassID = GetObjectCLSID(); return S_OK; } // IPersistStream STDMETHODIMP Cxxx::IsDirty(void) { if( 數據已經(jīng)改變,需要保存 ) return S_OK; else return S_FALSE; } STDMETHODIMP Cxxx::Load(/*[in]*/IStream *pStm) { return pStm->Read( 讀到哪里, 讀多長(cháng)字節, NULL); } STDMETHODIMP Cxxx::Save(/*[in]*/IStream *pStm,/*[in]*/BOOL fClearDirty) { if( fClearDirty ) 清除內部表示數據變化的變量; return pStm->Write( 需要保存的數據指針, 寫(xiě)多長(cháng)字節, NULL ); } STDMETHODIMP Cxxx::GetSizeMax(/*[out]*/ULARGE_INTEGER *pcbSize) { pcbSize->LowPart = 需要保存數據長(cháng)度的低位; pcbSize->HighPart = 需要保存數據長(cháng)度的高位;// 一般都是0,難道你的數據長(cháng)度都超過(guò)了 4G? return S_OK; } // IPersistStreamInit STDMETHODIMP Cxxx::InitNew(void) { 內部屬性數據默認初始化; 設置或清除內部表示數據變化的變量; return S_OK; } |
| 示例代碼:http://xmyang.bokee.com/inc/PersistSample.rar |
聯(lián)系客服