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

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