乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      COM——復(fù)合文檔與持續(xù)化--YXM的程序人生

       liujian6916 2007-01-04

                                        

      一、復(fù)合文件的特點(diǎn)
       
      1. 復(fù)合文件的內(nèi)部是使用指針構(gòu)造的一棵樹進(jìn)行管理的。編寫程序的時候要注意,由于使用的是單向指針,因此當(dāng)做定位操作的時候,向后定位比向前定位要快;
      2. 復(fù)合文件中的“流對象”,是真正保存數(shù)據(jù)的空間。它的存儲單位為512字節(jié)。也就是說,即使你在流中只保存了一個字節(jié)的數(shù)據(jù),它也要占據(jù)512字節(jié)的文件空間。
      3. 不同的進(jìn)程,或同一個進(jìn)程的不同線程可以同時訪問一個復(fù)合文件的不同部分而互不干擾;
      4. 大家都有這樣的體會,當(dāng)需要往一個文件中插入一個字節(jié)的話,需要對整個文件進(jìn)行操作,非常煩瑣并且效率低下。而復(fù)合文件則提供了非常方便的“增量訪問”能力;
      5. 當(dāng)頻繁地刪除文件,復(fù)制文件后,磁盤空間會變的很零碎,需要使用磁盤整理工具進(jìn)行重新整合。和磁盤管理非常相似,復(fù)合文件也會產(chǎn)生這個問題,在適當(dāng)?shù)臅r候也需要整理,但比較簡單,只要調(diào)用一個函數(shù)就可以完成了。
       
      示例一:建立一個復(fù)合文件,并在其下建立一個子存儲,在該子存儲中再建立一個流,寫入數(shù)據(jù)。
      	void SampleCreateDoc()
                  {
                  ::CoInitialize(NULL);	// COM 初始化
                  // 如果是MFC程序,可以使用AfxOleInit()替代
                  HRESULT hr;		// 函數(shù)執(zhí)行返回值
                  IStorage *pStg = NULL;	// 根存儲接口指針
                  IStorage *pSub = NULL;	// 子存儲接口指針
                  IStream *pStm = NULL;	// 流接口指針
                  hr = ::StgCreateDocfile(	// 建立復(fù)合文件
                  L"c:\\a.stg",	// 文件名稱
                  STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE,	// 打開方式
                  0,		// 保留參數(shù)
                  &pStg);		// 取得根存儲接口指針
                  ASSERT( SUCCEEDED(hr) );	// 為了突出重點(diǎn),簡化程序結(jié)構(gòu),所以使用了斷言。
                  // 在實(shí)際的程序中則要使用條件判斷和異常處理
                  hr = pStg->CreateStorage(	// 建立子存儲
                  L"SubStg",	// 子存儲名稱
                  STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE,
                  0,0,
                  &pSub);		// 取得子存儲接口指針
                  ASSERT( SUCCEEDED(hr) );
                  hr = pSub->CreateStream(	// 建立流
                  L"Stm",		// 流名稱
                  STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE,
                  0,0,
                  &pStm);		// 取得流接口指針
                  ASSERT( SUCCEEDED(hr) );
                  hr = pStm->Write(		// 向流中寫入數(shù)據(jù)
                  "Hello",		// 數(shù)據(jù)地址
                  5,		// 字節(jié)長度(注意,沒有寫入字符串結(jié)尾的\0)
                  NULL);		// 不需要得到實(shí)際寫入的字節(jié)長度
                  ASSERT( SUCCEEDED(hr) );
                  if( pStm )	pStm->Release();// 釋放流指針
                  if( pSub )	pSub->Release();// 釋放子存儲指針
                  if( pStg )	pStg->Release();// 釋放根存儲指針
                  ::CoUninitialize()		// COM 釋放
                  // 如果使用 AfxOleInit(),則不調(diào)用該函數(shù)
                  }	
       
      示例二:打開一個復(fù)合文件,枚舉其根存儲下的所有對象。
      	#include 	// ANSI、MBCS、UNICODE 轉(zhuǎn)換
                  void SampleEnum()
                  {	// 假設(shè)你已經(jīng)做過 COM 初始化了
                  LPCTSTR lpFileName = _T( "c:\\a.stg" );
                  HRESULT hr;
                  IStorage *pStg = NULL;
                  USES_CONVERSION;
                  LPCOLESTR lpwFileName = T2COLE( lpFileName );	// 轉(zhuǎn)換T類型為寬字符
                  hr = ::StgIsStorageFile( lpwFileName );	// 是復(fù)合文件嗎?
                  if( FAILED(hr) )	return;
                  hr = ::StgOpenStorage(			// 打開復(fù)合文件
                  lpwFileName,			// 文件名稱
                  NULL,
                  STGM_READ | STGM_SHARE_DENY_WRITE,
                  0,
                  0,
                  &pStg);				// 得到根存儲接口指針
                  IEnumSTATSTG *pEnum=NULL;	// 枚舉器
                  hr = pStg->EnumElements( 0, NULL, 0, &pEnum );
                  ASSERT( SUCCEEDED(hr) );
                  STATSTG statstg;
                  while( NOERROR == pEnum->Next( 1, &statstg, NULL) )
                  {
                  // statstg.type 保存著對象類型 STGTY_STREAM 或 STGTY_STORAGE
                  // statstg.pwcsName 保存著對象名稱
                  // ...... 還有時間,長度等很多信息。請查看 MSDN
                  ::CoTaskMemFree( statstg.pwcsName );	// 釋放名稱所使用的內(nèi)存
                  }
                  if( pEnum )	pEnum->Release();
                  if( pStg )	pStg->Release();
                  }
                  
       
      二、持續(xù)性原理
          持續(xù)性,也叫永久性。組件方提供 IPersistXXX 接口,調(diào)用者(容器)提供存儲介質(zhì),比如文件啦、內(nèi)存啦、注冊表啦、流啦、文本啦......啦啦拉。需要保存的時候,調(diào)用者通過 IPersistXXX::Save() 接口函數(shù)讓組件去自己存儲屬性信息,而調(diào)用者根本不用關(guān)心存儲格式和存儲內(nèi)容;需要還原狀態(tài)的時候,調(diào)用者打開存儲介質(zhì),然后同樣調(diào)用 IPersistXXX::Load() 接口函數(shù)讓組件自己去讀取屬性信息并完成初始化的設(shè)置。
       
      持續(xù)性接口組件的實(shí)現(xiàn)
      1、建立一個 ATL 工程項(xiàng)目。
      2、增加 ATL 組件類,vc.net 使用者注意不要選擇“屬性化編程”方式,其它的設(shè)置全部使用默認(rèn)方法。當(dāng)然你愿意適當(dāng)?shù)馗淖冞x擇也無所謂。
      3、設(shè)計完成你的組件功能。
         示例程序中,實(shí)現(xiàn)了一個接口函數(shù) GetNext() 負(fù)責(zé)計算下一個素數(shù)。
      4、添加IPersistStreamInit 接口。
       
      	class ATL_NO_VTABLE Cxxx :
                  public CComObjectRootEx<...>,
                  public CComCoClass<...>,
                  ......
                  public IPersistStreamInit	// 手工添加持續(xù)性接口
                  {
                  ......
                  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 接口函數(shù)。
      手工在 h 頭文件中增加函數(shù)聲明:
       
      	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ù)實(shí)現(xiàn):
       
      	// IPersist
                  STDMETHODIMP Cxxx::GetClassID(/*[out]*/CLSID * pClassID)
                  {
                  *pClassID = GetObjectCLSID();
                  return S_OK;
                  }
                  // IPersistStream
                  STDMETHODIMP Cxxx::IsDirty(void)
                  {
                  if( 數(shù)據(jù)已經(jīng)改變,需要保存 )	return S_OK;
                  else			return S_FALSE;
                  }
                  STDMETHODIMP Cxxx::Load(/*[in]*/IStream *pStm)
                  {
                  return pStm->Read( 讀到哪里, 讀多長字節(jié), NULL);
                  }
                  STDMETHODIMP Cxxx::Save(/*[in]*/IStream *pStm,/*[in]*/BOOL fClearDirty)
                  {
                  if( fClearDirty )	清除內(nèi)部表示數(shù)據(jù)變化的變量;
                  return pStm->Write( 需要保存的數(shù)據(jù)指針, 寫多長字節(jié), NULL );
                  }
                  STDMETHODIMP Cxxx::GetSizeMax(/*[out]*/ULARGE_INTEGER *pcbSize)
                  {
                  pcbSize->LowPart = 需要保存數(shù)據(jù)長度的低位;
                  pcbSize->HighPart = 需要保存數(shù)據(jù)長度的高位;// 一般都是0,難道你的數(shù)據(jù)長度都超過了 4G?
                  return S_OK;
                  }
                  // IPersistStreamInit
                  STDMETHODIMP Cxxx::InitNew(void)
                  {
                  內(nèi)部屬性數(shù)據(jù)默認(rèn)初始化;
                  設(shè)置或清除內(nèi)部表示數(shù)據(jù)變化的變量;
                  return S_OK;
                  }
       
      示例代碼:http://xmyang./inc/PersistSample.rar

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多