665 lines
16 KiB
C++
665 lines
16 KiB
C++
//=--------------------------------------------------------------------------=
|
|
// ControlPersistence.Cpp
|
|
//=--------------------------------------------------------------------------=
|
|
// Copyright 1995 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 "pch.h"
|
|
#include "CtrlObj.H"
|
|
|
|
#include "CtlHelp.H"
|
|
|
|
// for ASSERT and FAIL
|
|
//
|
|
SZTHISFILE
|
|
|
|
|
|
// this is the name of the stream we'll save our ole controls to.
|
|
//
|
|
const WCHAR wszCtlSaveStream [] = L"Contents";
|
|
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// 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();
|
|
|
|
// make sure we mark ourselves as dirty
|
|
//
|
|
m_fDirty = TRUE;
|
|
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 (FAILED(hr)) goto DefaultSize;
|
|
|
|
slHiMetric.cx = v.lVal;
|
|
|
|
v.lVal = 0;
|
|
hr = pPropertyBag->Read(L"_ExtentY", &v, pErrorLog);
|
|
if (FAILED(hr)) goto DefaultSize;
|
|
slHiMetric.cy = v.lVal;
|
|
|
|
HiMetricToPixel(&slHiMetric, &m_Size);
|
|
return S_OK;
|
|
|
|
DefaultSize:
|
|
m_Size.cx = 100;
|
|
m_Size.cy = 50;
|
|
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;
|
|
}
|
|
|
|
|