⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iperstor.cpp

📁 英文版的 想要的话可以下载了 为大家服务
💻 CPP
字号:
/*
 * IPERSTOR.CPP
 * Cosmo Chapter 18
 *
 * Implementation of the IPersistStorage interface that we expose on
 * the CFigure compound document object.  This ties into the
 * functionality of CPolyline.
 *
 * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
 *
 * Kraig Brockschmidt, Microsoft
 * Internet  :  kraigb@microsoft.com
 * Compuserve:  >INTERNET:kraigb@microsoft.com
 */


#include "cosmo.h"


/*
 * CImpIPersistStorage:CImpIPersistStorage
 * CImpIPersistStorage::~CImpIPersistStorage
 *
 * Constructor Parameters:
 *  pObj            PCFigure associated with this object.
 *  pUnkOuter       LPUNKNOWN of the controlling unknown.
 */

CImpIPersistStorage::CImpIPersistStorage(PCFigure pObj
    , LPUNKNOWN pUnkOuter)
    {
    m_cRef=0;
    m_pObj=pObj;
    m_pUnkOuter=pUnkOuter;
    m_psState=PSSTATE_UNINIT;

    m_fConvert=FALSE;
    return;
    }


CImpIPersistStorage::~CImpIPersistStorage(void)
    {
    return;
    }




/*
 * CImpIPersistStorage::QueryInterface
 * CImpIPersistStorage::AddRef
 * CImpIPersistStorage::Release
 */

STDMETHODIMP CImpIPersistStorage::QueryInterface(REFIID riid
    , PPVOID ppv)
    {
    return m_pUnkOuter->QueryInterface(riid, ppv);
    }

STDMETHODIMP_(ULONG) CImpIPersistStorage::AddRef(void)
    {
    ++m_cRef;
    return m_pUnkOuter->AddRef();
    }

STDMETHODIMP_(ULONG) CImpIPersistStorage::Release(void)
    {
    --m_cRef;
    return m_pUnkOuter->Release();
    }





/*
 * CImpIPersistStorage::GetClassID
 *
 * Purpose:
 *  Returns the CLSID of the object represented by this interface.
 *
 * Parameters:
 *  pClsID          LPCLSID in which to store our CLSID.
 *
 * Return Value:
 *  HRESULT         NOERROR or a general error value.
 */

STDMETHODIMP CImpIPersistStorage::GetClassID(LPCLSID pClsID)
    {
    if (PSSTATE_UNINIT==m_psState)
        return ResultFromScode(E_UNEXPECTED);

    *pClsID=m_pObj->m_clsID;
    return NOERROR;
    }





/*
 * CImpIPersistStorage::IsDirty
 *
 * Purpose:
 *  Tells the caller if we have made changes to this object since
 *  it was loaded or initialized new.
 *
 * Parameters:
 *  None
 *
 * Return Value:
 *  HRESULT         Contains S_OK if we ARE dirty, S_FALSE if
 *                  NOT dirty.
 */

STDMETHODIMP CImpIPersistStorage::IsDirty(void)
    {
    if (PSSTATE_UNINIT==m_psState)
        return ResultFromScode(E_UNEXPECTED);

    //CFigure::FIsDirty returns the document's dirty flag.
    return ResultFromScode(m_pObj->FIsDirty() ? S_OK : S_FALSE);
    }







/*
 * CImpIPersistStorage::InitNew
 *
 * Purpose:
 *  Provides the object with the IStorage to hold on to while the
 *  object is running.  Here we initialize the structure of the
 *  storage and AddRef it for incremental access. This function will
 *  only be called once in the object's lifetime in lieu of Load.
 *
 * Parameters:
 *  pIStorage       LPSTORAGE for the object.
 *
 * Return Value:
 *  HRESULT         NOERROR or a general error value.
 */

STDMETHODIMP CImpIPersistStorage::InitNew(LPSTORAGE pIStorage)
    {
    HRESULT     hr;

    if (PSSTATE_UNINIT!=m_psState)
        return ResultFromScode(E_UNEXPECTED);

    if (NULL==pIStorage)
        return ResultFromScode(E_POINTER);

    /*
     * The rules of IPersistStorage mean we hold onto the IStorage
     * and pre-create anything we'd need in Save(...,TRUE) for
     * low-memory situations.  For us this means creating our
     * "CONTENTS" stream and holding onto that IStream as
     * well as the IStorage here (requiring an AddRef call).
     */

    hr=pIStorage->CreateStream(SZSTREAM, STGM_DIRECT
        | STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE
        , 0, 0, &m_pObj->m_pIStream);

    if (FAILED(hr))
        return hr;

    //We expect that the client has called WriteClassStg
    WriteFmtUserTypeStg(pIStorage, m_pObj->m_cf
        , (*m_pObj->m_pST)[IDS_USERTYPE]);

    pIStorage->AddRef();
    m_pObj->m_pIStorage=pIStorage;

    m_psState=PSSTATE_SCRIBBLE;
    return NOERROR;
    }





/*
 * CImpIPersistStorage::Load
 *
 * Purpose:
 *  Instructs the object to load itself from a previously saved
 *  IStorage that was handled by Save in another object lifetime.
 *  This function will only be called once in the object's lifetime
 *  in lieu of InitNew. The object should hold on to pIStorage here
 *  for incremental access and low-memory saves in Save.
 *
 * Parameters:
 *  pIStorage       LPSTORAGE from which to load.
 *
 * Return Value:
 *  HRESULT         NOERROR or a general error value.
 */

STDMETHODIMP CImpIPersistStorage::Load(LPSTORAGE pIStorage)
    {
    HRESULT     hr;
    LONG        lRet;
    LPSTREAM    pIStream;

    if (PSSTATE_UNINIT!=m_psState)
        return ResultFromScode(E_UNEXPECTED);

    if (NULL==pIStorage)
        return ResultFromScode(E_POINTER);

    //This tells us if we're coming from another class storage.
    m_fConvert=(NOERROR==GetConvertStg(pIStorage));

    //This is the type of storage we're really messing with in Treat As
    ReadClassStg(pIStorage, &m_pObj->m_clsID);

    hr=pIStorage->OpenStream(SZSTREAM, 0, STGM_DIRECT
        | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pIStream);

    //We might be looking for OLE 1 streams as well.
    if (FAILED(hr))
        {
        hr=pIStorage->OpenStream(SZOLE1STREAM, 0, STGM_DIRECT
            | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pIStream);

        if (FAILED(hr))
            return ResultFromScode(STG_E_READFAULT);

        m_pObj->m_pPL->m_fReadFromOLE10=TRUE;
        }

    if (FAILED(hr))
        return ResultFromScode(STG_E_READFAULT);

    lRet=m_pObj->m_pPL->ReadFromStream(pIStream);

    if (lRet < 0)
        return ResultFromScode(STG_E_READFAULT);


    /*
     * We don't call pIStream->Release here because we may need
     * it for a low-memory save in Save.  We also need to
     * hold onto a copy of pIStorage, meaning AddRef.
     */
    m_pObj->m_pIStream=pIStream;

    pIStorage->AddRef();
    m_pObj->m_pIStorage=pIStorage;

    m_psState=PSSTATE_SCRIBBLE;
    return NOERROR;
    }





/*
 * CImpIPersistStorage::Save
 *
 * Purpose:
 * Purpose:
 *  Saves the data for this object to an IStorage which may
 *  or may not be the same as the one previously passed to
 *  Load, indicated with fSameAsLoad.  After this call we may
 *  not write into the storage again until SaveCompleted is
 *  called, although we may still read.
 *
 * Parameters:
 *  pIStorage       LPSTORAGE in which to save our data.
 *  fSameAsLoad     BOOL indicating if this is the same pIStorage
 *                  that was passed to Load.  If TRUE, then the
 *                  object should write whatever it has *without
 *                  *using any extra memory* as this may be a low
 *                  memory save attempt.  That means that you must
 *                  not try to open or create streams.  If FALSE
 *                  you need to regenerate your whole storage
 *                  structure, being sure to also release any
 *                  pointers held from InitNew and Load.
 *
 * Return Value:
 *  HRESULT         NOERROR or a general error value.
 */

STDMETHODIMP CImpIPersistStorage::Save(LPSTORAGE pIStorage
    , BOOL fSameAsLoad)
    {
    LONG        lRet;
    HRESULT     hr;
    LPSTREAM    pIStream;
    LONG        lVer=VERSIONCURRENT;

    //Have to come here from scribble state.
    if (PSSTATE_SCRIBBLE!=m_psState)
        return ResultFromScode(E_UNEXPECTED);

    //Must have an IStorage if we're not in SameAsLoad
    if (NULL==pIStorage && !fSameAsLoad)
        return ResultFromScode(E_POINTER);

    /*
     * If this was read from an OLE 1.0 storage, but there is no
     * convert bit, then we have to save the 1.0 format to the
     * "\1Ole10Native" stream.  Otherwise if we were converting
     * from OLE 1.0, we should nuke the stream since it's no longer
     * useful.  To handle this, we call WriteToStorage with
     * VERSIONCURRENT in any convert case.  WriteToStorage will
     * remove the OLE 1.0 stream if it previously read from one, or
     * it will just save normally.
     *
     * The Polyine allows us to look at it's m_fReadFromOLE10 which
     * tells us to pass it 0x00010000 if we're not converting, that
     * is, we're doing Treat As on the OLE 1.0 object and so we
     * need to write the new data in the Ole10Native stream.
     */

    if (!m_fConvert && m_pObj->m_pPL->m_fReadFromOLE10)
        lVer=0x00010000;


    /*
     * If we're saving to a new storage, create a new stream.
     * If fSameAsLoad it TRUE, then we write to the
     * stream we already allocated.  We should NOT depends on
     * pIStorage with fSameAsLoad is TRUE.
     *
     * If we're converting an OLE 1 storage to an OLE 2 storage,
     * then we have to create a new stream (conversion is not
     * guaranteed to succeed in low memory) and delete the old
     * one, so we ignore fSameAsLoad if we're converting.
     */

    if (fSameAsLoad
        && !(m_pObj->m_pPL->m_fReadFromOLE10 && m_fConvert))
        {
        LARGE_INTEGER   li;

        /*
         * Use pre-allocated streams to avoid failures due
         * to low-memory conditions.  Be sure to reset the
         * stream pointer if you used this stream before!!
         */
        pIStream=m_pObj->m_pIStream;
        LISet32(li, 0);
        pIStream->Seek(li, STREAM_SEEK_SET, NULL);

        //This matches the Release below.
        pIStream->AddRef();
        }
    else
        {
        hr=pIStorage->CreateStream(SZSTREAM, STGM_DIRECT
            | STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE
            , 0, 0, &pIStream);

        if (FAILED(hr))
            return hr;

        WriteFmtUserTypeStg(pIStorage, m_pObj->m_cf
            , (*m_pObj->m_pST)[IDS_USERTYPE]);
        }

    lRet=m_pObj->m_pPL->WriteToStream(pIStream, lVer);
    pIStream->Release();

    /*
     * If we are overwriting an OLE 1 storage, delete the old
     * Ole10Native stream if writing our CONTENTS worked.
     */
    if (m_pObj->m_pPL->m_fReadFromOLE10 && m_fConvert && (lRet >= 0))
        pIStorage->DestroyElement(SZOLE1STREAM);

    //Clear the convert bit if it was set
    if (m_fConvert)
        {
        UINT        cf;

        cf=RegisterClipboardFormat((*m_pObj->m_pST)[IDS_FORMAT]);
        WriteFmtUserTypeStg(pIStorage, cf
            , (*m_pObj->m_pST)[IDS_USERTYPE]);

        SetConvertStg(pIStorage, FALSE);
        m_fConvert=FALSE;
        }

    if (lRet >= 0)
        {
        m_psState=PSSTATE_ZOMBIE;
        return NOERROR;
        }

    return ResultFromScode(STG_E_WRITEFAULT);
    }






/*
 * CImpIPersistStorage::SaveCompleted
 *
 * Purpose:
 *  Notifies the object that the storage in pIStorage has been
 *  completely saved now.  This is called when the user of this
 *  object wants to save us in a completely new storage, and if
 *  we normally hang on to the storage we have to reinitialize
 *  ourselves here for this new one that is now complete.
 *
 * Parameters:
 *  pIStorage       LPSTORAGE of the new storage in which we live.
 *
 * Return Value:
 *  HRESULT         NOERROR or a general error value.
 */

STDMETHODIMP CImpIPersistStorage::SaveCompleted(LPSTORAGE pIStorage)
    {
    HRESULT     hr;
    LPSTREAM    pIStream;

    //Must be called in no-scribble or hands-off state
    if (!(PSSTATE_ZOMBIE==m_psState || PSSTATE_HANDSOFF==m_psState))
        return ResultFromScode(E_UNEXPECTED);

    //If we're coming from Hands-Off, we'd better get a storage
    if (NULL==pIStorage && PSSTATE_HANDSOFF==m_psState)
        return ResultFromScode(E_UNEXPECTED);

    /*
     * If pIStorage is NULL, then we don't need to do anything
     * since we already have all the pointers we need for Save.
     * Otherwise we have to release any held pointers and
     * reinitialize them from pIStorage.
     */

    if (NULL!=pIStorage)
        {
        hr=pIStorage->OpenStream(SZSTREAM, 0, STGM_DIRECT
            | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0
            , &pIStream);

        if (FAILED(hr))
            return hr;

        if (NULL!=m_pObj->m_pIStream)
            m_pObj->m_pIStream->Release();

        m_pObj->m_pIStream=pIStream;

        if (NULL!=m_pObj->m_pIStorage)
            m_pObj->m_pIStorage->Release();

        m_pObj->m_pIStorage=pIStorage;
        m_pObj->m_pIStorage->AddRef();
        }

    m_pObj->SendAdvise(OBJECTCODE_SAVED);
    m_psState=PSSTATE_SCRIBBLE;
    return NOERROR;
    }





/*
 * CImpIPersistStorage::HandsOffStorage
 *
 * Purpose:
 * Purpose:
 *  Instructs the object that another agent is interested in having
 *  total access to the storage we might be hanging on to from
 *  InitNew or SaveCompleted.  In this case we must release our hold
 *  and await another call to SaveCompleted before we have a hold
 *  again.  Therefore we cannot read or write after this call until
 *  SaveCompleted.
 *
 *  Situations where this might happen arise in compound document
 *  scenarios where this object might be in-place active but the
 *  application wants to rename and commit the root storage.
 *  Therefore we are asked to close our hold, let the container
 *  party on the storage, then call us again later to tell us the
 *  new storage we can hold.
 *
 * Parameters:
 *  None
 *
 * Return Value:
 *  HRESULT         NOERROR or a general error value.
 */

STDMETHODIMP CImpIPersistStorage::HandsOffStorage(void)
    {
    /*
     * Must come from scribble or no-scribble.  A repeated call
     * to HandsOffStorage is an unexpected error (bug in client).
     */
    if (PSSTATE_UNINIT==m_psState || PSSTATE_HANDSOFF==m_psState)
        return ResultFromScode(E_UNEXPECTED);

    //Release held pointers
    if (NULL!=m_pObj->m_pIStream)
        {
        m_pObj->m_pIStream->Release();
        m_pObj->m_pIStream=NULL;
        }

    if (NULL!=m_pObj->m_pIStorage)
        {
        m_pObj->m_pIStorage->Release();
        m_pObj->m_pIStorage=NULL;
        }

    m_psState=PSSTATE_HANDSOFF;
    return NOERROR;
    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -