IPERSTOR.CPP
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:14k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /*
  2.  * IPERSTOR.CPP
  3.  * Cosmo Chapter 18
  4.  *
  5.  * Implementation of the IPersistStorage interface that we expose on
  6.  * the CFigure compound document object.  This ties into the
  7.  * functionality of CPolyline.
  8.  *
  9.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  10.  *
  11.  * Kraig Brockschmidt, Microsoft
  12.  * Internet  :  kraigb@microsoft.com
  13.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  14.  */
  15. #include "cosmo.h"
  16. /*
  17.  * CImpIPersistStorage:CImpIPersistStorage
  18.  * CImpIPersistStorage::~CImpIPersistStorage
  19.  *
  20.  * Constructor Parameters:
  21.  *  pObj            PCFigure associated with this object.
  22.  *  pUnkOuter       LPUNKNOWN of the controlling unknown.
  23.  */
  24. CImpIPersistStorage::CImpIPersistStorage(PCFigure pObj
  25.     , LPUNKNOWN pUnkOuter)
  26.     {
  27.     m_cRef=0;
  28.     m_pObj=pObj;
  29.     m_pUnkOuter=pUnkOuter;
  30.     m_psState=PSSTATE_UNINIT;
  31.     m_fConvert=FALSE;
  32.     return;
  33.     }
  34. CImpIPersistStorage::~CImpIPersistStorage(void)
  35.     {
  36.     return;
  37.     }
  38. /*
  39.  * CImpIPersistStorage::QueryInterface
  40.  * CImpIPersistStorage::AddRef
  41.  * CImpIPersistStorage::Release
  42.  */
  43. STDMETHODIMP CImpIPersistStorage::QueryInterface(REFIID riid
  44.     , PPVOID ppv)
  45.     {
  46.     return m_pUnkOuter->QueryInterface(riid, ppv);
  47.     }
  48. STDMETHODIMP_(ULONG) CImpIPersistStorage::AddRef(void)
  49.     {
  50.     ++m_cRef;
  51.     return m_pUnkOuter->AddRef();
  52.     }
  53. STDMETHODIMP_(ULONG) CImpIPersistStorage::Release(void)
  54.     {
  55.     --m_cRef;
  56.     return m_pUnkOuter->Release();
  57.     }
  58. /*
  59.  * CImpIPersistStorage::GetClassID
  60.  *
  61.  * Purpose:
  62.  *  Returns the CLSID of the object represented by this interface.
  63.  *
  64.  * Parameters:
  65.  *  pClsID          LPCLSID in which to store our CLSID.
  66.  *
  67.  * Return Value:
  68.  *  HRESULT         NOERROR or a general error value.
  69.  */
  70. STDMETHODIMP CImpIPersistStorage::GetClassID(LPCLSID pClsID)
  71.     {
  72.     if (PSSTATE_UNINIT==m_psState)
  73.         return ResultFromScode(E_UNEXPECTED);
  74.     *pClsID=m_pObj->m_clsID;
  75.     return NOERROR;
  76.     }
  77. /*
  78.  * CImpIPersistStorage::IsDirty
  79.  *
  80.  * Purpose:
  81.  *  Tells the caller if we have made changes to this object since
  82.  *  it was loaded or initialized new.
  83.  *
  84.  * Parameters:
  85.  *  None
  86.  *
  87.  * Return Value:
  88.  *  HRESULT         Contains S_OK if we ARE dirty, S_FALSE if
  89.  *                  NOT dirty.
  90.  */
  91. STDMETHODIMP CImpIPersistStorage::IsDirty(void)
  92.     {
  93.     if (PSSTATE_UNINIT==m_psState)
  94.         return ResultFromScode(E_UNEXPECTED);
  95.     //CFigure::FIsDirty returns the document's dirty flag.
  96.     return ResultFromScode(m_pObj->FIsDirty() ? S_OK : S_FALSE);
  97.     }
  98. /*
  99.  * CImpIPersistStorage::InitNew
  100.  *
  101.  * Purpose:
  102.  *  Provides the object with the IStorage to hold on to while the
  103.  *  object is running.  Here we initialize the structure of the
  104.  *  storage and AddRef it for incremental access. This function will
  105.  *  only be called once in the object's lifetime in lieu of Load.
  106.  *
  107.  * Parameters:
  108.  *  pIStorage       LPSTORAGE for the object.
  109.  *
  110.  * Return Value:
  111.  *  HRESULT         NOERROR or a general error value.
  112.  */
  113. STDMETHODIMP CImpIPersistStorage::InitNew(LPSTORAGE pIStorage)
  114.     {
  115.     HRESULT     hr;
  116.     if (PSSTATE_UNINIT!=m_psState)
  117.         return ResultFromScode(E_UNEXPECTED);
  118.     if (NULL==pIStorage)
  119.         return ResultFromScode(E_POINTER);
  120.     /*
  121.      * The rules of IPersistStorage mean we hold onto the IStorage
  122.      * and pre-create anything we'd need in Save(...,TRUE) for
  123.      * low-memory situations.  For us this means creating our
  124.      * "CONTENTS" stream and holding onto that IStream as
  125.      * well as the IStorage here (requiring an AddRef call).
  126.      */
  127.     hr=pIStorage->CreateStream(SZSTREAM, STGM_DIRECT
  128.         | STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE
  129.         , 0, 0, &m_pObj->m_pIStream);
  130.     if (FAILED(hr))
  131.         return hr;
  132.     //We expect that the client has called WriteClassStg
  133.     WriteFmtUserTypeStg(pIStorage, m_pObj->m_cf
  134.         , (*m_pObj->m_pST)[IDS_USERTYPE]);
  135.     pIStorage->AddRef();
  136.     m_pObj->m_pIStorage=pIStorage;
  137.     m_psState=PSSTATE_SCRIBBLE;
  138.     return NOERROR;
  139.     }
  140. /*
  141.  * CImpIPersistStorage::Load
  142.  *
  143.  * Purpose:
  144.  *  Instructs the object to load itself from a previously saved
  145.  *  IStorage that was handled by Save in another object lifetime.
  146.  *  This function will only be called once in the object's lifetime
  147.  *  in lieu of InitNew. The object should hold on to pIStorage here
  148.  *  for incremental access and low-memory saves in Save.
  149.  *
  150.  * Parameters:
  151.  *  pIStorage       LPSTORAGE from which to load.
  152.  *
  153.  * Return Value:
  154.  *  HRESULT         NOERROR or a general error value.
  155.  */
  156. STDMETHODIMP CImpIPersistStorage::Load(LPSTORAGE pIStorage)
  157.     {
  158.     HRESULT     hr;
  159.     LONG        lRet;
  160.     LPSTREAM    pIStream;
  161.     if (PSSTATE_UNINIT!=m_psState)
  162.         return ResultFromScode(E_UNEXPECTED);
  163.     if (NULL==pIStorage)
  164.         return ResultFromScode(E_POINTER);
  165.     //This tells us if we're coming from another class storage.
  166.     m_fConvert=(NOERROR==GetConvertStg(pIStorage));
  167.     //This is the type of storage we're really messing with in Treat As
  168.     ReadClassStg(pIStorage, &m_pObj->m_clsID);
  169.     hr=pIStorage->OpenStream(SZSTREAM, 0, STGM_DIRECT
  170.         | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  171.     //We might be looking for OLE 1 streams as well.
  172.     if (FAILED(hr))
  173.         {
  174.         hr=pIStorage->OpenStream(SZOLE1STREAM, 0, STGM_DIRECT
  175.             | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  176.         if (FAILED(hr))
  177.             return ResultFromScode(STG_E_READFAULT);
  178.         m_pObj->m_pPL->m_fReadFromOLE10=TRUE;
  179.         }
  180.     if (FAILED(hr))
  181.         return ResultFromScode(STG_E_READFAULT);
  182.     lRet=m_pObj->m_pPL->ReadFromStream(pIStream);
  183.     if (lRet < 0)
  184.         return ResultFromScode(STG_E_READFAULT);
  185.     /*
  186.      * We don't call pIStream->Release here because we may need
  187.      * it for a low-memory save in Save.  We also need to
  188.      * hold onto a copy of pIStorage, meaning AddRef.
  189.      */
  190.     m_pObj->m_pIStream=pIStream;
  191.     pIStorage->AddRef();
  192.     m_pObj->m_pIStorage=pIStorage;
  193.     m_psState=PSSTATE_SCRIBBLE;
  194.     return NOERROR;
  195.     }
  196. /*
  197.  * CImpIPersistStorage::Save
  198.  *
  199.  * Purpose:
  200.  * Purpose:
  201.  *  Saves the data for this object to an IStorage which may
  202.  *  or may not be the same as the one previously passed to
  203.  *  Load, indicated with fSameAsLoad.  After this call we may
  204.  *  not write into the storage again until SaveCompleted is
  205.  *  called, although we may still read.
  206.  *
  207.  * Parameters:
  208.  *  pIStorage       LPSTORAGE in which to save our data.
  209.  *  fSameAsLoad     BOOL indicating if this is the same pIStorage
  210.  *                  that was passed to Load.  If TRUE, then the
  211.  *                  object should write whatever it has *without
  212.  *                  *using any extra memory* as this may be a low
  213.  *                  memory save attempt.  That means that you must
  214.  *                  not try to open or create streams.  If FALSE
  215.  *                  you need to regenerate your whole storage
  216.  *                  structure, being sure to also release any
  217.  *                  pointers held from InitNew and Load.
  218.  *
  219.  * Return Value:
  220.  *  HRESULT         NOERROR or a general error value.
  221.  */
  222. STDMETHODIMP CImpIPersistStorage::Save(LPSTORAGE pIStorage
  223.     , BOOL fSameAsLoad)
  224.     {
  225.     LONG        lRet;
  226.     HRESULT     hr;
  227.     LPSTREAM    pIStream;
  228.     LONG        lVer=VERSIONCURRENT;
  229.     //Have to come here from scribble state.
  230.     if (PSSTATE_SCRIBBLE!=m_psState)
  231.         return ResultFromScode(E_UNEXPECTED);
  232.     //Must have an IStorage if we're not in SameAsLoad
  233.     if (NULL==pIStorage && !fSameAsLoad)
  234.         return ResultFromScode(E_POINTER);
  235.     /*
  236.      * If this was read from an OLE 1.0 storage, but there is no
  237.      * convert bit, then we have to save the 1.0 format to the
  238.      * "1Ole10Native" stream.  Otherwise if we were converting
  239.      * from OLE 1.0, we should nuke the stream since it's no longer
  240.      * useful.  To handle this, we call WriteToStorage with
  241.      * VERSIONCURRENT in any convert case.  WriteToStorage will
  242.      * remove the OLE 1.0 stream if it previously read from one, or
  243.      * it will just save normally.
  244.      *
  245.      * The Polyine allows us to look at it's m_fReadFromOLE10 which
  246.      * tells us to pass it 0x00010000 if we're not converting, that
  247.      * is, we're doing Treat As on the OLE 1.0 object and so we
  248.      * need to write the new data in the Ole10Native stream.
  249.      */
  250.     if (!m_fConvert && m_pObj->m_pPL->m_fReadFromOLE10)
  251.         lVer=0x00010000;
  252.     /*
  253.      * If we're saving to a new storage, create a new stream.
  254.      * If fSameAsLoad it TRUE, then we write to the
  255.      * stream we already allocated.  We should NOT depends on
  256.      * pIStorage with fSameAsLoad is TRUE.
  257.      *
  258.      * If we're converting an OLE 1 storage to an OLE 2 storage,
  259.      * then we have to create a new stream (conversion is not
  260.      * guaranteed to succeed in low memory) and delete the old
  261.      * one, so we ignore fSameAsLoad if we're converting.
  262.      */
  263.     if (fSameAsLoad
  264.         && !(m_pObj->m_pPL->m_fReadFromOLE10 && m_fConvert))
  265.         {
  266.         LARGE_INTEGER   li;
  267.         /*
  268.          * Use pre-allocated streams to avoid failures due
  269.          * to low-memory conditions.  Be sure to reset the
  270.          * stream pointer if you used this stream before!!
  271.          */
  272.         pIStream=m_pObj->m_pIStream;
  273.         LISet32(li, 0);
  274.         pIStream->Seek(li, STREAM_SEEK_SET, NULL);
  275.         //This matches the Release below.
  276.         pIStream->AddRef();
  277.         }
  278.     else
  279.         {
  280.         hr=pIStorage->CreateStream(SZSTREAM, STGM_DIRECT
  281.             | STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE
  282.             , 0, 0, &pIStream);
  283.         if (FAILED(hr))
  284.             return hr;
  285.         WriteFmtUserTypeStg(pIStorage, m_pObj->m_cf
  286.             , (*m_pObj->m_pST)[IDS_USERTYPE]);
  287.         }
  288.     lRet=m_pObj->m_pPL->WriteToStream(pIStream, lVer);
  289.     pIStream->Release();
  290.     /*
  291.      * If we are overwriting an OLE 1 storage, delete the old
  292.      * Ole10Native stream if writing our CONTENTS worked.
  293.      */
  294.     if (m_pObj->m_pPL->m_fReadFromOLE10 && m_fConvert && (lRet >= 0))
  295.         pIStorage->DestroyElement(SZOLE1STREAM);
  296.     //Clear the convert bit if it was set
  297.     if (m_fConvert)
  298.         {
  299.         UINT        cf;
  300.         cf=RegisterClipboardFormat((*m_pObj->m_pST)[IDS_FORMAT]);
  301.         WriteFmtUserTypeStg(pIStorage, cf
  302.             , (*m_pObj->m_pST)[IDS_USERTYPE]);
  303.         SetConvertStg(pIStorage, FALSE);
  304.         m_fConvert=FALSE;
  305.         }
  306.     if (lRet >= 0)
  307.         {
  308.         m_psState=PSSTATE_ZOMBIE;
  309.         return NOERROR;
  310.         }
  311.     return ResultFromScode(STG_E_WRITEFAULT);
  312.     }
  313. /*
  314.  * CImpIPersistStorage::SaveCompleted
  315.  *
  316.  * Purpose:
  317.  *  Notifies the object that the storage in pIStorage has been
  318.  *  completely saved now.  This is called when the user of this
  319.  *  object wants to save us in a completely new storage, and if
  320.  *  we normally hang on to the storage we have to reinitialize
  321.  *  ourselves here for this new one that is now complete.
  322.  *
  323.  * Parameters:
  324.  *  pIStorage       LPSTORAGE of the new storage in which we live.
  325.  *
  326.  * Return Value:
  327.  *  HRESULT         NOERROR or a general error value.
  328.  */
  329. STDMETHODIMP CImpIPersistStorage::SaveCompleted(LPSTORAGE pIStorage)
  330.     {
  331.     HRESULT     hr;
  332.     LPSTREAM    pIStream;
  333.     //Must be called in no-scribble or hands-off state
  334.     if (!(PSSTATE_ZOMBIE==m_psState || PSSTATE_HANDSOFF==m_psState))
  335.         return ResultFromScode(E_UNEXPECTED);
  336.     //If we're coming from Hands-Off, we'd better get a storage
  337.     if (NULL==pIStorage && PSSTATE_HANDSOFF==m_psState)
  338.         return ResultFromScode(E_UNEXPECTED);
  339.     /*
  340.      * If pIStorage is NULL, then we don't need to do anything
  341.      * since we already have all the pointers we need for Save.
  342.      * Otherwise we have to release any held pointers and
  343.      * reinitialize them from pIStorage.
  344.      */
  345.     if (NULL!=pIStorage)
  346.         {
  347.         hr=pIStorage->OpenStream(SZSTREAM, 0, STGM_DIRECT
  348.             | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0
  349.             , &pIStream);
  350.         if (FAILED(hr))
  351.             return hr;
  352.         if (NULL!=m_pObj->m_pIStream)
  353.             m_pObj->m_pIStream->Release();
  354.         m_pObj->m_pIStream=pIStream;
  355.         if (NULL!=m_pObj->m_pIStorage)
  356.             m_pObj->m_pIStorage->Release();
  357.         m_pObj->m_pIStorage=pIStorage;
  358.         m_pObj->m_pIStorage->AddRef();
  359.         }
  360.     m_pObj->SendAdvise(OBJECTCODE_SAVED);
  361.     m_psState=PSSTATE_SCRIBBLE;
  362.     return NOERROR;
  363.     }
  364. /*
  365.  * CImpIPersistStorage::HandsOffStorage
  366.  *
  367.  * Purpose:
  368.  * Purpose:
  369.  *  Instructs the object that another agent is interested in having
  370.  *  total access to the storage we might be hanging on to from
  371.  *  InitNew or SaveCompleted.  In this case we must release our hold
  372.  *  and await another call to SaveCompleted before we have a hold
  373.  *  again.  Therefore we cannot read or write after this call until
  374.  *  SaveCompleted.
  375.  *
  376.  *  Situations where this might happen arise in compound document
  377.  *  scenarios where this object might be in-place active but the
  378.  *  application wants to rename and commit the root storage.
  379.  *  Therefore we are asked to close our hold, let the container
  380.  *  party on the storage, then call us again later to tell us the
  381.  *  new storage we can hold.
  382.  *
  383.  * Parameters:
  384.  *  None
  385.  *
  386.  * Return Value:
  387.  *  HRESULT         NOERROR or a general error value.
  388.  */
  389. STDMETHODIMP CImpIPersistStorage::HandsOffStorage(void)
  390.     {
  391.     /*
  392.      * Must come from scribble or no-scribble.  A repeated call
  393.      * to HandsOffStorage is an unexpected error (bug in client).
  394.      */
  395.     if (PSSTATE_UNINIT==m_psState || PSSTATE_HANDSOFF==m_psState)
  396.         return ResultFromScode(E_UNEXPECTED);
  397.     //Release held pointers
  398.     if (NULL!=m_pObj->m_pIStream)
  399.         {
  400.         m_pObj->m_pIStream->Release();
  401.         m_pObj->m_pIStream=NULL;
  402.         }
  403.     if (NULL!=m_pObj->m_pIStorage)
  404.         {
  405.         m_pObj->m_pIStorage->Release();
  406.         m_pObj->m_pIStorage=NULL;
  407.         }
  408.     m_psState=PSSTATE_HANDSOFF;
  409.     return NOERROR;
  410.     }