home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / inole2 / chap21 / polyline / iperstor.cpp < prev    next >
C/C++ Source or Header  |  1995-05-03  |  13KB  |  485 lines

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