CTLPSST.CPP
//=--------------------------------------------------------------------------= 
// CtlPsst.Cpp 
//=--------------------------------------------------------------------------= 
// Copyright 1995 - 1998 Microsoft Corporation.  All Rights Reserved. 
// 
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF  
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO  
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A  
// PARTICULAR PURPOSE. 
//=--------------------------------------------------------------------------= 
// 
// implementation of persistence interfaces for COleControl. 
// 
#include "IPServer.H" 
#include "CtrlObj.H" 
 
#include "CtlHelp.H" 
#include "Util.H" 
 
// this is the name of the stream we'll save our ole controls to. 
// 
const WCHAR wszCtlSaveStream [] = L"CONTROLSAVESTREAM"; 
 
// for ASSERT and FAIL 
// 
SZTHISFILE 
 
//=--------------------------------------------------------------------------= 
// to help with out stream save implementation ... 
// 
#define STREAMHDR_SIGNATURE 0x12344321  // Signature to identify our format (avoid crashes!) 
#define IPROP_END 0xFF                  // Marker at end of property list 
#define MAXAUTOBUF 3800                 // Best if < 1 page. 
 
typedef struct tagSTREAMHDR { 
 
    DWORD  dwSignature;     // Signature. 
    size_t cbWritten;       // Number of bytes written 
 
} STREAMHDR; 
 
//=--------------------------------------------------------------------------= 
// COleControl persistence interfaces 
//=--------------------------------------------------------------------------= 
 
 
//=--------------------------------------------------------------------------= 
// COleControl::Load    [IPersistPropertyBag] 
//=--------------------------------------------------------------------------= 
// IPersistPropertyBag.  we've got a property bag, so let's load our properties 
// from it. 
// 
// Parameters: 
//    IPropertyBag *      - [in] pbag from which to read props. 
//    IErrorLog *         - [in] error log to write to 
// 
// Output: 
//    HRESULT 
// 
// Notes: 
// 
STDMETHODIMP COleControl::Load 
( 
    IPropertyBag *pPropertyBag, 
    IErrorLog    *pErrorLog 
) 
{ 
    HRESULT hr; 
 
    // load in our standard state first.  nothing serious here ... currently, 
    // we've just got two properties, for cx and cy. 
    // 
    hr = LoadStandardState(pPropertyBag, pErrorLog); 
    RETURN_ON_FAILURE(hr); 
 
    // now call the user text load function, and get them to load in whatever 
    // they're interested in. 
    // 
    hr = LoadTextState(pPropertyBag, pErrorLog); 
 
    return hr; 
} 
 
//=--------------------------------------------------------------------------= 
// COleControl::Save    [IPersistPropertyBag] 
//=--------------------------------------------------------------------------= 
// given a property bag, save out all the relevant state information. 
// 
// Parameters: 
//    IPropertyBag *        - [in] property to write to 
//    BOOL                  - [in] do we clear the dirty bit? 
//    BOOL                  - [in] do we write out default values anyhoo? 
// 
// Output: 
//    HRESULT 
// 
// Notes: 
// 
STDMETHODIMP COleControl::Save 
( 
    IPropertyBag *pPropertyBag, 
    BOOL          fClearDirty, 
    BOOL          fWriteDefault 
) 
{ 
    HRESULT hr; 
 
    // save out standard state information 
    // 
    hr = SaveStandardState(pPropertyBag); 
    RETURN_ON_FAILURE(hr); 
 
    // now call the user function and get them to save out 
    // all of their properties. 
    // 
    hr = SaveTextState(pPropertyBag, fWriteDefault); 
    RETURN_ON_FAILURE(hr); 
 
    // now clear the dirty flag and send out notification that we're 
    // done. 
    // 
    if (fClearDirty) 
        m_fDirty = FALSE; 
 
    if (m_pOleAdviseHolder) 
        m_pOleAdviseHolder->SendOnSave(); 
 
    return S_OK; 
} 
 
//=--------------------------------------------------------------------------= 
// COleControl::GetClassID    [IPersistStreamInit] 
//=--------------------------------------------------------------------------= 
// returns the classid of this mamma 
// 
// Parameters: 
//    CLSID *         - [out] where to put the clsid 
// 
// Output: 
//    HRESULT 
// 
// Notes: 
// 
STDMETHODIMP COleControl::GetClassID 
( 
    CLSID *pclsid 
) 
{ 
    CHECK_POINTER(pclsid); 
 
    // copy the thing over 
    // 
    *pclsid = CLSIDOFOBJECT(m_ObjectType); 
    return S_OK; 
} 
 
 
//=--------------------------------------------------------------------------= 
// COleControl::IsDirty    [IPersistStreamInit] 
//=--------------------------------------------------------------------------= 
// asks if we're dirty or not.  duh. 
// 
// Output: 
//    HRESULT        - S_OK: dirty, S_FALSE: not dirty 
// 
// Notes: 
// 
STDMETHODIMP COleControl::IsDirty 
( 
    void 
) 
{ 
    return (m_fDirty) ? S_OK : S_FALSE; 
} 
 
//=--------------------------------------------------------------------------= 
// COleControl::InitNew    [IPersistStreamInit] 
//=--------------------------------------------------------------------------= 
// causes the control to intialize itself with a new bunch of state information 
// 
// Output: 
//    HRESULT 
// 
// Notes: 
// 
STDMETHODIMP COleControl::InitNew 
( 
    void 
) 
{ 
    BOOL f; 
 
    // call the overridable function to do this work 
    // 
    f = InitializeNewState(); 
    return (f) ? S_OK : E_FAIL; 
} 
 
//=--------------------------------------------------------------------------= 
// COleControl::GetSizeMax    [IPersistStreamInit] 
//=--------------------------------------------------------------------------= 
// 
// Parameters: 
//    ULARGE_INTEGER *    - [out] 
// 
// Output: 
//    HRESULT 
// 
// Notes: 
// 
STDMETHODIMP COleControl::GetSizeMax 
( 
    ULARGE_INTEGER *pulMaxSize 
) 
{ 
    return E_NOTIMPL; 
} 
 
//=--------------------------------------------------------------------------= 
// COleControl::Load    [IPersistStreamInit] 
//=--------------------------------------------------------------------------= 
// load from an IStream 
// 
// Parameters: 
//    IStream *    - [in] stream from which to load 
// 
// Output: 
//    HRESULT 
// 
// Notes: 
// 
STDMETHODIMP COleControl::Load 
( 
    IStream *pStream 
) 
{ 
    HRESULT hr; 
 
    // first thing to do is read in standard properties the user don't 
    // persist themselves. 
    // 
    hr = LoadStandardState(pStream); 
    RETURN_ON_FAILURE(hr); 
 
    // load in the user properties.  this method is one they -have- to implement 
    // themselves. 
    // 
    hr = LoadBinaryState(pStream); 
     
    return hr; 
} 
 
//=--------------------------------------------------------------------------= 
// COleControl::Save    [IPersistStreamInit] 
//=--------------------------------------------------------------------------= 
// saves out our state using streams 
// 
// Parameters: 
//    IStream *        - [in] 
//    BOOL             - [in] clear dirty bit? 
// 
// Output: 
//    HRESULT 
// 
// Notes: 
// 
STDMETHODIMP COleControl::Save 
( 
    IStream *pStream, 
    BOOL     fClearDirty 
) 
{ 
    HRESULT hr; 
 
    // use our helper routine that we share with the IStorage persistence 
    // code. 
    // 
    hr = m_SaveToStream(pStream); 
    RETURN_ON_FAILURE(hr); 
 
    // clear out dirty flag [if appropriate] and notify that we're done 
    // with save. 
    // 
    if (fClearDirty) 
        m_fDirty = FALSE; 
    if (m_pOleAdviseHolder) 
        m_pOleAdviseHolder->SendOnSave(); 
 
    return S_OK; 
} 
 
//=--------------------------------------------------------------------------= 
// COleControl::InitNew    [IPersistStorage] 
//=--------------------------------------------------------------------------= 
// ipersiststorage version of this.  fweee 
// 
// Parameters: 
//    IStorage *    - [in] we don't use this 
// 
// Output: 
//    HRESULT 
// 
// Notes: 
// 
STDMETHODIMP COleControl::InitNew 
( 
    IStorage *pStorage 
) 
{ 
    // we already have an implementation of this [for IPersistStreamInit] 
    // 
    return InitNew(); 
} 
 
//=--------------------------------------------------------------------------= 
// COleControl::Load    [IPersistStorage] 
//=--------------------------------------------------------------------------= 
// Ipersiststorage version of this 
// 
// Parameters: 
//    IStorage *    - [in] DUH. 
// 
// Output: 
//    HRESULT 
// 
// Notes: 
// 
STDMETHODIMP COleControl::Load(IStorage *pStorage) 
{ 
    IStream *pStream; 
    HRESULT  hr; 
 
    // we're going to use IPersistStream::Load from the CONTENTS stream. 
    // 
    hr = pStorage->OpenStream(wszCtlSaveStream, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream); 
    RETURN_ON_FAILURE(hr); 
 
    // IPersistStreamInit::Load 
    // 
    hr = Load(pStream); 
    pStream->Release(); 
    return hr; 
} 
 
//=--------------------------------------------------------------------------= 
// COleControl::Save    [IPersistStorage] 
//=--------------------------------------------------------------------------= 
// save into the contents stream of the given storage object. 
// 
// Parameters: 
//    IStorage *        - [in] 10 points if you figure it out 
//    BOOL              - [in] is the storage the same as the load storage? 
// 
// Output: 
//    HRESULT 
// 
// Notes: 
// 
STDMETHODIMP COleControl::Save 
( 
    IStorage *pStorage, 
    BOOL      fSameAsLoad 
) 
{ 
    IStream *pStream; 
    HRESULT  hr; 
 
    // we're just going to save out to the CONTENTES stream. 
    // 
    hr = pStorage->CreateStream(wszCtlSaveStream, STGM_WRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, 
                                0, 0, &pStream); 
    RETURN_ON_FAILURE(hr); 
 
    // use our helper routine. 
    // 
    hr = m_SaveToStream(pStream); 
    m_fSaveSucceeded = (FAILED(hr)) ? FALSE : TRUE; 
    pStream->Release(); 
    return hr; 
} 
 
//=--------------------------------------------------------------------------= 
// COleControl::SaveCompleted    [IPersistStorage] 
//=--------------------------------------------------------------------------= 
// lets us clear out our flags. 
// 
// Parameters: 
//    IStorage *    - ignored 
// 
// Output: 
//    HRESULT 
// 
// Notes: 
// 
STDMETHODIMP COleControl::SaveCompleted 
( 
    IStorage *pStorageNew 
) 
{ 
    // if our save succeeded, then we can do our post save work. 
    // 
    if (m_fSaveSucceeded) { 
        m_fDirty = FALSE; 
        if (m_pOleAdviseHolder) 
            m_pOleAdviseHolder->SendOnSave(); 
    } 
 
    return S_OK; 
} 
 
//=--------------------------------------------------------------------------= 
// COleControl::HandsOffStorage    [IPersistStorage] 
//=--------------------------------------------------------------------------= 
// not interesting 
// 
// Output: 
//    S_OK 
// 
// Notes: 
// 
STDMETHODIMP COleControl::HandsOffStorage 
( 
    void 
) 
{ 
    // we don't ever hold on to  a storage pointer, so this is remarkably 
    // uninteresting to us. 
    // 
    return S_OK; 
} 
 
//=--------------------------------------------------------------------------= 
// COleControl::m_SaveToStream    [helper: IPersistStreamInit/IPersistStorage] 
//=--------------------------------------------------------------------------= 
// save ourselves to a stream 
// 
// Parameters: 
//    IStream *        - figure it out 
// 
// Output: 
//    HRESULT 
// 
// Notes: 
// 
HRESULT COleControl::m_SaveToStream 
( 
    IStream *pStream 
) 
{ 
    HRESULT hr; 
 
    // save out standard state information that the user has no control 
    // over 
    // 
    hr = SaveStandardState(pStream); 
    RETURN_ON_FAILURE(hr); 
 
    // save out user-specific satte information.  they MUST implement this 
    // function 
    // 
    hr = SaveBinaryState(pStream); 
 
    return hr; 
} 
 
//=--------------------------------------------------------------------------= 
// COleControl::LoadStandardState    [ helper ] 
//=--------------------------------------------------------------------------= 
// reads in standard properties that all controls are going to have, using 
// text persistence APIs.  there is another version for streams. 
// 
// Parameters: 
//    IPropertyBag *    - [in] 
//    IErrorLog *       - [in] 
// 
// Output: 
//    HRESULT 
// 
// Notes: 
// 
HRESULT COleControl::LoadStandardState 
( 
    IPropertyBag *pPropertyBag, 
    IErrorLog    *pErrorLog 
) 
{ 
    VARIANT v; 
    HRESULT hr; 
    SIZEL   slHiMetric = { 100, 50 }; 
 
    // currently, our only standard properties are related to size. 
    // if we can't find them, then we'll just use some defaults. 
    // 
    v.vt = VT_I4; 
    v.lVal = 0; 
    hr = pPropertyBag->Read(L"_ExtentX", &v, pErrorLog); 
    if (SUCCEEDED(hr)) slHiMetric.cx = v.lVal; 
 
    v.lVal = 0; 
    hr = pPropertyBag->Read(L"_ExtentY", &v, pErrorLog); 
    if (SUCCEEDED(hr)) slHiMetric.cy = v.lVal; 
 
    HiMetricToPixel(&slHiMetric, &m_Size); 
    return S_OK; 
} 
 
//=--------------------------------------------------------------------------= 
// COleControl::LoadStandardState    [ helper ] 
//=--------------------------------------------------------------------------= 
// reads in standard properties that all controls are going to have, using 
// stream persistence APIs.  there is another version for text. 
// 
// Parameters: 
//    IStream *         - [in]  
// 
// Output: 
//    HRESULT 
// 
// Notes: 
// 
HRESULT COleControl::LoadStandardState 
( 
    IStream *pStream 
) 
{ 
    STREAMHDR stmhdr; 
    HRESULT hr; 
    SIZEL   slHiMetric; 
 
    // look for our header structure, so we can verify stream validity. 
    // 
    hr = pStream->Read(&stmhdr, sizeof(STREAMHDR), NULL); 
    RETURN_ON_FAILURE(hr); 
 
    if (stmhdr.dwSignature != STREAMHDR_SIGNATURE) 
        return E_UNEXPECTED; 
 
    // currently, the only standard state we're writing out is 
    // a SIZEL structure describing the control's size. 
    // 
    if (stmhdr.cbWritten != sizeof(m_Size)) 
        return E_UNEXPECTED; 
 
    // we like the stream.  let's go load in our two properties. 
    // 
    hr = pStream->Read(&slHiMetric, sizeof(slHiMetric), NULL); 
    RETURN_ON_FAILURE(hr); 
 
    HiMetricToPixel(&slHiMetric, &m_Size); 
    return S_OK; 
} 
 
//=--------------------------------------------------------------------------= 
// COleControl::SaveStandardState    [ helper ] 
//=--------------------------------------------------------------------------= 
// saves out standard properties that we're managing for a control using text 
// persistence APIs.  there is another version for stream persistence. 
// 
// Parameters: 
//    IPropertyBag *        - [in] 
// 
// Output: 
//    HRESULT 
// 
// Notes: 
// 
HRESULT COleControl::SaveStandardState 
( 
    IPropertyBag *pPropertyBag 
) 
{ 
    HRESULT hr; 
    VARIANT v; 
    SIZEL   slHiMetric; 
 
    // currently, the only standard proprerties we persist are Size related 
    // 
    PixelToHiMetric(&m_Size, &slHiMetric); 
 
    v.vt = VT_I4; 
    v.lVal = slHiMetric.cx; 
 
    hr = pPropertyBag->Write(L"_ExtentX", &v); 
    RETURN_ON_FAILURE(hr); 
 
    v.lVal = slHiMetric.cy; 
 
    hr = pPropertyBag->Write(L"_ExtentY", &v); 
 
    return hr; 
} 
 
//=--------------------------------------------------------------------------= 
// COleControl::SaveStandardState    [ helper ] 
//=--------------------------------------------------------------------------= 
// saves out standard properties that we're managing for a control using stream 
// persistence APIs.  there is another version for text persistence. 
// 
// Parameters: 
//    IStream *            - [in] 
// 
// Output: 
//    HRESULT 
// 
// Notes: 
// 
HRESULT COleControl::SaveStandardState 
( 
    IStream *pStream 
) 
{ 
    STREAMHDR streamhdr = { STREAMHDR_SIGNATURE, sizeof(SIZEL) }; 
    HRESULT hr; 
    SIZEL   slHiMetric; 
 
 
    // first thing to do is write out our stream hdr structure. 
    // 
    hr = pStream->Write(&streamhdr, sizeof(STREAMHDR), NULL); 
    RETURN_ON_FAILURE(hr); 
 
    // the only properties we're currently persisting here are the size 
    // properties for this control.  make sure we do that in HiMetric 
    // 
    PixelToHiMetric(&m_Size, &slHiMetric); 
 
    hr = pStream->Write(&slHiMetric, sizeof(slHiMetric), NULL); 
    return hr; 
} 
 
//=--------------------------------------------------------------------------= 
// COleControl::InitializeNewState    [overridable] 
//=--------------------------------------------------------------------------= 
// the user can override this to initialize variables 
// 
// Output: 
//    BOOL        - FALSE means couldn't do it. 
// 
// Notes: 
// 
BOOL COleControl::InitializeNewState 
( 
    void 
) 
{ 
    // we find this largely uninteresting 
    // 
    return TRUE; 
}