windows-nt/Source/XPSP1/NT/admin/activec/nodemgr/siprop.cpp
2020-09-26 16:20:57 +08:00

1072 lines
31 KiB
C++

/*--------------------------------------------------------------------------*
*
* Microsoft Windows
* Copyright (C) Microsoft Corporation, 1992 - 1999
*
* File: siprop.cpp
*
* Contents: Implementation file for CSnapInPropertiesRoot, et al
*
* History: 04-Nov-99 jeffro Created
*
*--------------------------------------------------------------------------*/
#include "stdafx.h"
#include "siprop.h"
#include "variant.h"
#include "mtnode.h"
#ifdef DBG
CTraceTag tagSnapInProps(_T("Snap-in Properties"), _T("Snap-in Properties"));
#endif
/*+=========================================================================*/
/* */
/* CSnapinPropertyComObject */
/* */
/*==========================================================================*/
/*+-------------------------------------------------------------------------*
* CSnapinPropertyComObject
*
* This is the COM object that exposes the Property object model interface.
*--------------------------------------------------------------------------*/
class CSnapinPropertyComObject :
public CMMCIDispatchImpl<Property>, // the Property interface
public CTiedComObject<CSnapinProperties>
{
typedef CSnapinProperties CMyTiedObject;
public:
BEGIN_MMC_COM_MAP(CSnapinPropertyComObject)
END_MMC_COM_MAP()
public:
// Property interface
MMC_METHOD1_PARAM (get_Value, VARIANT* /*pvarValue*/, m_key);
MMC_METHOD1_PARAM (put_Value, VARIANT /*varValue*/, m_key);
STDMETHODIMP get_Name (BSTR* pbstrName)
{
DECLARE_SC (sc, _T("CSnapinPropertyComObject::get_Name"));
/*
* validate parameters
*/
sc = ScCheckPointers (pbstrName);
if (sc)
return (sc.ToHr());
/*
* copy the name
*/
*pbstrName = SysAllocString (m_key.data());
if (*pbstrName == NULL)
return ((sc = E_OUTOFMEMORY).ToHr());
return (sc.ToHr());
}
void SetKey (const CSnapinProperties::CPropertyKey& key)
{ m_key = key; }
private:
CSnapinProperties::CPropertyKey m_key;
};
/*+=========================================================================*/
/* */
/* CSnapinProperties implementation */
/* */
/*==========================================================================*/
/*+-------------------------------------------------------------------------*
* CSnapinProperties::FromInterface
*
* Returns a pointer to the CSnapinProperties object that implements
* the given interface, or NULL if the implementing object is not a
* CSnapinProperties.
*--------------------------------------------------------------------------*/
CSnapinProperties* CSnapinProperties::FromInterface (IUnknown* pUnk)
{
CSnapinProperties* pProps;
/*
* dynamic_cast will throw if pUnk is junk (i.e. not a real interface
* pointer and not NULL), so do it in an exception frame.
*/
try
{
pProps = dynamic_cast<CSnapinProperties*>(pUnk);
}
catch (...)
{
pProps = NULL;
}
return (pProps);
}
/*+-------------------------------------------------------------------------*
* CSnapinProperties::Item
*
* Returns an interface to a property identified by bstrName, which must
* be released by the caller. If the collection doesn't contain a property
* with the given name, a new property with the given name (initialized to
* VT_EMPTY) is added to the collection.
*
* Returns:
* S_OK the property was successfully returned
* S_FALSE the property was successfully returned, but didn't
* exist in the collection beforehand, so a new one
* was added
* E_INVALIDARG the property name wasn't valid (i.e. empty) or
* ppProperty was NULL
* E_OUTOFMEMORY not enough memory to perform the operation
* E_UNEXPECTED something dire happened
*--------------------------------------------------------------------------*/
STDMETHODIMP CSnapinProperties::Item (
BSTR bstrName, /* I:name of property to get */
PPPROPERTY ppProperty) /* O:interface to property */
{
DECLARE_SC (sc, _T("CSnapinProperties::Item"));
/*
* validate the parameters
*/
sc = ScCheckPointers (bstrName, ppProperty);
if (sc)
return (sc.ToHr());
const std::wstring strName = bstrName;
if (strName.empty())
return ((sc = E_INVALIDARG).ToHr());
bool fPropWasAdded = false;
/*
* Look up the property. If it's not there yet, add a new one (maybe).
*/
if (m_PropMap.find(strName) == m_PropMap.end())
{
/*
* Fail without implicitly adding if we're not attached to a snap-in.
* This will prevent us from adding properties that weren't
* registered with AddPropertyName
*/
if (m_spSnapinProps != NULL)
return ((sc = ScFromMMC(MMC_E_UnrecognizedProperty)).ToHr());
/*
* put an empty property in the map with the given name
*/
m_PropMap[strName] = CSnapinProperty();
fPropWasAdded = true;
}
/*
* get a COM object tied to the new property
*/
sc = ScGetPropertyComObject (strName, *ppProperty);
if (sc)
return (sc.ToHr());
if (*ppProperty == NULL)
return ((sc = E_UNEXPECTED).ToHr());
/*
* if we had to add the property, return S_FALSE so the caller can
* tell (if he cares)
*/
if (fPropWasAdded)
sc = S_FALSE;
return (sc.ToHr());
}
/*+-------------------------------------------------------------------------*
* CSnapinProperties::get_Count
*
* Returns the number of properties in the collection in *pCount.
*
* Returns:
*
* S_OK success
* E_INVALIDARG pCount is NULL
*--------------------------------------------------------------------------*/
STDMETHODIMP CSnapinProperties::get_Count (
PLONG pCount) /* O:number of items in the collection */
{
DECLARE_SC (sc, _T("CSnapinProperties::get_Count"));
/*
* validate the parameters
*/
sc = ScCheckPointers (pCount);
if (sc)
return (sc.ToHr());
/*
* return the number of elements in the property map
*/
*pCount = m_PropMap.size();
return (sc.ToHr());
}
/*+-------------------------------------------------------------------------*
* CSnapinProperties::Remove
*
* Removes a property from the collection.
*
* Returns:
* S_OK the property was successfully removed
* S_FALSE the property didn't exist in the collection
* E_INVALIDARG the property name wasn't valid (i.e. empty)
* E_UNEXPECTED something dire happened
*--------------------------------------------------------------------------*/
STDMETHODIMP CSnapinProperties::Remove (
BSTR bstrName) /* I:name of property to remove */
{
DECLARE_SC (sc, _T("CSnapinProperties::Remove"));
Trace (tagSnapInProps, _T("Snap-in Properties"));
/*
* validate the parameters
*/
sc = ScCheckPointers (bstrName);
if (sc)
return (sc.ToHr());
/*
* find the item to remove
*/
CPropertyIterator itProp = m_PropMap.find (bstrName);
if (itProp == m_PropMap.end())
return ((sc = S_FALSE).ToHr());
/*
* see if we can remove it
*/
if ( itProp->second.IsInitialized() &&
(itProp->second.GetFlags() & MMC_PROP_REMOVABLE) == 0)
return ((sc = ScFromMMC(MMC_E_CannotRemoveProperty)).ToHr());
/*
* Inform snapin before we remove the property about removal.
*/
sc = ScNotifyPropertyChange(itProp, itProp->second.GetValue(), MMC_PROPACT_DELETING);
if (sc)
return sc.ToHr();
/*
* the snap-in approved the change, remove the property
*/
m_PropMap.erase (itProp);
return (sc.ToHr());
}
/*+-------------------------------------------------------------------------*
*
* CSnapinProperties::ScEnumNext
*
* PURPOSE: Returns the next Property interface.
*
* PARAMETERS:
* _Position & key :
* PDISPATCH & pDispatch :
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC CSnapinProperties::ScEnumNext (CPropertyKey &key, PDISPATCH & pDispatch)
{
DECLARE_SC (sc, _T("CSnapinProperties::ScEnumNext"));
Trace (tagSnapInProps, _T("Snap-in Properties"));
/*
* get the next element
*/
CPropertyIterator it = IteratorFromKey (key, false);
if(it == m_PropMap.end())
return (sc = S_FALSE); // out of elements.
/*
* get the Properties COM object for this property
*/
PropertyPtr spProperty;
sc = ScGetPropertyComObject (it->first, *&spProperty);
if (sc)
return (sc);
if (spProperty == NULL)
return (sc = E_UNEXPECTED);
/*
* return the IDispatch for the object and leave a ref on it for the client
*/
pDispatch = spProperty.Detach();
// remember the enumeration key for next time
key = it->first;
return (sc);
}
/*+-------------------------------------------------------------------------*
* CSnapinProperties::ScEnumSkip
*
* Skips the next celt elements in the properties collection.
*--------------------------------------------------------------------------*/
SC CSnapinProperties::ScEnumSkip (
unsigned long celt, /* I:number of items to skip */
unsigned long& celtSkipped, /* O:number of items skipped */
CPropertyKey& key) /* I/O:enumeration key */
{
DECLARE_SC (sc, _T("CSnapinProperties::ScEnumSkip"));
Trace (tagSnapInProps, _T("Snap-in Properties"));
/*
* skip the next celt properties
*/
CPropertyIterator it = IteratorFromKey (key, false);
for (celtSkipped = 0;
(celtSkipped < celt) && (it != m_PropMap.end());
++celtSkipped, ++it)
{
/*
* remember the enumeration key for next time
*/
key = it->first;
}
/*
* if we advanced less than the requested number, return S_FALSE
*/
if (celtSkipped < celt)
sc = S_FALSE;
return (sc);
}
/*+-------------------------------------------------------------------------*
* CSnapinProperties::ScEnumReset
*
* Resets a CPropertyKey so that the next item it will return is the
* first item in the properties collection.
*--------------------------------------------------------------------------*/
SC CSnapinProperties::ScEnumReset (
CPropertyKey& key) /* I/O:enumeration key to reset */
{
DECLARE_SC (sc, _T("CSnapinProperties::ScEnumReset"));
key.erase();
return (sc);
}
/*+-------------------------------------------------------------------------*
* CSnapinProperties::get__NewEnum
*
* Creates returns an interface that can be queried for IEnumVARIANT
*--------------------------------------------------------------------------*/
STDMETHODIMP CSnapinProperties::get__NewEnum (IUnknown** ppUnk)
{
DECLARE_SC (sc, _T("CSnapinProperties::get__NewEnum"));
Trace (tagSnapInProps, _T("Snap-in Properties"));
// validate the parameter
sc = ScCheckPointers (ppUnk);
if (sc)
return (sc.ToHr());
*ppUnk = NULL;
// typedef the enumerator
typedef CComObject<CMMCEnumerator<CSnapinProperties, CPropertyKey> > CEnumerator;
// create an instance of the enumerator
CEnumerator *pEnum = NULL;
sc = CEnumerator::CreateInstance (&pEnum);
if (sc)
return (sc.ToHr());
if(!pEnum)
return ((sc = E_UNEXPECTED).ToHr());
// create a connection between the enumerator and ourselves
sc = ScCreateConnection(*pEnum, *this);
if(sc)
return (sc.ToHr());
// initialize the position using the Reset function
sc = ScEnumReset (pEnum->m_position);
if(sc)
return (sc.ToHr());
// get the IUnknown to return
sc = pEnum->QueryInterface (IID_IUnknown, (void**) ppUnk);
if (sc)
return (sc.ToHr());
return (sc.ToHr());
}
/*+-------------------------------------------------------------------------*
* CSnapinProperties::IteratorFromKey
*
* Returns the iterator in the property map corresponding to the first
* element following the one designated by key.
*
* The caller might be interested in an exact match or the nearest match.
* The nearest match would be suitable when the key is used in an
* enumeration. Let's say that the collection consists of "Alpha", "Bravo",
* and "Charlie". The first request for an item will return "Alpha" and
* the key will hold "Alpha" (see comments for CPropertyKey). Let's
* assume that "Alpha" is removed from the collection and then the enumeration
* continues. We want to return the one after the last one we got back
* ("Alpha") which would be "Bravo". All is well.
*
* An exact match would be required when trying to find a CSnapinProperty
* for a CSnapinPropertyComObject. The COM object will refer to a specific
* property, which we want to be sure to find every time. A close match
* isn't sufficient.
*--------------------------------------------------------------------------*/
CSnapinProperties::CPropertyIterator
CSnapinProperties::IteratorFromKey (
const CPropertyKey& key, /* I:key to convert */
bool fExactMatch) /* I:match key exactly? */
{
CPropertyIterator it;
/*
* need an exact match?
*/
if (fExactMatch)
{
/*
* nothing matches an empty key
*/
if (key.empty())
it = m_PropMap.end();
/*
* the key's not empty, look up the property
*/
else
it = m_PropMap.find (key);
}
/*
* nearest match
*/
else
{
/*
* the beginning of the map is nearest an empty key
*/
if (key.empty())
it = m_PropMap.begin();
/*
* otherwise, find the nearest one greater than the key
*/
else
it = m_PropMap.upper_bound (key);
}
return (it);
}
/*+-------------------------------------------------------------------------*
* CSnapinProperties::ScInitialize
*
* Initializes a CSnapinProperties. This function will return an error if
* psip is NULL, or if there's an error copying the initial properties.
*--------------------------------------------------------------------------*/
SC CSnapinProperties::ScInitialize (
ISnapinProperties* psip, /* I:snap-in's ISnapinProperties iface */
Properties* pInitProps_, /* I:initial properties for the snap-in */
CMTSnapInNode* pMTSnapInNode) /* I:snap-in these properties belong to */
{
DECLARE_SC (sc, _T("CSnapinProperties::ScInitialize"));
/*
* validate the parameters
*/
sc = ScCheckPointers (psip);
if (sc)
return (sc);
/*
* pInitProps_ is optional, but if it was given, it should be the
* one implemented by CSnapinProperties
*/
CSnapinProperties* pInitProps = FromInterface (pInitProps_);
if ((pInitProps_ != NULL) && (pInitProps == NULL))
return (sc = E_INVALIDARG);
/*
* keep the the snap-in and the snap-in's interface
*/
m_pMTSnapInNode = pMTSnapInNode;
m_spSnapinProps = psip;
/*
* get the names of the properties recognized by the snap-in
*/
sc = psip->QueryPropertyNames (this);
if (sc)
return (sc);
/*
* If we're reloading a snap-in's properties from the console file,
* weed out entries that the snap-in registered last time but didn't
* register this time.
*/
if (pInitProps == this)
{
CPropertyIterator itProp = m_PropMap.begin();
while (itProp != m_PropMap.end())
{
/*
* snap-in registered? keep it
*/
if (itProp->second.IsRegisteredBySnapin())
++itProp;
/*
* snap-in didn't register, toss it
*/
else
itProp = m_PropMap.erase (itProp);
}
}
/*
* Otherwise, if we got initial properties, find each property
* that the snap-in registered in set of initial properties and
* copy them to the snap-in's collection.
*/
else if (pInitProps != NULL)
{
sc = ScMergeProperties (*pInitProps);
if (sc)
return (sc);
}
/*
* initialize the ISnapinProperties interface
*/
sc = psip->Initialize (this);
if (sc)
return (sc);
/*
* give the ISnapinProperties its initial property values
*/
if (!m_PropMap.empty())
{
/*
* Build an array of CSmartProperty objects to pass to
* ISnapinProperties::PropertiesChanged. CSmartProperty objects
* look just like MMC_SNAPIN_PROPERTY structures, but use a
* CComVariant instead of VARIANT for automatic resource management.
* See the definition of CSmartProperty.
*/
CAutoArrayPtr<CSmartProperty> spInitialProps (
new (std::nothrow) CSmartProperty[m_PropMap.size()]);
if (spInitialProps == NULL)
return (sc = E_OUTOFMEMORY);
CPropertyIterator it = m_PropMap.begin();
for (int i = 0; it != m_PropMap.end(); ++it, ++i)
{
spInitialProps[i].pszPropName = it->first.data();
spInitialProps[i].varValue = it->second.GetValue();
spInitialProps[i].eAction = MMC_PROPACT_INITIALIZED;
}
/*
* we don't want to trace a failure here, so use a local SC
*/
SC scLocal = ScNotifyPropertyChange (spInitialProps, m_PropMap.size());
if (scLocal)
return (scLocal);
}
return (sc);
}
/*+-------------------------------------------------------------------------*
* CSnapinProperties::ScSetSnapInNode
*
* Attaches this properties collection to a CMTSnapInNode.
*--------------------------------------------------------------------------*/
SC CSnapinProperties::ScSetSnapInNode (CMTSnapInNode* pMTSnapInNode)
{
DECLARE_SC (sc, _T("CSnapinProperties::ScSetSnapInNode"));
m_pMTSnapInNode = pMTSnapInNode;
return (sc);
}
/*+-------------------------------------------------------------------------*
* CSnapinProperties::ScMergeProperties
*
* Merges the properties from another property collection into this one.
* Only properties that already exist in the destination collection are
* copied from the source.
*--------------------------------------------------------------------------*/
SC CSnapinProperties::ScMergeProperties (const CSnapinProperties& other)
{
DECLARE_SC (sc, _T("CSnapinProperties::ScMergeProperties"));
/*
* for each property in the other collection...
*/
CConstPropertyIterator itOtherProp;
for (itOtherProp = other.m_PropMap.begin();
(itOtherProp != other.m_PropMap.end()) && !sc.IsError();
++itOtherProp)
{
/*
* look for a corresponding property in the our set
*/
CPropertyIterator itProp = m_PropMap.find (itOtherProp->first);
/*
* if it's in our set, copy its value
*/
if (itProp != m_PropMap.end())
sc = itProp->second.ScSetValue (itOtherProp->second.GetValue());
}
return (sc);
}
/*+-------------------------------------------------------------------------*
* CSnapinProperties::AddPropertyName
*
* This method is called by the snap-in from its implementation of
* ISnapinProperties::QueryPropertyNames to register the properties it
* recognizes.
*--------------------------------------------------------------------------*/
STDMETHODIMP CSnapinProperties::AddPropertyName (
LPCOLESTR pszPropName, /* I:property name */
DWORD dwFlags) /* I:flags for this property */
{
DECLARE_SC (sc, _T("CSnapinProperties::AddPropertyName"));
/*
* validate the parameters
*/
sc = ScCheckPointers (pszPropName);
if (sc)
return (sc.ToHr());
const std::wstring strName = pszPropName;
if (strName.empty())
return ((sc = E_INVALIDARG).ToHr());
/*
* make sure no undocumented flags were passed in
*/
if ((dwFlags & ~CSnapinProperty::PublicFlags) != 0)
return ((sc = E_INVALIDARG).ToHr());
/*
* if the property already exists (from a persisted collection),
* just update the flags; otherwise add a property with the given
* name and flags
*/
CPropertyIterator itProp = m_PropMap.find (strName);
if (itProp != m_PropMap.end())
itProp->second.InitializeFlags (dwFlags);
else
{
m_PropMap[strName] = CSnapinProperty(dwFlags);
m_PropMap[strName].SetRegisteredBySnapin();
}
return (sc.ToHr());
}
/*+-------------------------------------------------------------------------*
* CSnapinProperties::ScNotifyPropertyChange
*
* Notifies the snap-in that owns this collection of a change to it's
* properties. This function delegates the heavy lifting to
*
* ScNotifyPropertyChange (CSmartProperty*, ULONG);
*
*--------------------------------------------------------------------------*/
SC CSnapinProperties::ScNotifyPropertyChange (
CPropertyIterator itProp, /* I:changing property */
const VARIANT& varValue, /* I:if action is remove then this is current value
else if action is set then this is the proposed value */
MMC_PROPERTY_ACTION eAction) /* I:what's happening to the prop? */
{
DECLARE_SC (sc, _T("CSnapinProperties::ScNotifyPropertyChange"));
ASSERT(eAction == MMC_PROPACT_CHANGING || eAction == MMC_PROPACT_DELETING);
/*
* validate the parameters
*/
if (itProp == m_PropMap.end())
return (sc = E_INVALIDARG);
/*
* make sure we're allowed to change the property
*/
if ( itProp->second.IsInitialized() &&
(itProp->second.GetFlags() & MMC_PROP_MODIFIABLE) == 0)
return (sc = ScFromMMC (MMC_E_CannotChangeProperty));
/*
* if this property change will affect the UI, and the snap-in
* isn't awake yet, wake him up
*/
if ((itProp->second.GetFlags() & MMC_PROP_CHANGEAFFECTSUI) &&
(m_pMTSnapInNode != NULL) &&
!m_pMTSnapInNode->IsInitialized())
{
sc = m_pMTSnapInNode->Init();
if (sc)
return (sc);
}
/*
* we don't want to trace failures here, so don't assign to sc
*/
CSmartProperty SmartProp (itProp->first.data(), varValue, eAction);
SC scNoTrace = ScNotifyPropertyChange (&SmartProp, 1);
if (scNoTrace.ToHr() != S_OK)
return (scNoTrace);
return (sc);
}
/*+-------------------------------------------------------------------------*
* CSnapinProperties::ScNotifyPropertyChange
*
* Notifies the snap-in that owns this collection of a change to it's
* properties.
*
* The snap-in will return:
* S_OK change was successful
* S_FALSE change was ignored
* E_INVALIDARG a changed property was invalid (e.g. a malformed
* computer name)
* E_FAIL a changed property was valid, but couldn't be used
* (e.g. a valid name for a computer that couldn't be
* located)
*--------------------------------------------------------------------------*/
SC CSnapinProperties::ScNotifyPropertyChange (
CSmartProperty* pProps, /* I:changing props */
ULONG cProps) /* I:how many are there? */
{
DECLARE_SC (sc, _T("CSnapinProperties::ScNotifyPropertyChange"));
/*
* if we're not connected to a snap-in, short out
*/
if (m_spSnapinProps == NULL)
return (sc);
/*
* validate the parameters
*/
sc = ScCheckPointers (pProps, E_UNEXPECTED);
if (sc)
return (sc);
if (cProps == 0)
return (sc = E_UNEXPECTED);
/*
* we don't want to trace failures here, so don't assign to sc
*/
return (m_spSnapinProps->PropertiesChanged (
cProps,
reinterpret_cast<MMC_SNAPIN_PROPERTY*>(pProps)));
}
/*+-------------------------------------------------------------------------*
* CSnapinProperties::Scget_Value
*
* Returns the value of the property.
*--------------------------------------------------------------------------*/
SC CSnapinProperties::Scget_Value (VARIANT* pvarValue, const CPropertyKey& key)
{
DECLARE_SC (sc, _T("CSnapinProperties::Scget_Value"));
/*
* validate parameters
*/
pvarValue = ConvertByRefVariantToByValue (pvarValue);
sc = ScCheckPointers (pvarValue);
if (sc)
return (sc);
/*
* get the iterator for the requested property
*/
CPropertyIterator itProp = IteratorFromKey (key, true);
if (itProp == m_PropMap.end())
return (sc = E_INVALIDARG);
/*
* give it to the caller
*/
const VARIANT& varValue = itProp->second.GetValue();
sc = VariantCopy (pvarValue, const_cast<VARIANT*>(&varValue));
if (sc)
return (sc);
return (sc);
}
/*+-------------------------------------------------------------------------*
* CSnapinProperties::Scput_Value
*
* Changes the value of the property.
*--------------------------------------------------------------------------*/
SC CSnapinProperties::Scput_Value (VARIANT varValue, const CPropertyKey& key)
{
DECLARE_SC (sc, _T("CSnapinProperties::Scput_Value"));
/*
* convert possible by-ref VARIANT
*/
VARIANT* pvarValue = ConvertByRefVariantToByValue (&varValue);
sc = ScCheckPointers (pvarValue);
if (sc)
return (sc);
/*
* make sure this is of the type we can persist
*/
if (!CXMLVariant::IsPersistable(pvarValue))
return (sc = E_INVALIDARG);
/*
* get the iterator for the requested property
*/
CPropertyIterator itProp = IteratorFromKey (key, true);
if (itProp == m_PropMap.end())
return (sc = E_INVALIDARG);
/*
* Notify the snap-in of the proposed change.
*/
sc = ScNotifyPropertyChange (itProp, *pvarValue, MMC_PROPACT_CHANGING);
if (sc)
return sc;
/*
* the snap-in approved the change, update the property value
*/
sc = itProp->second.ScSetValue (*pvarValue);
if (sc)
return (sc);
return sc;
}
/*+-------------------------------------------------------------------------*
* CSnapinProperties::ScGetPropertyComObject
*
* Returns a Property interface on a COM object tied to property identified
* by key. The returned interface is a tear-off interface. The collection
* will not hold a reference to it, but instead will generate a new object
* for each request for a Property.
*--------------------------------------------------------------------------*/
SC CSnapinProperties::ScGetPropertyComObject (
const CPropertyKey& key, /* I:the key for this property */
Property*& rpProperty) /* O:the Property interface */
{
DECLARE_SC (sc, _T("CSnapinProperties::ScGetPropertyComObject"));
/*
* create a CSnapinPropertyComObject if necessary
*/
CSnapinPropertyComObject* pComObj = NULL;
typedef CTiedComObjectCreator<CSnapinPropertyComObject> ObjectCreator;
sc = ObjectCreator::ScCreateAndConnect (*this, pComObj);
if (sc)
return (sc);
if (pComObj == NULL)
return (sc = E_UNEXPECTED);
/*
* tell the object what its key is
*/
pComObj->SetKey (key);
/*
* put a ref on for the caller (note that the collection will *not*
* hold a reference to the property)
*/
rpProperty = pComObj;
rpProperty->AddRef();
return (sc);
}
/*+-------------------------------------------------------------------------*
* CSnapinProperties::Persist
*
* Persists the property collection to/from an XML persistor.
*--------------------------------------------------------------------------*/
void CSnapinProperties::Persist (CPersistor &persistor)
{
if (persistor.IsStoring())
{
for (CPropertyIterator it = m_PropMap.begin(); it != m_PropMap.end(); ++it)
{
if (it->second.GetFlags() & MMC_PROP_PERSIST)
PersistWorker (persistor, it);
}
}
else
{
/*
* clear out any existing properties
*/
m_PropMap.clear();
// let the base class do the job
// it will call OnNewElement for every element found
XMLListCollectionBase::Persist(persistor);
}
}
/*+-------------------------------------------------------------------------*
* CSnapinProperties::PersistWorker
*
* Persists an individual element of the CPropertyMap to/from an XML
* persistor. It exists solely to prevent CSnapinProperties::Persist from
* calling W2CT (which implicitly calls _alloca) in a loop.
*--------------------------------------------------------------------------*/
void CSnapinProperties::PersistWorker (CPersistor& persistor, CPropertyIterator it)
{
USES_CONVERSION;
persistor.Persist (it->second, W2CT(it->first.data()));
}
/*+-------------------------------------------------------------------------*
* CSnapinProperties::OnNewElement
*
* XMLListCollectionBase::Persist will call this method for every element
* to be read from the persistor.
*--------------------------------------------------------------------------*/
void CSnapinProperties::OnNewElement(CPersistor& persistor)
{
/*
* read the property name
*/
std::wstring strName;
persistor.PersistAttribute (XML_ATTR_SNAPIN_PROP_NAME, strName);
/*
* read the property itself
*/
USES_CONVERSION;
CSnapinProperty prop;
persistor.Persist (prop, W2CT(strName.data()));
/*
* put the property in the map
*/
m_PropMap[strName] = prop;
}
/*+=========================================================================*/
/* */
/* CSnapinProperty implementation */
/* */
/*==========================================================================*/
/*+-------------------------------------------------------------------------*
* CSnapinProperty::Persist
*
* Persists the property to/from an XML persistor.
*--------------------------------------------------------------------------*/
void CSnapinProperty::Persist (CPersistor &persistor)
{
/*
* persist the value and flags (but not the private ones)
*/
DWORD dwFlags;
if (persistor.IsStoring())
dwFlags = m_dwFlags & ~PrivateFlags;
persistor.Persist (m_varValue);
persistor.PersistAttribute (XML_ATTR_SNAPIN_PROP_FLAGS, dwFlags);
if (persistor.IsLoading())
m_dwFlags = dwFlags;
}