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 / chap19 / polyline / iperstor.cpp < prev    next >
C/C++ Source or Header  |  1995-05-03  |  13KB  |  500 lines

  1. /*
  2.  * IPERSTOR.CPP
  3.  * Polyline Component Chapter 19
  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.     //CHAPTER19MOD
  182.     //Initialize the cache as needed.
  183.     m_pObj->m_pDefIPersistStorage->InitNew(pIStorage);
  184.     //End CHAPTER19MOD
  185.  
  186.     return NOERROR;
  187.     }
  188.  
  189.  
  190.  
  191.  
  192.  
  193. /*
  194.  * CImpIPersistStorage::Load
  195.  *
  196.  * Purpose:
  197.  *  Instructs the object to load itself from a previously saved
  198.  *  IStorage that was handled by Save in another object lifetime.
  199.  *  This function will only be called once in the object's lifetime
  200.  *  in lieu of InitNew. The object should hold on to pIStorage here
  201.  *  for incremental access and low-memory saves in Save.
  202.  *
  203.  * Parameters:
  204.  *  pIStorage       LPSTORAGE from which to load.
  205.  *
  206.  * Return Value:
  207.  *  HRESULT         NOERROR or a general error value.
  208.  */
  209.  
  210. STDMETHODIMP CImpIPersistStorage::Load(LPSTORAGE pIStorage)
  211.     {
  212.     POLYLINEDATA    pl;
  213.     ULONG           cb;
  214.     LPSTREAM        pIStream;
  215.     HRESULT         hr;
  216.  
  217.     if (PSSTATE_UNINIT!=m_psState)
  218.         return ResultFromScode(E_UNEXPECTED);
  219.  
  220.     if (NULL==pIStorage)
  221.         return ResultFromScode(E_POINTER);
  222.  
  223.     //We don't check CLSID to remain compatible with other chapters.
  224.  
  225.     hr=pIStorage->OpenStream(SZSTREAM, 0, STGM_DIRECT
  226.         | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  227.  
  228.     if (FAILED(hr))
  229.         return ResultFromScode(STG_E_READFAULT);
  230.  
  231.     //Read all the data into the POLYLINEDATA structure.
  232.     hr=pIStream->Read(&pl, CBPOLYLINEDATA, &cb);
  233.  
  234.     if (FAILED(hr) || CBPOLYLINEDATA!=cb)
  235.         {
  236.         pIStream->Release();
  237.         return hr;
  238.         }
  239.  
  240.     /*
  241.      * We don't call pIStream->Release here because we may need
  242.      * it for a low-memory save in Save.  We also need to
  243.      * hold onto a copy of pIStorage, meaning AddRef.
  244.      */
  245.     m_pObj->m_pIStream=pIStream;
  246.  
  247.     m_pObj->m_pIStorage=pIStorage;
  248.     pIStorage->AddRef();
  249.  
  250.     //DataSet now internal on CPolyline
  251.     m_pObj->DataSet(&pl, TRUE, TRUE);
  252.  
  253.     m_psState=PSSTATE_SCRIBBLE;
  254.  
  255.     //CHAPTER19MOD
  256.     //We also need to tell the cache to load cached graphics
  257.     m_pObj->m_pDefIPersistStorage->Load(pIStorage);
  258.     //End CHAPTER19MOD
  259.  
  260.     return NOERROR;
  261.     }
  262.  
  263.  
  264.  
  265.  
  266.  
  267. /*
  268.  * CImpIPersistStorage::Save
  269.  *
  270.  * Purpose:
  271.  *  Saves the data for this object to an IStorage which may
  272.  *  or may not be the same as the one previously passed to
  273.  *  Load, indicated with fSameAsLoad.  After this call we may
  274.  *  not write into the storage again until SaveCompleted is
  275.  *  called, although we may still read.
  276.  *
  277.  * Parameters:
  278.  *  pIStorage       LPSTORAGE in which to save our data.
  279.  *  fSameAsLoad     BOOL indicating if this is the same pIStorage
  280.  *                  that was passed to Load.  If TRUE, then the
  281.  *                  object should write whatever it has *without
  282.  *                  *using any extra memory* as this may be a low
  283.  *                  memory save attempt.  That means that you must
  284.  *                  not try to open or create streams.  If FALSE
  285.  *                  you need to regenerate your whole storage
  286.  *                  structure, being sure to also release any
  287.  *                  pointers held from InitNew and Load.
  288.  *
  289.  * Return Value:
  290.  *  HRESULT         NOERROR or a general error value.
  291.  */
  292.  
  293. STDMETHODIMP CImpIPersistStorage::Save(LPSTORAGE pIStorage
  294.     , BOOL fSameAsLoad)
  295.     {
  296.     POLYLINEDATA    pl;
  297.     ULONG           cb;
  298.     LPSTREAM        pIStream;
  299.     HRESULT         hr;
  300.  
  301.     //Have to come here from scribble state.
  302.     if (PSSTATE_SCRIBBLE!=m_psState)
  303.         return ResultFromScode(E_UNEXPECTED);
  304.  
  305.     //Must have an IStorage if we're not in SameAsLoad
  306.     if (NULL==pIStorage && !fSameAsLoad)
  307.         return ResultFromScode(E_POINTER);
  308.  
  309.  
  310.     /*
  311.      * If we're saving to a new storage, create a new stream.
  312.      * If fSameAsLoad it TRUE, then we write to the
  313.      * stream we already allocated.  We should NOT depends on
  314.      * pIStorage with fSameAsLoad is TRUE.
  315.      */
  316.     if (fSameAsLoad)
  317.         {
  318.         LARGE_INTEGER   li;
  319.  
  320.         /*
  321.          * Use pre-allocated streams to avoid failures due
  322.          * to low-memory conditions.  Be sure to reset the
  323.          * stream pointer if you used this stream before!!
  324.          */
  325.         pIStream=m_pObj->m_pIStream;
  326.         LISet32(li, 0);
  327.         pIStream->Seek(li, STREAM_SEEK_SET, NULL);
  328.  
  329.         //This matches the Release below.
  330.         pIStream->AddRef();
  331.         }
  332.     else
  333.         {
  334.         hr=pIStorage->CreateStream(SZSTREAM, STGM_DIRECT
  335.             | STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE
  336.             , 0, 0, &pIStream);
  337.  
  338.         if (FAILED(hr))
  339.             return hr;
  340.  
  341.         //Only do this with new storages.
  342.         WriteFmtUserTypeStg(pIStorage, m_pObj->m_cf
  343.             , (*m_pObj->m_pST)[IDS_USERTYPE]);
  344.         }
  345.  
  346.     //DataGet now internal on CPolyline
  347.     m_pObj->DataGet(&pl);
  348.  
  349.     hr=pIStream->Write(&pl, CBPOLYLINEDATA, &cb);
  350.     pIStream->Release();
  351.  
  352.     if (FAILED(hr) || CBPOLYLINEDATA!=cb)
  353.         return ResultFromScode(STG_E_WRITEFAULT);
  354.  
  355.     m_psState=PSSTATE_ZOMBIE;
  356.  
  357.     //CHAPTER19MOD
  358.     //We also need to tell the cache to save cached graphics
  359.     m_pObj->m_pDefIPersistStorage->Save(pIStorage, fSameAsLoad);
  360.     //End CHAPTER19MOD
  361.  
  362.     return NOERROR;
  363.     }
  364.  
  365.  
  366.  
  367.  
  368.  
  369.  
  370.  
  371.  
  372. /*
  373.  * CImpIPersistStorage::SaveCompleted
  374.  *
  375.  * Purpose:
  376.  *  Notifies the object that the storage in pIStorage has been
  377.  *  completely saved now.  This is called when the user of this
  378.  *  object wants to save us in a completely new storage, and if
  379.  *  we normally hang on to the storage we have to reinitialize
  380.  *  ourselves here for this new one that is now complete.
  381.  *
  382.  * Parameters:
  383.  *  pIStorage       LPSTORAGE of the new storage in which we live.
  384.  *
  385.  * Return Value:
  386.  *  HRESULT         NOERROR or a general error value.
  387.  */
  388.  
  389. STDMETHODIMP CImpIPersistStorage::SaveCompleted(LPSTORAGE pIStorage)
  390.     {
  391.     HRESULT     hr;
  392.     LPSTREAM    pIStream;
  393.  
  394.     //Must be called in no-scribble or hands-off state
  395.     if (!(PSSTATE_ZOMBIE==m_psState || PSSTATE_HANDSOFF==m_psState))
  396.         return ResultFromScode(E_UNEXPECTED);
  397.  
  398.     //If we're coming from Hands-Off, we'd better get a storage
  399.     if (NULL==pIStorage && PSSTATE_HANDSOFF==m_psState)
  400.         return ResultFromScode(E_UNEXPECTED);
  401.  
  402.     /*
  403.      * If pIStorage is NULL, then we don't need to do anything
  404.      * since we already have all the pointers we need for Save.
  405.      * Otherwise we have to release any held pointers and
  406.      * reinitialize them from pIStorage.
  407.      */
  408.  
  409.     if (NULL!=pIStorage)
  410.         {
  411.         hr=pIStorage->OpenStream(SZSTREAM, 0, STGM_DIRECT
  412.             | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0
  413.             , &pIStream);
  414.  
  415.         if (FAILED(hr))
  416.             return hr;
  417.  
  418.         if (NULL!=m_pObj->m_pIStream)
  419.             m_pObj->m_pIStream->Release();
  420.  
  421.         m_pObj->m_pIStream=pIStream;
  422.  
  423.         if (NULL!=m_pObj->m_pIStorage)
  424.             m_pObj->m_pIStorage->Release();
  425.  
  426.         m_pObj->m_pIStorage=pIStorage;
  427.         m_pObj->m_pIStorage->AddRef();
  428.         }
  429.  
  430.     //Change state back to scribble.
  431.     m_psState=PSSTATE_SCRIBBLE;
  432.  
  433.     //CHAPTER19MOD
  434.     m_pObj->m_pDefIPersistStorage->SaveCompleted(pIStorage);
  435.     //End CHAPTER19MOD
  436.  
  437.     return NOERROR;
  438.     }
  439.  
  440.  
  441.  
  442.  
  443.  
  444. /*
  445.  * CImpIPersistStorage::HandsOffStorage
  446.  *
  447.  * Purpose:
  448.  *  Instructs the object that another agent is interested in having
  449.  *  total access to the storage we might be hanging on to from
  450.  *  InitNew or SaveCompleted.  In this case we must release our hold
  451.  *  and await another call to SaveCompleted before we have a hold
  452.  *  again.  Therefore we cannot read or write after this call until
  453.  *  SaveCompleted.
  454.  *
  455.  *  Situations where this might happen arise in compound document
  456.  *  scenarios where this object might be in-place active but the
  457.  *  application wants to rename and commit the root storage.
  458.  *  Therefore we are asked to close our hold, let the container
  459.  *  party on the storage, then call us again later to tell us the
  460.  *  new storage we can hold.
  461.  *
  462.  * Parameters:
  463.  *  None
  464.  *
  465.  * Return Value:
  466.  *  HRESULT         NOERROR or a general error value.
  467.  */
  468.  
  469. STDMETHODIMP CImpIPersistStorage::HandsOffStorage(void)
  470.     {
  471.     /*
  472.      * Must come from scribble or no-scribble.  A repeated call
  473.      * to HandsOffStorage is an unexpected error (bug in client).
  474.      */
  475.     if (PSSTATE_UNINIT==m_psState || PSSTATE_HANDSOFF==m_psState)
  476.         return ResultFromScode(E_UNEXPECTED);
  477.  
  478.  
  479.     //Release held pointers
  480.     if (NULL!=m_pObj->m_pIStream)
  481.         {
  482.         m_pObj->m_pIStream->Release();
  483.         m_pObj->m_pIStream=NULL;
  484.         }
  485.  
  486.     if (NULL!=m_pObj->m_pIStorage)
  487.         {
  488.         m_pObj->m_pIStorage->Release();
  489.         m_pObj->m_pIStorage=NULL;
  490.         }
  491.  
  492.     m_psState=PSSTATE_HANDSOFF;
  493.  
  494.     //CHAPTER19MOD
  495.     m_pObj->m_pDefIPersistStorage->HandsOffStorage();
  496.     //End CHAPTER19MOD
  497.  
  498.     return NOERROR;
  499.     }
  500.