OLE文档接口(1)----粗略实现IPersistStorage
允许一个ActiveX控件嵌入到容器中,这项技术已经很长时间了。OLE文档标准(当时称为复合文档,Compound Documents)于1991年创建,其中包含了OLE的主要内容。实际上OLE是Object Linking and Embedding(对象链接与嵌入)的首字母缩写。在ActiveX控件出现以后,OLE文档标准也得到了增强,它允许文档服务器向外公开programmatic功能。
现在,如果你所开发的控件需要提供一个可视化界面,并需要通过鼠标点击或类似的方式与用户实现交互,则它必须支持基本的OLE文档接口:IOleObject、IOleInPlaceObject、IOleInPlaceActiveObject、IDataObject以及IViewObject2
接口
说明
IOleObject
IOleObject提供了OLE文档构架的基本内容。通过该接口,容器和组件相互协商被嵌入对象的大小
IOleInPlaceObject
一个控件必须实现IOleInPlaceObject来支持在容器中实现在位激活和失效。该接口还提供了一个方法,用于通知控件,他的大小已经改变或已经在容器中删除
IOleInPlace
ActiveObject
一个控件必须实现IOleInPlaceActiveObject,以便对在控件中使用和转换加速键提供支持。IOleInPlaceActiveObject的大部分方法对于ActiveX控件是不需要的
IOleControl
IOleControl是为支持ActiveX控件而加入的一个新的接口。它所提供的方法使得与控件容器的交互得到了加强。IOleControl的主要功能是允许控件和容器在处理键盘输入时能够很好的协调工作
IDataObject
控件实现该接口主要用于为容器提供图形绘制功能。IDataObject还提供了一个属性,用于对它的属性持续性进行设置
IViewObject2
当一个控件提供一个可视的外观时需要提供IViewObject2。该接口为容器提供各种方法,允许容器通过这些方法请求控件在容器的客户区重绘控件本身
IPersistFile
IPersistFile接口比较简单,客户程序调用Load函数使永久对象装载状态数据,执行初始化操作,永久对象可以使文件保持打开状态。在Save函数中,如果参数lpszFileName为NULL,那么永久对象把状态数据写到文件中,同时清除修改标记并关闭文件;如果lpszFileName不为NULL,那么根据参数fRemember的不同值,或者执行Save As操作,或者执行Save Copy As,前者情况下也要清除修改标记并关闭文件。客户程序调用SaveCompleted函数,通知永久对象保存操作已经完成,对象可以再打开文件。GetCurFile函数返回永久对象所使用的文件名字
IPersistStorage
IPersistStorage接口并不复杂,它不仅可实现在事物方式下用存储对象保存永久状态数据,而且也支持零内存保存特性。客户程序通过SaveCompleted函数通知永久对象,它已经完成了所有的保存操作,根据参数的值,客户控制永久对象进入相应的状态。客户程序利用HandsOffStorage函数指示永久对象释放存储对象的所有接口指针,包括所有的子对象,以后由客户程序完全控制存储对象
来个例子吧,仅仅是实现了一个IPersistStorage接口:
1、我打算从d://test.bmp得到bmp的数据,然后StgCreateStorageEx,通过IPersistStorage的Save函数保存到Zeng.stg中(createStream了一个流“ZengStream”)
2、通过读取d://a.stg然后在Load函数中OpenStream流“ZengStream”,从里面得到刚才保存的数据,再写到本地文件1.bmp中
// CImpIPersist.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include "windows.h"#include "fstream"#include "iostream"using namespace std;#include <initguid.h>#include "assert.h"DEFINE_GUID(CLSID_CImpIPersistStorage, 0x00021108, 0, 0, 0xB0,0,0,0,0,0,0,0x47);class ImpIPersistStorage : public IPersistStorage{protected:ULONGrefence_count_;LPSTORAGEpIStorage_;LPSTREAMpIStream_;public:ImpIPersistStorage();~ImpIPersistStorage();STDMETHODIMP QueryInterface(/* [in] */ REFIID riid,/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR *__RPC_FAR *ppvObject);STDMETHODIMP_(ULONG) AddRef(void);STDMETHODIMP_(ULONG) Release(void);STDMETHODIMP GetClassID(LPCLSID);STDMETHODIMP IsDirty(void);STDMETHODIMP InitNew(LPSTORAGE);STDMETHODIMP Load(LPSTORAGE);STDMETHODIMP Save(LPSTORAGE, BOOL);STDMETHODIMP SaveCompleted(LPSTORAGE);STDMETHODIMP HandsOffStorage(void);};ImpIPersistStorage::ImpIPersistStorage(){refence_count_ = 0;pIStorage_= NULL;pIStream_= NULL;}ImpIPersistStorage::~ImpIPersistStorage(){if (0 == refence_count_){//delete this;}}//////////////////////////////////////////////////////////////////////////// IUnknown//////////////////////////////////////////////////////////////////////////STDMETHODIMP ImpIPersistStorage::QueryInterface(/* [in] */ REFIID riid, /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR *__RPC_FAR *ppvObject){*ppvObject = NULL;if (IsEqualIID(riid, IID_IUnknown))*ppvObject=(LPVOID)this;if (IsEqualIID(riid, IID_IPersist)|| IsEqualIID(riid, IID_IPersistStorage))*ppvObject=(LPVOID)this;//AddRef any interface we'll return.if (NULL!=*ppvObject){((LPUNKNOWN)*ppvObject)->AddRef();return NOERROR;}return ResultFromScode(E_NOINTERFACE);}STDMETHODIMP_(ULONG) ImpIPersistStorage::AddRef(void){++refence_count_;return (ULONG)refence_count_;}STDMETHODIMP_(ULONG) ImpIPersistStorage::Release(void){--refence_count_;if (0 == refence_count_){delete this;return 0;}return (ULONG)refence_count_;}//////////////////////////////////////////////////////////////////////////// IPersistStorage//////////////////////////////////////////////////////////////////////////STDMETHODIMP ImpIPersistStorage::GetClassID(LPCLSID pClsID){*pClsID = CLSID_CImpIPersistStorage;return NOERROR;}STDMETHODIMP ImpIPersistStorage::IsDirty(void){return ResultFromScode(S_OK);}STDMETHODIMP ImpIPersistStorage::InitNew(LPSTORAGE pIStorage){if (NULL != pIStorage_){return ResultFromScode(E_UNEXPECTED);}HRESULT hr = pIStorage->CreateStream(L"ZengStream", STGM_DIRECT | STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pIStream_);if (FAILED(hr)){return hr;}WriteClassStg(pIStorage, CLSID_CImpIPersistStorage);WriteFmtUserTypeStg(pIStorage, 0, 0);pIStorage->AddRef();pIStorage_ = pIStorage;return NOERROR;}STDMETHODIMP ImpIPersistStorage::Load(LPSTORAGE pIStorage){HRESULThr;ULONG cb = -1;ULONGfileLength = 0;LPSTREAMpIStream;ofstreamfout("d://1.bmp", ios::binary);if ( NULL != pIStorage_ )return ResultFromScode(E_UNEXPECTED);if ( NULL == pIStorage )return ResultFromScode( STG_E_INVALIDPOINTER );hr = pIStorage->OpenStream( L"ZengStream", 0, STGM_DIRECT| STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pIStream );if ( FAILED(hr) )return ResultFromScode( STG_E_READFAULT );// begin read the file length info from IStreamhr = pIStream->Read( (LPVOID)&fileLength, sizeof(ULONG), &cb );LARGE_INTEGER lInt;lInt.QuadPart = sizeof(ULONG);pIStream->Seek( lInt,STREAM_SEEK_SET, 0 );if ( FAILED(hr) || ( sizeof(ULONG) != cb ) ){pIStream->Release();return ResultFromScode( STG_E_READFAULT ); }cout << "read the file length is :" << fileLength << endl;void *readFileData = new char[ fileLength ];hr = pIStream->Read( readFileData, fileLength, &cb );if ( FAILED(hr) || ( fileLength != cb ) ){pIStream->Release();return ResultFromScode( STG_E_READFAULT ); }//已经读取到了bmp的数据fout.write( (char *)readFileData, fileLength );pIStream_ = pIStream;pIStorage->AddRef();pIStorage_ = pIStorage;fout.close();return NOERROR;}STDMETHODIMP ImpIPersistStorage::Save( LPSTORAGE pIStorage, BOOL fSameAsLoad ){HRESULThr;LPSTREAMpIStream;ULONGtotalWriteBytes = 0;if (NULL==pIStorage)return ResultFromScode(STG_E_INVALIDPOINTER);// fSameAsLoad is true, mean create a new streamif ( fSameAsLoad ){LARGE_INTEGERli;pIStream = pIStream_;LISet32( li, 0 );pIStream->Seek( li, STREAM_SEEK_SET, NULL );pIStream->AddRef();}else{// hr = pIStorage->CreateStream(L"zengraoli", STGM_DIRECT// | STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pIStream );hr = pIStorage->CreateStream(// 建立流L"ZengStream",// 流名称STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE,0,0,&pIStream );// 取得流接口指针if (FAILED(hr)){return hr;}WriteFmtUserTypeStg( pIStorage, 0, 0 );}if ( NULL == pIStream ){return ResultFromScode( STG_E_WRITEFAULT );}// read bitmap from local fileifstream fin("d://test.bmp", ios::binary);if (NULL == fin){printf("the file is open fail...");return 0;}fin.seekg(0, ios::end);ULONG fileLength = fin.tellg();fin.seekg(0, 0);int writeLength = fileLength + sizeof(ULONG);void *fileData = new char[writeLength + 1];*((ULONG*)fileData) = fileLength;// write the bitmap date length to fileDatewhile (!fin.eof()){fin.read((char *)fileData + sizeof(ULONG), fileLength);}// write fileData to pIStreamhr = pIStream->Write(fileData, writeLength, &totalWriteBytes);pIStream->Release();if (FAILED(hr) || totalWriteBytes != writeLength){return ResultFromScode(STG_E_WRITEFAULT);}return NOERROR;}STDMETHODIMP ImpIPersistStorage::SaveCompleted(LPSTORAGE pIStorage){HRESULT hr;LPSTREAM pIStream;if (NULL != pIStorage){hr = pIStorage->OpenStream( L"ZengStream", 0, STGM_DIRECT| STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pIStream );if (FAILED(hr)){return hr;}if (NULL != pIStream_){pIStream_->Release();}pIStream_ = pIStream;if (NULL != pIStorage_){pIStorage_->Release();}pIStorage_ = pIStorage;pIStorage_->AddRef();}return NOERROR;}STDMETHODIMP ImpIPersistStorage::HandsOffStorage(void){//Release held pointersif (NULL != pIStream_){pIStream_->Release();pIStream_ = NULL;}if (NULL != pIStorage_){pIStorage_->Release();pIStorage_ = NULL;}return NOERROR;}int _tmain(int argc, _TCHAR* argv[]){ImpIPersistStorage test;HRESULT hr;IStorage *pStg = NULL;// 根存储指针IStorage *pSub = NULL;// 子存储接口指针IStream *pStm = NULL;// 流接口指针::CoInitialize(NULL);// COM 初始化//////////////////////////////////////////////////////////////////////////// test the Save method//////////////////////////////////////////////////////////////////////////// hr = ::StgCreateStorageEx(L"d://Zeng.stg", // STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, STGFMT_STORAGE,// 0, NULL, NULL, IID_IStorage, (void **)&pStg );// // hr = pStg->CreateStorage(// 建立子存储// L"ZengStorage",// 子存储名称// STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE,// 0,0,// &pSub );// 取得子存储接口指针// // assert( SUCCEEDED(hr) );// // test.InitNew(pSub);// test.Save(pSub, false);// test.SaveCompleted(pStg);////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// test the Load method//////////////////////////////////////////////////////////////////////////hr = ::StgOpenStorage(L"d://Zeng.stg", NULL,STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE | STGFMT_STORAGE,0, 0, &pStg);assert( SUCCEEDED(hr) );hr = pStg->OpenStorage( L"ZengStorage", 0, STGM_READ | STGM_SHARE_EXCLUSIVE | STGFMT_STORAGE,0, 0, &pSub );// hr = pSub->OpenStream(L"ZengStream", 0,// STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStm);assert( SUCCEEDED(hr) );test.Load(pSub);//////////////////////////////////////////////////////////////////////////if( pStm )pStm->Release();// 释放流指针if( pSub )pSub->Release();// 释放子存储指针if( pStg )pStg->Release();// 释放根存储指针::CoUninitialize();// COM 释放return 0;}
测试完之后,在我的D盘出现1.bmp和Zeng