123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924 |
- #ifndef __PropertyClass_cpp__
- #define __PropertyClass_cpp__
- /////////////////////////////////////////////////////////////////////////////
- // PropertyClass.cpp | Implementation of the TCComPropertyClassRoot class.
- //
- #include "PropertyClass.h"
- /////////////////////////////////////////////////////////////////////////////
- // TCComPropertyClassRoot
- /////////////////////////////////////////////////////////////////////////////
- // Construction
- #ifdef _DEBUG
- ///////////////////////////////////////////////////////////////////////////
- // {group:Construction}
- // Parameters:
- // pszType - The class name of the most-derived class, used only for
- // diagnostic purposes. This parameter only exists under _DEBUG builds
- TCComPropertyClassRoot::TCComPropertyClassRoot(LPCSTR pszType)
- : m_nLoadingRefs(0), m_nSavingRefs(0), m_bRequiresSave(FALSE),
- m_pszType(pszType)
- {
- }
- #endif // _DEBUG
- #ifndef _DEBUG
- TCComPropertyClassRoot::TCComPropertyClassRoot()
- : m_nLoadingRefs(0), m_nSavingRefs(0), m_bRequiresSave(FALSE)
- {
- }
- #endif // !_DEBUG
- /////////////////////////////////////////////////////////////////////////////
- // Group=Attributes
- /////////////////////////////////////////////////////////////////////////////
- // Description: Sets or clears the object's dirty flag.
- //
- // Sets or clears the object's dirty flag.
- //
- // Parameters:
- // bDirty - *TRUE* to set the object's dirty flag, *FALSE* to clear it.
- //
- // See Also: TCComPropertyClassRoot::GetDirty,
- // TCComPropertyClassRoot::m_bRequiresSave
- void TCComPropertyClassRoot::SetDirty(BOOL bDirty)
- {
- m_bRequiresSave = 0 != bDirty;
- }
- /////////////////////////////////////////////////////////////////////////////
- // Description: Gets the current state of the object's dirty flag.
- //
- // Gets the current state of the object's dirty flag.
- //
- // Return Value: *TRUE* if the object needs to be saved, otherwise *FALSE*.
- //
- // See Also: TCComPropertyClassRoot::SetDirty,
- // TCComPropertyClassRoot::m_bRequiresSave
- BOOL TCComPropertyClassRoot::GetDirty() const
- {
- return m_bRequiresSave ? TRUE : FALSE;
- }
- /////////////////////////////////////////////////////////////////////////////
- // Description: Returns the object's current persistence load state.
- //
- // Determines if the object is currently being loaded from a persistence
- // mechanism.
- //
- // Return Value: *true* if the object is being loaded from a persistence
- // mechanism, otherwise *false*.
- //
- // See Also: TCComPropertyClassRoot::SetLoading,
- // TCComPropertyClassRoot::IsSaving, TCComPropertyClassRoot::CLoadSaveScope
- bool TCComPropertyClassRoot::IsLoading()
- {
- return m_nLoadingRefs != 0;
- }
- /////////////////////////////////////////////////////////////////////////////
- // Description: Sets or clears the object's current persistence load state.
- //
- // Sets or clears the object's current persistence state. Actually, since
- // loading from a persistence mechanism may be nested into several levels,
- // this method only increments or decrements a reference count of load
- // operations. Typically, this method is only used internally by the
- // TCComPropertyClassRoot::CLoadSaveScope class. Usually, there is no reason
- // to call it directly.
- //
- // Parameters:
- // bLoading - *true* specifies that a persistence load operation is about
- // to be entered; *false* indicates that such an operation is finished.
- //
- // See Also: TCComPropertyClassRoot::IsLoading,
- // TCComPropertyClassRoot::SetSaving, TCComPropertyClassRoot::CLoadSaveScope
- void TCComPropertyClassRoot::SetLoading(bool bLoading)
- {
- if (bLoading)
- InterlockedIncrement(&m_nLoadingRefs);
- else
- InterlockedDecrement(&m_nLoadingRefs);
- }
- /////////////////////////////////////////////////////////////////////////////
- // Description: Returns the object's current persistence save state.
- //
- // Determines if the object is currently being saved to a persistence
- // mechanism.
- //
- // Return Value: *true* if the object is being saved to a persistence
- // mechanism, otherwise *false*.
- //
- // See Also: TCComPropertyClassRoot::SetSaving,
- // TCComPropertyClassRoot::IsLoading, TCComPropertyClassRoot::CLoadSaveScope
- bool TCComPropertyClassRoot::IsSaving()
- {
- return m_nSavingRefs != 0;
- }
- /////////////////////////////////////////////////////////////////////////////
- // Description: Sets or clears the object's current persistence save state.
- //
- // Sets or clears the object's current persistence state. Actually, since
- // saving to a persistence mechanism may be nested into several levels,
- // this method only increments or decrements a reference count of save
- // operations. Typically, this method is only used internally by the
- // TCComPropertyClassRoot::CLoadSaveScope class. Usually, there is no reason
- // to call it directly.
- //
- // Parameters:
- // bSaving - *true* specifies that a persistence save operation is about to
- // be entered; *false* indicates that such an operation is finished.
- //
- // See Also: TCComPropertyClassRoot::IsSaving,
- // TCComPropertyClassRoot::SetLoading, TCComPropertyClassRoot::CLoadSaveScope
- void TCComPropertyClassRoot::SetSaving(bool bSaving)
- {
- if (bSaving)
- InterlockedIncrement(&m_nSavingRefs);
- else
- InterlockedDecrement(&m_nSavingRefs);
- }
- /////////////////////////////////////////////////////////////////////////////
- // Group=Implementation
- /////////////////////////////////////////////////////////////////////////////
- // Description: Implementation of *IPersistStreamInit::Load*.
- //
- // Initializes an object from the stream where it was previously saved.
- //
- // Note: The *ATL::IPersistStreamInitImpl* class uses this method for its
- // implementation of *IPersistStreamInit::Load*.
- //
- // Parameters:
- // pStm - [in] *IStream* pointer to the stream from which the object should
- // be loaded.
- // pMap - [in] Pointer to the first element of an array of
- // *ATL_PROPMAP_ENTRY* structures, as defined by the ATL property map macros.
- //
- // Return Value:
- //
- // S_OK - The object was successfully loaded.
- // E_OUTOFMEMORY - The object was not loaded due to a lack of memory.
- // E_FAIL - The object was not loaded due to some reason other than a lack
- // of memory.
- //
- // See Also: TCComPropertyClass, *ATL::IPersistStreamInitImpl* „
- HRESULT TCComPropertyClassRoot::TCPersistStreamInit_Load(LPSTREAM pStm,
- ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk)
- {
- // Enter the Loading mode for this scope
- CLoadSaveScope loading(this);
- assert(pMap != NULL);
- HRESULT hr = S_OK;
- DWORD dwVer;
- hr = pStm->Read(&dwVer, sizeof(DWORD), NULL);
- if (dwVer > _ATL_VER)
- return E_FAIL;
- if (FAILED(hr))
- return hr;
- CComPtr<IDispatch> pDispatch;
- const IID* piidOld = NULL;
- for(int i = 0; pMap[i].pclsidPropPage != NULL; i++)
- {
- if (pMap[i].szDesc == NULL)
- continue;
- // check if raw data entry
- if (pMap[i].dwSizeData != 0)
- {
- void* pData = (void*) (pMap[i].dwOffsetData + (DWORD)pThis);
- hr = pStm->Read(pData, pMap[i].dwSizeData, NULL);
- if (FAILED(hr))
- return hr;
- continue;
- }
- CComVariant var;
- // Handle safe arrays seperately from general VARTYPE's
- if (S_FALSE == (hr = TCReadSafeArrayFromStream(pStm, var)))
- hr = var.ReadFromStream(pStm);
- if (FAILED(hr))
- break;
- if(pMap[i].piidDispatch != piidOld)
- {
- pDispatch.Release();
- if(FAILED(pUnk->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
- {
- _TRACE_BEGIN
- _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
- _TRACE_PART0("IPersistStreamInit_Load(): Failed to get a dispatch ");
- _TRACE_PART2("pointer for property #%i, \"%ls\"\n", i, pMap[i].szDesc);
- _TRACE_END
- hr = E_FAIL;
- break;
- }
- piidOld = pMap[i].piidDispatch;
- }
- if (FAILED(CComDispatchDriver::PutProperty(pDispatch, pMap[i].dispid, &var)))
- {
- _TRACE_BEGIN
- _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
- _TRACE_PART0("IPersistStreamInit_Load(): Invoke failed on DISPID ");
- _TRACE_PART2("0x%x, \"%ls\"\n", pMap[i].dispid, pMap[i].szDesc);
- _TRACE_END
- hr = E_FAIL;
- break;
- }
- }
- return hr;
- }
- /////////////////////////////////////////////////////////////////////////////
- // Description: Implementation of *IPersistStreamInit::Save*.
- //
- // Saves an object to the specified stream.
- //
- // Note: The *ATL::IPersistStreamInitImpl* class uses this method for its
- // implementation of *IPersistStreamInit::Save*.
- //
- // Parameters:
- // pStm - [in] *IStream* pointer to the stream into which the object should
- // be saved.
- // fClearDirty - [in] Indicates whether to clear the dirty flag after the
- // save is complete. If *TRUE*, the flag should be cleared. If *FALSE*, the
- // flag should be left unchanged.
- // pMap - [in] Pointer to the first element of an array of
- // *ATL_PROPMAP_ENTRY* structures, as defined by the ATL property map macros.
- //
- // Return Value:
- //
- // S_OK - The object was successfully saved to the stream.
- // STG_E_CANTSAVE - The object could not save itself to the stream. This
- // error could indicate, for example, that the object contains another object
- // that is not serializable to a stream or that an
- // *ISequentialStream::Write* call returned *STG_E_CANTSAVE*.
- // STG_E_MEDIUMFULL - The object could not be saved because there is no
- // space left on the storage device.
- //
- // See Also: TCComPropertyClass, *ATL::IPersistStreamInitImpl* „
- HRESULT TCComPropertyClassRoot::TCPersistStreamInit_Save(LPSTREAM pStm,
- BOOL fClearDirty, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk)
- {
- // Enter the Saving mode for this scope
- CLoadSaveScope saving(this, false);
- assert(pMap != NULL);
- DWORD dw = _ATL_VER;
- HRESULT hr = pStm->Write(&dw, sizeof(DWORD), NULL);
- if (FAILED(hr))
- return hr;
- CComPtr<IDispatch> pDispatch;
- const IID* piidOld = NULL;
- for(int i = 0; pMap[i].pclsidPropPage != NULL; i++)
- {
- if (pMap[i].szDesc == NULL)
- continue;
- // check if raw data entry
- if (pMap[i].dwSizeData != 0)
- {
- void* pData = (void*) (pMap[i].dwOffsetData + (DWORD)pThis);
- hr = pStm->Write(pData, pMap[i].dwSizeData, NULL);
- if (FAILED(hr))
- return hr;
- continue;
- }
- CComVariant var;
- if(pMap[i].piidDispatch != piidOld)
- {
- pDispatch.Release();
- if(FAILED(pUnk->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
- {
- _TRACE_BEGIN
- _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
- _TRACE_PART0("IPersistStreamInit_Save(): Failed to get a dispatch ");
- _TRACE_PART2("pointer for property #%i, \"%ls\"\n", i, pMap[i].szDesc);
- _TRACE_END
- hr = E_FAIL;
- break;
- }
- piidOld = pMap[i].piidDispatch;
- }
- if (FAILED(CComDispatchDriver::GetProperty(pDispatch, pMap[i].dispid, &var)))
- {
- _TRACE_BEGIN
- _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
- _TRACE_PART0("IPersistStreamInit_Save(): Invoke failed on DISPID ");
- _TRACE_PART2("0x%x, \"%ls\"\n", pMap[i].dispid, pMap[i].szDesc);
- _TRACE_END
- hr = E_FAIL;
- break;
- }
- // Handle safe arrays seperately from general VARTYPE's
- if (S_FALSE == (hr = TCWriteSafeArrayToStream(pStm, var)))
- hr = var.WriteToStream(pStm);
- if (FAILED(hr))
- break;
- }
- if (SUCCEEDED(hr) && fClearDirty)
- SetDirty(FALSE);
- return hr;
- }
- /////////////////////////////////////////////////////////////////////////////
- // Description: Implementation of *IPersistPropertyBag::Load*.
- //
- // This method instructs the object to initialize itself using the properties
- // available in the property bag, notifying the provided error log object
- // when errors occur. All property storage must take place within this method
- // call as the object cannot hold the IPropertyBag pointer.
- //
- // *E_NOTIMPL* is not a valid return code as any object implementing this
- // interface must support the entire functionality of the interface.
- //
- // Note: The *ATL::IPersistPropertyBagImpl* class uses this method for its
- // implementation of *IPersistPropertyBag::Load*.
- //
- // Parameters:
- // pPropBag - [in] Pointer to the caller's *IPropertyBag* interface bag
- // that the object uses to read its properties. Cannot be *NULL*.
- // pErrorLog - [in] Pointer to the caller's *IErrorLog* interface in which
- // the object stores any errors that occur during initialization. Can be
- // *NULL* in which case the caller is not interested in errors.
- // pMap - [in] Pointer to the first element of an array of
- // *ATL_PROPMAP_ENTRY* structures, as defined by the ATL property map macros.
- //
- // Return Value:
- //
- // S_OK - The object successfully initialized itself.
- // E_UNEXPECTED - This method was called after
- // *IPersistPropertyBag::InitNew* has already been called. The two
- // initialization methods are mutually exclusive.
- // E_OUTOFMEMORY - The properties were not loaded due to a lack of memory.
- // E_POINTER - The address in /pPropBag/ is not valid (such as *NULL*) and
- // therefore the object cannot initialize itself.
- // E_FAIL - The object was unable to retrieve a critical property that is
- // necessary for the object's successful operation. The object was therefore
- // unable to initialize itself completely.
- //
- // See Also: TCComPropertyClass, *ATL::IPersistPropertyBagImpl* „
- HRESULT TCComPropertyClassRoot::TCPersistPropertyBag_Load(
- LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog, ATL_PROPMAP_ENTRY* pMap,
- void* pThis, IUnknown* pUnk)
- {
- // Enter the Loading mode for this scope
- CLoadSaveScope loading(this);
- USES_CONVERSION;
- CComPtr<IDispatch> pDispatch;
- const IID* piidOld = NULL;
- for(int i = 0; pMap[i].pclsidPropPage != NULL; i++)
- {
- if (pMap[i].szDesc == NULL)
- continue;
- CComVariant var;
- // If raw entry, handle specially
- if (pMap[i].dwSizeData != 0)
- {
- void* pData = (void*) (pMap[i].dwOffsetData + (DWORD)pThis);
- HRESULT hr = pPropBag->Read(pMap[i].szDesc, &var, pErrorLog);
- if (SUCCEEDED(hr))
- {
- // check the type - we only deal with limited set
- switch (pMap[i].vt)
- {
- case VT_UI1:
- case VT_I1:
- *((BYTE*)pData) = var.bVal;
- break;
- case VT_BOOL:
- *((VARIANT_BOOL*)pData) = var.boolVal;
- break;
- case VT_I2: // Added by TC
- case VT_UI2:
- *((short*)pData) = var.iVal;
- break;
- case VT_I4: // Added by TC
- case VT_UI4:
- case VT_INT:
- case VT_UINT:
- *((long*)pData) = var.lVal;
- break;
- /////////////////////////////////////////////////////////////////////
- // The following all added by TC //
- case VT_R4: //
- *((float*)pData) = var.fltVal; //
- break; //
- case VT_R8: //
- *((double*)pData) = var.dblVal; //
- break; //
- case VT_CY: //
- *((CY*)pData) = var.cyVal; //
- break; //
- case VT_DATE: //
- *((DATE*)pData) = var.date; //
- break; //
- case VT_ERROR: //
- *((SCODE*)pData) = var.scode; //
- break; //
- case VT_DECIMAL: //
- *((DECIMAL*)pData) = *var.pdecVal; //
- break; //
- /////////////////////////////////////////////////////////////////////
- // TODO: Implement the following VARIANT types //
- case VT_BSTR: // Tricky: different ways to store a BSTR //
- break; //
- case VT_UNKNOWN: // Tricky: different ways to store a IUnknown* //
- case VT_DISPATCH: // Tricky: different ways to store a IDispatch*//
- continue; //
- case VT_VARIANT: // Tricky: different ways to store a VARIANT //
- continue; //
- case VT_RECORD: // Tricky: how possible? //
- continue; //
- case VT_ARRAY: // Very tricky: Also, caution: OR flag //
- continue; //
- case VT_BYREF: // Shouldn't be TOO tricky. Caution: OR flag //
- continue; //
- /////////////////////////////////////////////////////////////////////
- }
- }
- continue;
- }
- if(pMap[i].piidDispatch != piidOld)
- {
- pDispatch.Release();
- if(FAILED(pUnk->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
- {
- _TRACE_BEGIN
- _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
- _TRACE_PART0("IPersistPropertyBag_Load(): Failed to get a dispatch ");
- _TRACE_PART2("pointer for property #%i, \"%ls\"\n", i, pMap[i].szDesc);
- _TRACE_END
- return E_FAIL;
- }
- piidOld = pMap[i].piidDispatch;
- }
- if (FAILED(CComDispatchDriver::GetProperty(pDispatch, pMap[i].dispid, &var)))
- {
- _TRACE_BEGIN
- _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
- _TRACE_PART0("IPersistPropertyBag_Load(): Invoke failed on DISPID ");
- _TRACE_PART2("0x%x, \"%ls\"\n", pMap[i].dispid, pMap[i].szDesc);
- _TRACE_END
- return E_FAIL;
- }
- if (VT_DISPATCH == V_VT(&var))
- var.Clear();
- HRESULT hr = pPropBag->Read(pMap[i].szDesc, &var, pErrorLog);
- if (FAILED(hr))
- {
- if (hr == E_INVALIDARG)
- {
- _TRACE_BEGIN
- _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
- _TRACE_PART0("IPersistPropertyBag_Load(): ");
- _TRACE_PART1("Property %ls not in Bag\n", pMap[i].szDesc);
- _TRACE_END
- }
- else
- {
- // Many containers return different ERROR values for Member not found
- _TRACE_BEGIN
- _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
- _TRACE_PART0("IPersistPropertyBag_Load(): Error attempting to read ");
- _TRACE_PART1("Property %ls from PropertyBag\n", pMap[i].szDesc);
- _TRACE_END
- }
- continue;
- }
- if (FAILED(CComDispatchDriver::PutProperty(pDispatch, pMap[i].dispid, &var)))
- {
- _TRACE_BEGIN
- _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
- _TRACE_PART0("IPersistPropertyBag_Load(): Invoke failed on DISPID ");
- _TRACE_PART2("0x%x, \"%ls\"\n", pMap[i].dispid, pMap[i].szDesc);
- _TRACE_END
- return E_FAIL;
- }
- }
- return S_OK;
- }
- /////////////////////////////////////////////////////////////////////////////
- // Description: Implementation of *IPersistPropertyBag::Save*.
- //
- // This method instructs the object to save its properties to the specified
- // property bag, optionally clearing the object's dirty flag. The caller can
- // request that the object save all properties or that the object save only
- // those that are known to have changed.
- //
- // *E_NOTIMPL* is not a valid return code as any object implementing this
- // interface must support the entire functionality of the interface.
- //
- // Note: The *ATL::IPersistPropertyBagImpl* class uses this method for its
- // implementation of *IPersistPropertyBag::Save*.
- //
- // Parameters:
- // pPropBag - [in] Pointer to the caller's *IPropertyBag* interface bag
- // that the object uses to write its properties. Cannot be *NULL*.
- // fClearDirty - [in] A flag indicating whether the object should clear its
- // dirty flag when saving is complete. *TRUE* means clear the flag, *FALSE* „
- // means leave the flag unaffected. *FALSE* is used when the caller wishes to
- // do a /Save/ /Copy/ /As/ type of operation.
- // fSaveAllProperties - [in] A flag indicating whether the object should
- // save all its properties (TRUE) or only those that have changed since the
- // last save or initialization (FALSE).
- // pMap - [in] Pointer to the first element of an array of
- // *ATL_PROPMAP_ENTRY* structures, as defined by the ATL property map macros.
- //
- // Return Value:
- //
- // S_OK - The object successfully saved the requested properties itself.
- // E_FAIL - There was a problem saving one of the properties. The object can
- // choose to fail only if a necessary property could not be saved, meaning
- // that the object can assume default property values if a given property is
- // not seen through *IPersistPropertyBag::Load* at some later time.
- // E_POINTER - The address in /pPropBag/ is not valid (such as *NULL*) and
- // therefore the object cannot save itself.
- // STG_E_MEDIUMFULL - The object was not saved because of a lack of space on
- // the disk.
- //
- // See Also: TCComPropertyClass, *ATL::IPersistPropertyBagImpl* „
- HRESULT TCComPropertyClassRoot::TCPersistPropertyBag_Save(
- LPPROPERTYBAG pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties,
- ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk)
- {
- // Do nothing if saving only the dirty properties and there are none
- if (!fSaveAllProperties && !GetDirty())
- return S_OK;
- if (pPropBag == NULL)
- {
- _TRACE_BEGIN
- _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
- _TRACE_PART0("IPersistPropertyBag_Save(): ");
- _TRACE_PART0("PropBag pointer passed in was invalid\n");
- _TRACE_END
- return E_POINTER;
- }
- // Enter the Saving mode for this scope
- CLoadSaveScope saving(this, false);
- CComPtr<IDispatch> pDispatch;
- const IID* piidOld = NULL;
- for(int i = 0; pMap[i].pclsidPropPage != NULL; i++)
- {
- if (pMap[i].szDesc == NULL)
- continue;
- CComVariant var;
- // If raw entry skip it - we don't handle it for property bags just yet
- if (pMap[i].dwSizeData != 0)
- {
- void* pData = (void*) (pMap[i].dwOffsetData + (DWORD)pThis);
- // check the type - we only deal with limited set
- bool bTypeOK = false;
- switch (pMap[i].vt)
- {
- case VT_UI1:
- case VT_I1:
- var.bVal = *((BYTE*)pData);
- bTypeOK = true;
- break;
- case VT_BOOL:
- var.boolVal = *((VARIANT_BOOL*)pData);
- bTypeOK = true;
- break;
- case VT_I2: // Added by TC
- case VT_UI2:
- var.iVal = *((short*)pData);
- bTypeOK = true;
- break;
- case VT_I4: // Added by TC
- case VT_UI4:
- case VT_INT:
- case VT_UINT:
- var.lVal = *((long*)pData);
- bTypeOK = true;
- break;
- /////////////////////////////////////////////////////////////////////
- // The following all added by TC //
- case VT_R4: //
- var.fltVal = *((float*)pData); //
- bTypeOK = true; //
- break; //
- case VT_R8: //
- var.dblVal = *((double*)pData); //
- bTypeOK = true; //
- break; //
- case VT_CY: //
- var.cyVal = *((CY*)pData); //
- bTypeOK = true; //
- break; //
- case VT_DATE: //
- var.date = *((DATE*)pData); //
- bTypeOK = true; //
- break; //
- case VT_ERROR: //
- var.scode = *((SCODE*)pData); //
- bTypeOK = true; //
- break; //
- case VT_DECIMAL: //
- var.pdecVal = ((DECIMAL*)pData); //
- bTypeOK = true; //
- break; //
- /////////////////////////////////////////////////////////////////////
- // TODO: Implement the following VARIANT types //
- case VT_BSTR: // Tricky: different ways to store a BSTR //
- break; //
- case VT_UNKNOWN: // Tricky: different ways to store a IUnknown* //
- case VT_DISPATCH: // Tricky: different ways to store a IDispatch*//
- continue; //
- case VT_VARIANT: // Tricky: different ways to store a VARIANT //
- continue; //
- case VT_RECORD: // Tricky: how possible? //
- continue; //
- case VT_ARRAY: // Very tricky: Also, caution: OR flag //
- continue; //
- case VT_BYREF: // Shouldn't be TOO tricky. Caution: OR flag //
- continue; //
- /////////////////////////////////////////////////////////////////////
- }
- if (bTypeOK)
- {
- var.vt = pMap[i].vt;
- HRESULT hr = pPropBag->Write(pMap[i].szDesc, &var);
- if (FAILED(hr))
- return hr;
- }
- continue;
- }
- if(pMap[i].piidDispatch != piidOld)
- {
- pDispatch.Release();
- if(FAILED(pUnk->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
- {
- _TRACE_BEGIN
- _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
- _TRACE_PART0("IPersistPropertyBag_Save(): Failed to get a dispatch ");
- _TRACE_PART2("pointer for property #%i, \"%ls\"\n", i, pMap[i].szDesc);
- _TRACE_END
- return E_FAIL;
- }
- piidOld = pMap[i].piidDispatch;
- }
- if (FAILED(CComDispatchDriver::GetProperty(pDispatch, pMap[i].dispid, &var)))
- {
- _TRACE_BEGIN
- _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
- _TRACE_PART0("IPersistPropertyBag_Save(): Invoke failed on DISPID ");
- _TRACE_PART2("0x%x, \"%ls\"\n", pMap[i].dispid, pMap[i].szDesc);
- _TRACE_END
- return E_FAIL;
- }
- if (var.vt == VT_UNKNOWN || var.vt == VT_DISPATCH)
- {
- if (var.ppunkVal == NULL)
- {
- _TRACE_BEGIN
- _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
- _TRACE_PART0("IPersistPropertyBag_Save(): ");
- _TRACE_PART0("Warning skipping empty IUnknown in Save\n");
- _TRACE_END
- continue;
- }
- }
- HRESULT hr = pPropBag->Write(pMap[i].szDesc, &var);
- if (FAILED(hr))
- return hr;
- }
- if (fClearDirty)
- SetDirty(FALSE);
- return S_OK;
- }
- /////////////////////////////////////////////////////////////////////////////
- // Description: Implementation of *ISpecifyPropertyPages::GetPages*.
- //
- // Fills a counted array of GUID values where each GUID specifies the CLSID
- // of each property page that can be displayed in the property sheet for this
- // object.
- //
- // Note: The *ATL::ISpecifyPropertyPagesImpl* class uses this method for its
- // implementation of *ISpecifyPropertyPages::GetPages*.
- //
- // Parameters:
- // pPages - [out] Pointer to a caller-allocated *CAUUID* structure that must
- // be initialized and filled before returning. The /pElems/ field in the
- // *CAUUID* structure is allocated by the callee with *CoTaskMemAlloc* and
- // freed by the caller with *CoTaskMemFree*.
- // pMap - [in] Pointer to the first element of an array of
- // *ATL_PROPMAP_ENTRY* structures, as defined by the ATL property map macros.
- //
- // Return Value: This method supports the standard return values
- // *E_OUTOFMEMORY* and *E_UNEXPECTED*, as well as the following:
- //
- // S_OK - The array was filled successfully.
- // E_POINTER - The address in /pPages/ is not valid. For example, it may be
- // *NULL*.
- //
- // See Also: TCComPropertyClass, *ATL::ISpecifyPropertyPagesImpl* „
- HRESULT TCComPropertyClassRoot::ISpecifyPropertyPages_GetPages(
- CAUUID* pPages, ATL_PROPMAP_ENTRY* pMap)
- {
- assert(pMap != NULL);
- int nCnt = 0;
- // Get count of unique pages
- for(int i = 0; pMap[i].pclsidPropPage != NULL; i++)
- {
- if (!InlineIsEqualGUID(*pMap[i].pclsidPropPage, CLSID_NULL))
- nCnt++;
- }
- pPages->pElems = NULL;
- pPages->pElems = (GUID*) CoTaskMemAlloc(sizeof(CLSID)*nCnt);
- if (pPages->pElems == NULL)
- return E_OUTOFMEMORY;
- nCnt = 0;
- for(i = 0; pMap[i].pclsidPropPage != NULL; i++)
- {
- if (!InlineIsEqualGUID(*pMap[i].pclsidPropPage, CLSID_NULL))
- {
- BOOL bMatch = FALSE;
- for (int j=0;j<nCnt;j++)
- {
- if (InlineIsEqualGUID(*(pMap[i].pclsidPropPage), pPages->pElems[j]))
- {
- bMatch = TRUE;
- break;
- }
- }
- if (!bMatch)
- pPages->pElems[nCnt++] = *pMap[i].pclsidPropPage;
- }
- }
- pPages->cElems = nCnt;
- return S_OK;
- }
- /////////////////////////////////////////////////////////////////////////////
- // Group=
- /////////////////////////////////////////////////////////////////////////////
- // Global Implementation
- #ifdef _ATL
- ///////////////////////////////////////////////////////////////////////////
- // Description: Compares a *CComVariant* to a *VARIANT*.
- //
- // Since CComVariant::operator== does not compare arrays of *BSTR*'s, this
- // function was developed to first check for the variant type
- // *VT_ARRAY*|*VT_BSTR*. If both parameters are of that variant type,
- // the elements of the first dimension of the string array are compared.
- // Otherwise, processing is delegated to CComVariant::operator==.
- //
- // Parameters:
- // dest - A reference to the *CComVariant* on the left-hand side of the
- // comparison.
- // src - A reference to the *VARIANT* on the right-hand side of the
- // comparison.
- //
- // Return Value: *true* if the arguments are equal, otherwise *false*.
- //
- // See Also: TCComPropertyCompare, TCComPropertyPut
- bool TCComVariantCompare(CComVariant& dest, VARIANT& src)
- {
- // Check for (some) types that CComVariant::operator== doesnt' handle
- VARTYPE vtDest = V_VT(&dest);
- VARTYPE vtSrc = V_VT(&src);
-
- // Array of ...
- if ((VT_ARRAY & vtDest) && (VT_ARRAY & vtSrc))
- {
- // Check equal element size
- SAFEARRAY* psaDest = V_ARRAY(&dest);
- SAFEARRAY* psaSrc = V_ARRAY(&src);
- if (psaDest->cbElements != psaSrc->cbElements)
- return false;
- // Strip off array flag and check to see if BSTR's
- vtDest &= ~VT_ARRAY;
- vtSrc &= ~VT_ARRAY;
- if (VT_BSTR == vtDest && VT_BSTR == vtSrc)
- {
- // Check array bounds for match
- LONG lLBoundDest, lUBoundDest;
- LONG lLBoundSrc, lUBoundSrc;
- // Upper, most likely to be different
- if (FAILED(SafeArrayGetUBound(psaDest, 1, &lUBoundDest)))
- return false;
- if (FAILED(SafeArrayGetUBound(psaSrc, 1, &lUBoundSrc)))
- return false;
- if (lUBoundDest != lUBoundSrc)
- return false;
- // Check the lower too
- if (FAILED(SafeArrayGetLBound(psaDest, 1, &lLBoundDest)))
- return false;
- if (FAILED(SafeArrayGetLBound(psaSrc, 1, &lLBoundSrc)))
- return false;
- if (lLBoundDest != lLBoundSrc)
- return false;
- // Compute the elements size, equal if no elements
- LONG cElements = lUBoundDest - lLBoundDest + 1;
- if (!cElements)
- return true;
- // Get pointers to the elements of the arrays
- BSTR *pbstrDest,*pbstrSrc;
- if (FAILED(SafeArrayAccessData(psaDest, (void**)&pbstrDest)))
- return false;
- if (FAILED(SafeArrayAccessData(psaSrc, (void**)&pbstrSrc)))
- {
- _VERIFYE(SUCCEEDED(SafeArrayUnaccessData(psaDest)));
- return false;
- }
- // Loop through all elements and check for difference
- bool bSame = true;
- __try
- {
- // See if the strings are the same
- for (int i = 0; i < cElements && bSame; i++)
- {
- // Check for NULL pointers
- if (!pbstrDest[i] || !pbstrSrc[i])
- {
- bSame = pbstrDest[i] == pbstrSrc[i];
- continue;
- }
- // Get string lengths
- UINT nLenDest = SysStringLen(pbstrDest[i]);
- UINT nLenSrc = SysStringLen(pbstrSrc[i]);
- // Compare lengths and contents
- if (nLenDest != nLenSrc || wcscmp(pbstrDest[i], pbstrSrc[i]))
- bSame = false;
- }
- }
- __except(1)
- {
- _TRACE_BEGIN
- _TRACE_PART0("TCComPropertyCompare(): Caught an unknown exception ");
- _TRACE_PART0("(probably an invalid pointer was specified)");
- _TRACE_END
- bSame = false;
- }
- // Release access to the array elements
- _VERIFYE(SUCCEEDED(SafeArrayUnaccessData(psaDest)));
- _VERIFYE(SUCCEEDED(SafeArrayUnaccessData(psaSrc)));
- return bSame;
- }
- }
- // Default to CComVariant::operator==
- return dest == src;
- }
- #endif // _ATL
- /////////////////////////////////////////////////////////////////////////////
- #endif // !__PropertyClass_cpp__
|