Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1060 lines
32 KiB

  1. /*--------------------------------------------------------------------------*
  2. *
  3. * Microsoft Windows
  4. * Copyright (C) Microsoft Corporation, 1992 - 1999
  5. *
  6. * File: siprop.cpp
  7. *
  8. * Contents: Implementation file for CSnapInPropertiesRoot, et al
  9. *
  10. * History: 04-Nov-99 jeffro Created
  11. *
  12. *--------------------------------------------------------------------------*/
  13. #include "stdafx.h"
  14. #include "siprop.h"
  15. #include "variant.h"
  16. #include "mtnode.h"
  17. #ifdef DBG
  18. CTraceTag tagSnapInProps(_T("Snap-in Properties"), _T("Snap-in Properties"));
  19. #endif
  20. /*+=========================================================================*/
  21. /* */
  22. /* CSnapinPropertyComObject */
  23. /* */
  24. /*==========================================================================*/
  25. /*+-------------------------------------------------------------------------*
  26. * CSnapinPropertyComObject
  27. *
  28. * This is the COM object that exposes the Property object model interface.
  29. *--------------------------------------------------------------------------*/
  30. class CSnapinPropertyComObject :
  31. public CMMCIDispatchImpl<Property>, // the Property interface
  32. public CTiedComObject<CSnapinProperties>
  33. {
  34. typedef CSnapinProperties CMyTiedObject;
  35. public:
  36. BEGIN_MMC_COM_MAP(CSnapinPropertyComObject)
  37. END_MMC_COM_MAP()
  38. public:
  39. // Property interface
  40. MMC_METHOD1_PARAM (get_Value, VARIANT* /*pvarValue*/, m_key);
  41. MMC_METHOD1_PARAM (put_Value, VARIANT /*varValue*/, m_key);
  42. STDMETHODIMP get_Name (BSTR* pbstrName)
  43. {
  44. DECLARE_SC (sc, _T("CSnapinPropertyComObject::get_Name"));
  45. /*
  46. * validate parameters
  47. */
  48. sc = ScCheckPointers (pbstrName);
  49. if (sc)
  50. return (sc.ToHr());
  51. /*
  52. * copy the name
  53. */
  54. *pbstrName = SysAllocString (m_key.data());
  55. if (*pbstrName == NULL)
  56. return ((sc = E_OUTOFMEMORY).ToHr());
  57. return (sc.ToHr());
  58. }
  59. void SetKey (const CSnapinProperties::CPropertyKey& key)
  60. { m_key = key; }
  61. private:
  62. CSnapinProperties::CPropertyKey m_key;
  63. };
  64. /*+=========================================================================*/
  65. /* */
  66. /* CSnapinProperties implementation */
  67. /* */
  68. /*==========================================================================*/
  69. /*+-------------------------------------------------------------------------*
  70. * CSnapinProperties::FromInterface
  71. *
  72. * Returns a pointer to the CSnapinProperties object that implements
  73. * the given interface, or NULL if the implementing object is not a
  74. * CSnapinProperties.
  75. *--------------------------------------------------------------------------*/
  76. CSnapinProperties* CSnapinProperties::FromInterface (IUnknown* pUnk)
  77. {
  78. CSnapinProperties* pProps;
  79. pProps = dynamic_cast<CSnapinProperties*>(pUnk);
  80. return (pProps);
  81. }
  82. /*+-------------------------------------------------------------------------*
  83. * CSnapinProperties::Item
  84. *
  85. * Returns an interface to a property identified by bstrName, which must
  86. * be released by the caller. If the collection doesn't contain a property
  87. * with the given name, a new property with the given name (initialized to
  88. * VT_EMPTY) is added to the collection.
  89. *
  90. * Returns:
  91. * S_OK the property was successfully returned
  92. * S_FALSE the property was successfully returned, but didn't
  93. * exist in the collection beforehand, so a new one
  94. * was added
  95. * E_INVALIDARG the property name wasn't valid (i.e. empty) or
  96. * ppProperty was NULL
  97. * E_OUTOFMEMORY not enough memory to perform the operation
  98. * E_UNEXPECTED something dire happened
  99. *--------------------------------------------------------------------------*/
  100. STDMETHODIMP CSnapinProperties::Item (
  101. BSTR bstrName, /* I:name of property to get */
  102. PPPROPERTY ppProperty) /* O:interface to property */
  103. {
  104. DECLARE_SC (sc, _T("CSnapinProperties::Item"));
  105. /*
  106. * validate the parameters
  107. */
  108. sc = ScCheckPointers (bstrName, ppProperty);
  109. if (sc)
  110. return (sc.ToHr());
  111. const std::wstring strName = bstrName;
  112. if (strName.empty())
  113. return ((sc = E_INVALIDARG).ToHr());
  114. bool fPropWasAdded = false;
  115. /*
  116. * Look up the property. If it's not there yet, add a new one (maybe).
  117. */
  118. if (m_PropMap.find(strName) == m_PropMap.end())
  119. {
  120. /*
  121. * Fail without implicitly adding if we're not attached to a snap-in.
  122. * This will prevent us from adding properties that weren't
  123. * registered with AddPropertyName
  124. */
  125. if (m_spSnapinProps != NULL)
  126. return ((sc = ScFromMMC(MMC_E_UnrecognizedProperty)).ToHr());
  127. /*
  128. * put an empty property in the map with the given name
  129. */
  130. m_PropMap[strName] = CSnapinProperty();
  131. fPropWasAdded = true;
  132. }
  133. /*
  134. * get a COM object tied to the new property
  135. */
  136. sc = ScGetPropertyComObject (strName, *ppProperty);
  137. if (sc)
  138. return (sc.ToHr());
  139. if (*ppProperty == NULL)
  140. return ((sc = E_UNEXPECTED).ToHr());
  141. /*
  142. * if we had to add the property, return S_FALSE so the caller can
  143. * tell (if he cares)
  144. */
  145. if (fPropWasAdded)
  146. sc = S_FALSE;
  147. return (sc.ToHr());
  148. }
  149. /*+-------------------------------------------------------------------------*
  150. * CSnapinProperties::get_Count
  151. *
  152. * Returns the number of properties in the collection in *pCount.
  153. *
  154. * Returns:
  155. *
  156. * S_OK success
  157. * E_INVALIDARG pCount is NULL
  158. *--------------------------------------------------------------------------*/
  159. STDMETHODIMP CSnapinProperties::get_Count (
  160. PLONG pCount) /* O:number of items in the collection */
  161. {
  162. DECLARE_SC (sc, _T("CSnapinProperties::get_Count"));
  163. /*
  164. * validate the parameters
  165. */
  166. sc = ScCheckPointers (pCount);
  167. if (sc)
  168. return (sc.ToHr());
  169. /*
  170. * return the number of elements in the property map
  171. */
  172. *pCount = m_PropMap.size();
  173. return (sc.ToHr());
  174. }
  175. /*+-------------------------------------------------------------------------*
  176. * CSnapinProperties::Remove
  177. *
  178. * Removes a property from the collection.
  179. *
  180. * Returns:
  181. * S_OK the property was successfully removed
  182. * S_FALSE the property didn't exist in the collection
  183. * E_INVALIDARG the property name wasn't valid (i.e. empty)
  184. * E_UNEXPECTED something dire happened
  185. *--------------------------------------------------------------------------*/
  186. STDMETHODIMP CSnapinProperties::Remove (
  187. BSTR bstrName) /* I:name of property to remove */
  188. {
  189. DECLARE_SC (sc, _T("CSnapinProperties::Remove"));
  190. Trace (tagSnapInProps, _T("Snap-in Properties"));
  191. /*
  192. * validate the parameters
  193. */
  194. sc = ScCheckPointers (bstrName);
  195. if (sc)
  196. return (sc.ToHr());
  197. /*
  198. * find the item to remove
  199. */
  200. CPropertyIterator itProp = m_PropMap.find (bstrName);
  201. if (itProp == m_PropMap.end())
  202. return ((sc = S_FALSE).ToHr());
  203. /*
  204. * see if we can remove it
  205. */
  206. if ( itProp->second.IsInitialized() &&
  207. (itProp->second.GetFlags() & MMC_PROP_REMOVABLE) == 0)
  208. return ((sc = ScFromMMC(MMC_E_CannotRemoveProperty)).ToHr());
  209. /*
  210. * Inform snapin before we remove the property about removal.
  211. */
  212. sc = ScNotifyPropertyChange(itProp, itProp->second.GetValue(), MMC_PROPACT_DELETING);
  213. if (sc)
  214. return sc.ToHr();
  215. /*
  216. * the snap-in approved the change, remove the property
  217. */
  218. m_PropMap.erase (itProp);
  219. return (sc.ToHr());
  220. }
  221. /*+-------------------------------------------------------------------------*
  222. *
  223. * CSnapinProperties::ScEnumNext
  224. *
  225. * PURPOSE: Returns the next Property interface.
  226. *
  227. * PARAMETERS:
  228. * _Position & key :
  229. * PDISPATCH & pDispatch :
  230. *
  231. * RETURNS:
  232. * SC
  233. *
  234. *+-------------------------------------------------------------------------*/
  235. SC CSnapinProperties::ScEnumNext (CPropertyKey &key, PDISPATCH & pDispatch)
  236. {
  237. DECLARE_SC (sc, _T("CSnapinProperties::ScEnumNext"));
  238. Trace (tagSnapInProps, _T("Snap-in Properties"));
  239. /*
  240. * get the next element
  241. */
  242. CPropertyIterator it = IteratorFromKey (key, false);
  243. if(it == m_PropMap.end())
  244. return (sc = S_FALSE); // out of elements.
  245. /*
  246. * get the Properties COM object for this property
  247. */
  248. PropertyPtr spProperty;
  249. sc = ScGetPropertyComObject (it->first, *&spProperty);
  250. if (sc)
  251. return (sc);
  252. if (spProperty == NULL)
  253. return (sc = E_UNEXPECTED);
  254. /*
  255. * return the IDispatch for the object and leave a ref on it for the client
  256. */
  257. pDispatch = spProperty.Detach();
  258. // remember the enumeration key for next time
  259. key = it->first;
  260. return (sc);
  261. }
  262. /*+-------------------------------------------------------------------------*
  263. * CSnapinProperties::ScEnumSkip
  264. *
  265. * Skips the next celt elements in the properties collection.
  266. *--------------------------------------------------------------------------*/
  267. SC CSnapinProperties::ScEnumSkip (
  268. unsigned long celt, /* I:number of items to skip */
  269. unsigned long& celtSkipped, /* O:number of items skipped */
  270. CPropertyKey& key) /* I/O:enumeration key */
  271. {
  272. DECLARE_SC (sc, _T("CSnapinProperties::ScEnumSkip"));
  273. Trace (tagSnapInProps, _T("Snap-in Properties"));
  274. /*
  275. * skip the next celt properties
  276. */
  277. CPropertyIterator it = IteratorFromKey (key, false);
  278. for (celtSkipped = 0;
  279. (celtSkipped < celt) && (it != m_PropMap.end());
  280. ++celtSkipped, ++it)
  281. {
  282. /*
  283. * remember the enumeration key for next time
  284. */
  285. key = it->first;
  286. }
  287. /*
  288. * if we advanced less than the requested number, return S_FALSE
  289. */
  290. if (celtSkipped < celt)
  291. sc = S_FALSE;
  292. return (sc);
  293. }
  294. /*+-------------------------------------------------------------------------*
  295. * CSnapinProperties::ScEnumReset
  296. *
  297. * Resets a CPropertyKey so that the next item it will return is the
  298. * first item in the properties collection.
  299. *--------------------------------------------------------------------------*/
  300. SC CSnapinProperties::ScEnumReset (
  301. CPropertyKey& key) /* I/O:enumeration key to reset */
  302. {
  303. DECLARE_SC (sc, _T("CSnapinProperties::ScEnumReset"));
  304. key.erase();
  305. return (sc);
  306. }
  307. /*+-------------------------------------------------------------------------*
  308. * CSnapinProperties::get__NewEnum
  309. *
  310. * Creates returns an interface that can be queried for IEnumVARIANT
  311. *--------------------------------------------------------------------------*/
  312. STDMETHODIMP CSnapinProperties::get__NewEnum (IUnknown** ppUnk)
  313. {
  314. DECLARE_SC (sc, _T("CSnapinProperties::get__NewEnum"));
  315. Trace (tagSnapInProps, _T("Snap-in Properties"));
  316. // validate the parameter
  317. sc = ScCheckPointers (ppUnk);
  318. if (sc)
  319. return (sc.ToHr());
  320. *ppUnk = NULL;
  321. // typedef the enumerator
  322. typedef CComObject<CMMCEnumerator<CSnapinProperties, CPropertyKey> > CEnumerator;
  323. // create an instance of the enumerator
  324. CEnumerator *pEnum = NULL;
  325. sc = CEnumerator::CreateInstance (&pEnum);
  326. if (sc)
  327. return (sc.ToHr());
  328. if(!pEnum)
  329. return ((sc = E_UNEXPECTED).ToHr());
  330. // create a connection between the enumerator and ourselves
  331. sc = ScCreateConnection(*pEnum, *this);
  332. if(sc)
  333. return (sc.ToHr());
  334. // initialize the position using the Reset function
  335. sc = ScEnumReset (pEnum->m_position);
  336. if(sc)
  337. return (sc.ToHr());
  338. // get the IUnknown to return
  339. sc = pEnum->QueryInterface (IID_IUnknown, (void**) ppUnk);
  340. if (sc)
  341. return (sc.ToHr());
  342. return (sc.ToHr());
  343. }
  344. /*+-------------------------------------------------------------------------*
  345. * CSnapinProperties::IteratorFromKey
  346. *
  347. * Returns the iterator in the property map corresponding to the first
  348. * element following the one designated by key.
  349. *
  350. * The caller might be interested in an exact match or the nearest match.
  351. * The nearest match would be suitable when the key is used in an
  352. * enumeration. Let's say that the collection consists of "Alpha", "Bravo",
  353. * and "Charlie". The first request for an item will return "Alpha" and
  354. * the key will hold "Alpha" (see comments for CPropertyKey). Let's
  355. * assume that "Alpha" is removed from the collection and then the enumeration
  356. * continues. We want to return the one after the last one we got back
  357. * ("Alpha") which would be "Bravo". All is well.
  358. *
  359. * An exact match would be required when trying to find a CSnapinProperty
  360. * for a CSnapinPropertyComObject. The COM object will refer to a specific
  361. * property, which we want to be sure to find every time. A close match
  362. * isn't sufficient.
  363. *--------------------------------------------------------------------------*/
  364. CSnapinProperties::CPropertyIterator
  365. CSnapinProperties::IteratorFromKey (
  366. const CPropertyKey& key, /* I:key to convert */
  367. bool fExactMatch) /* I:match key exactly? */
  368. {
  369. CPropertyIterator it;
  370. /*
  371. * need an exact match?
  372. */
  373. if (fExactMatch)
  374. {
  375. /*
  376. * nothing matches an empty key
  377. */
  378. if (key.empty())
  379. it = m_PropMap.end();
  380. /*
  381. * the key's not empty, look up the property
  382. */
  383. else
  384. it = m_PropMap.find (key);
  385. }
  386. /*
  387. * nearest match
  388. */
  389. else
  390. {
  391. /*
  392. * the beginning of the map is nearest an empty key
  393. */
  394. if (key.empty())
  395. it = m_PropMap.begin();
  396. /*
  397. * otherwise, find the nearest one greater than the key
  398. */
  399. else
  400. it = m_PropMap.upper_bound (key);
  401. }
  402. return (it);
  403. }
  404. /*+-------------------------------------------------------------------------*
  405. * CSnapinProperties::ScInitialize
  406. *
  407. * Initializes a CSnapinProperties. This function will return an error if
  408. * psip is NULL, or if there's an error copying the initial properties.
  409. *--------------------------------------------------------------------------*/
  410. SC CSnapinProperties::ScInitialize (
  411. ISnapinProperties* psip, /* I:snap-in's ISnapinProperties iface */
  412. Properties* pInitProps_, /* I:initial properties for the snap-in */
  413. CMTSnapInNode* pMTSnapInNode) /* I:snap-in these properties belong to */
  414. {
  415. DECLARE_SC (sc, _T("CSnapinProperties::ScInitialize"));
  416. /*
  417. * validate the parameters
  418. */
  419. sc = ScCheckPointers (psip);
  420. if (sc)
  421. return (sc);
  422. /*
  423. * pInitProps_ is optional, but if it was given, it should be the
  424. * one implemented by CSnapinProperties
  425. */
  426. CSnapinProperties* pInitProps = FromInterface (pInitProps_);
  427. if ((pInitProps_ != NULL) && (pInitProps == NULL))
  428. return (sc = E_INVALIDARG);
  429. /*
  430. * keep the the snap-in and the snap-in's interface
  431. */
  432. m_pMTSnapInNode = pMTSnapInNode;
  433. m_spSnapinProps = psip;
  434. /*
  435. * get the names of the properties recognized by the snap-in
  436. */
  437. sc = psip->QueryPropertyNames (this);
  438. if (sc)
  439. return (sc);
  440. /*
  441. * If we're reloading a snap-in's properties from the console file,
  442. * weed out entries that the snap-in registered last time but didn't
  443. * register this time.
  444. */
  445. if (pInitProps == this)
  446. {
  447. CPropertyIterator itProp = m_PropMap.begin();
  448. while (itProp != m_PropMap.end())
  449. {
  450. /*
  451. * snap-in registered? keep it
  452. */
  453. if (itProp->second.IsRegisteredBySnapin())
  454. ++itProp;
  455. /*
  456. * snap-in didn't register, toss it
  457. */
  458. else
  459. itProp = m_PropMap.erase (itProp);
  460. }
  461. }
  462. /*
  463. * Otherwise, if we got initial properties, find each property
  464. * that the snap-in registered in set of initial properties and
  465. * copy them to the snap-in's collection.
  466. */
  467. else if (pInitProps != NULL)
  468. {
  469. sc = ScMergeProperties (*pInitProps);
  470. if (sc)
  471. return (sc);
  472. }
  473. /*
  474. * initialize the ISnapinProperties interface
  475. */
  476. sc = psip->Initialize (this);
  477. if (sc)
  478. return (sc);
  479. /*
  480. * give the ISnapinProperties its initial property values
  481. */
  482. if (!m_PropMap.empty())
  483. {
  484. /*
  485. * Build an array of CSmartProperty objects to pass to
  486. * ISnapinProperties::PropertiesChanged. CSmartProperty objects
  487. * look just like MMC_SNAPIN_PROPERTY structures, but use a
  488. * CComVariant instead of VARIANT for automatic resource management.
  489. * See the definition of CSmartProperty.
  490. */
  491. CAutoArrayPtr<CSmartProperty> spInitialProps (
  492. new (std::nothrow) CSmartProperty[m_PropMap.size()]);
  493. if (spInitialProps == NULL)
  494. return (sc = E_OUTOFMEMORY);
  495. CPropertyIterator it = m_PropMap.begin();
  496. for (int i = 0; it != m_PropMap.end(); ++it, ++i)
  497. {
  498. spInitialProps[i].pszPropName = it->first.data();
  499. spInitialProps[i].varValue = it->second.GetValue();
  500. spInitialProps[i].eAction = MMC_PROPACT_INITIALIZED;
  501. }
  502. /*
  503. * we don't want to trace a failure here, so use a local SC
  504. */
  505. SC scLocal = ScNotifyPropertyChange (spInitialProps, m_PropMap.size());
  506. if (scLocal)
  507. return (scLocal);
  508. }
  509. return (sc);
  510. }
  511. /*+-------------------------------------------------------------------------*
  512. * CSnapinProperties::ScSetSnapInNode
  513. *
  514. * Attaches this properties collection to a CMTSnapInNode.
  515. *--------------------------------------------------------------------------*/
  516. SC CSnapinProperties::ScSetSnapInNode (CMTSnapInNode* pMTSnapInNode)
  517. {
  518. DECLARE_SC (sc, _T("CSnapinProperties::ScSetSnapInNode"));
  519. m_pMTSnapInNode = pMTSnapInNode;
  520. return (sc);
  521. }
  522. /*+-------------------------------------------------------------------------*
  523. * CSnapinProperties::ScMergeProperties
  524. *
  525. * Merges the properties from another property collection into this one.
  526. * Only properties that already exist in the destination collection are
  527. * copied from the source.
  528. *--------------------------------------------------------------------------*/
  529. SC CSnapinProperties::ScMergeProperties (const CSnapinProperties& other)
  530. {
  531. DECLARE_SC (sc, _T("CSnapinProperties::ScMergeProperties"));
  532. /*
  533. * for each property in the other collection...
  534. */
  535. CConstPropertyIterator itOtherProp;
  536. for (itOtherProp = other.m_PropMap.begin();
  537. (itOtherProp != other.m_PropMap.end()) && !sc.IsError();
  538. ++itOtherProp)
  539. {
  540. /*
  541. * look for a corresponding property in the our set
  542. */
  543. CPropertyIterator itProp = m_PropMap.find (itOtherProp->first);
  544. /*
  545. * if it's in our set, copy its value
  546. */
  547. if (itProp != m_PropMap.end())
  548. sc = itProp->second.ScSetValue (itOtherProp->second.GetValue());
  549. }
  550. return (sc);
  551. }
  552. /*+-------------------------------------------------------------------------*
  553. * CSnapinProperties::AddPropertyName
  554. *
  555. * This method is called by the snap-in from its implementation of
  556. * ISnapinProperties::QueryPropertyNames to register the properties it
  557. * recognizes.
  558. *--------------------------------------------------------------------------*/
  559. STDMETHODIMP CSnapinProperties::AddPropertyName (
  560. LPCOLESTR pszPropName, /* I:property name */
  561. DWORD dwFlags) /* I:flags for this property */
  562. {
  563. DECLARE_SC (sc, _T("CSnapinProperties::AddPropertyName"));
  564. /*
  565. * validate the parameters
  566. */
  567. sc = ScCheckPointers (pszPropName);
  568. if (sc)
  569. return (sc.ToHr());
  570. const std::wstring strName = pszPropName;
  571. if (strName.empty())
  572. return ((sc = E_INVALIDARG).ToHr());
  573. /*
  574. * make sure no undocumented flags were passed in
  575. */
  576. if ((dwFlags & ~CSnapinProperty::PublicFlags) != 0)
  577. return ((sc = E_INVALIDARG).ToHr());
  578. /*
  579. * if the property already exists (from a persisted collection),
  580. * just update the flags; otherwise add a property with the given
  581. * name and flags
  582. */
  583. CPropertyIterator itProp = m_PropMap.find (strName);
  584. if (itProp != m_PropMap.end())
  585. itProp->second.InitializeFlags (dwFlags);
  586. else
  587. {
  588. m_PropMap[strName] = CSnapinProperty(dwFlags);
  589. m_PropMap[strName].SetRegisteredBySnapin();
  590. }
  591. return (sc.ToHr());
  592. }
  593. /*+-------------------------------------------------------------------------*
  594. * CSnapinProperties::ScNotifyPropertyChange
  595. *
  596. * Notifies the snap-in that owns this collection of a change to it's
  597. * properties. This function delegates the heavy lifting to
  598. *
  599. * ScNotifyPropertyChange (CSmartProperty*, ULONG);
  600. *
  601. *--------------------------------------------------------------------------*/
  602. SC CSnapinProperties::ScNotifyPropertyChange (
  603. CPropertyIterator itProp, /* I:changing property */
  604. const VARIANT& varValue, /* I:if action is remove then this is current value
  605. else if action is set then this is the proposed value */
  606. MMC_PROPERTY_ACTION eAction) /* I:what's happening to the prop? */
  607. {
  608. DECLARE_SC (sc, _T("CSnapinProperties::ScNotifyPropertyChange"));
  609. ASSERT(eAction == MMC_PROPACT_CHANGING || eAction == MMC_PROPACT_DELETING);
  610. /*
  611. * validate the parameters
  612. */
  613. if (itProp == m_PropMap.end())
  614. return (sc = E_INVALIDARG);
  615. /*
  616. * make sure we're allowed to change the property
  617. */
  618. if ( itProp->second.IsInitialized() &&
  619. (itProp->second.GetFlags() & MMC_PROP_MODIFIABLE) == 0)
  620. return (sc = ScFromMMC (MMC_E_CannotChangeProperty));
  621. /*
  622. * if this property change will affect the UI, and the snap-in
  623. * isn't awake yet, wake him up
  624. */
  625. if ((itProp->second.GetFlags() & MMC_PROP_CHANGEAFFECTSUI) &&
  626. (m_pMTSnapInNode != NULL) &&
  627. !m_pMTSnapInNode->IsInitialized())
  628. {
  629. sc = m_pMTSnapInNode->Init();
  630. if (sc)
  631. return (sc);
  632. }
  633. /*
  634. * we don't want to trace failures here, so don't assign to sc
  635. */
  636. CSmartProperty SmartProp (itProp->first.data(), varValue, eAction);
  637. SC scNoTrace = ScNotifyPropertyChange (&SmartProp, 1);
  638. if (scNoTrace.ToHr() != S_OK)
  639. return (scNoTrace);
  640. return (sc);
  641. }
  642. /*+-------------------------------------------------------------------------*
  643. * CSnapinProperties::ScNotifyPropertyChange
  644. *
  645. * Notifies the snap-in that owns this collection of a change to it's
  646. * properties.
  647. *
  648. * The snap-in will return:
  649. * S_OK change was successful
  650. * S_FALSE change was ignored
  651. * E_INVALIDARG a changed property was invalid (e.g. a malformed
  652. * computer name)
  653. * E_FAIL a changed property was valid, but couldn't be used
  654. * (e.g. a valid name for a computer that couldn't be
  655. * located)
  656. *--------------------------------------------------------------------------*/
  657. SC CSnapinProperties::ScNotifyPropertyChange (
  658. CSmartProperty* pProps, /* I:changing props */
  659. ULONG cProps) /* I:how many are there? */
  660. {
  661. DECLARE_SC (sc, _T("CSnapinProperties::ScNotifyPropertyChange"));
  662. /*
  663. * if we're not connected to a snap-in, short out
  664. */
  665. if (m_spSnapinProps == NULL)
  666. return (sc);
  667. /*
  668. * validate the parameters
  669. */
  670. sc = ScCheckPointers (pProps, E_UNEXPECTED);
  671. if (sc)
  672. return (sc);
  673. if (cProps == 0)
  674. return (sc = E_UNEXPECTED);
  675. /*
  676. * we don't want to trace failures here, so don't assign to sc
  677. */
  678. return (m_spSnapinProps->PropertiesChanged (
  679. cProps,
  680. reinterpret_cast<MMC_SNAPIN_PROPERTY*>(pProps)));
  681. }
  682. /*+-------------------------------------------------------------------------*
  683. * CSnapinProperties::Scget_Value
  684. *
  685. * Returns the value of the property.
  686. *--------------------------------------------------------------------------*/
  687. SC CSnapinProperties::Scget_Value (VARIANT* pvarValue, const CPropertyKey& key)
  688. {
  689. DECLARE_SC (sc, _T("CSnapinProperties::Scget_Value"));
  690. /*
  691. * validate parameters
  692. */
  693. pvarValue = ConvertByRefVariantToByValue (pvarValue);
  694. sc = ScCheckPointers (pvarValue);
  695. if (sc)
  696. return (sc);
  697. /*
  698. * get the iterator for the requested property
  699. */
  700. CPropertyIterator itProp = IteratorFromKey (key, true);
  701. if (itProp == m_PropMap.end())
  702. return (sc = E_INVALIDARG);
  703. /*
  704. * give it to the caller
  705. */
  706. const VARIANT& varValue = itProp->second.GetValue();
  707. sc = VariantCopy (pvarValue, const_cast<VARIANT*>(&varValue));
  708. if (sc)
  709. return (sc);
  710. return (sc);
  711. }
  712. /*+-------------------------------------------------------------------------*
  713. * CSnapinProperties::Scput_Value
  714. *
  715. * Changes the value of the property.
  716. *--------------------------------------------------------------------------*/
  717. SC CSnapinProperties::Scput_Value (VARIANT varValue, const CPropertyKey& key)
  718. {
  719. DECLARE_SC (sc, _T("CSnapinProperties::Scput_Value"));
  720. /*
  721. * convert possible by-ref VARIANT
  722. */
  723. VARIANT* pvarValue = ConvertByRefVariantToByValue (&varValue);
  724. sc = ScCheckPointers (pvarValue);
  725. if (sc)
  726. return (sc);
  727. /*
  728. * make sure this is of the type we can persist
  729. */
  730. if (!CXMLVariant::IsPersistable(pvarValue))
  731. return (sc = E_INVALIDARG);
  732. /*
  733. * get the iterator for the requested property
  734. */
  735. CPropertyIterator itProp = IteratorFromKey (key, true);
  736. if (itProp == m_PropMap.end())
  737. return (sc = E_INVALIDARG);
  738. /*
  739. * Notify the snap-in of the proposed change.
  740. */
  741. sc = ScNotifyPropertyChange (itProp, *pvarValue, MMC_PROPACT_CHANGING);
  742. if (sc)
  743. return sc;
  744. /*
  745. * the snap-in approved the change, update the property value
  746. */
  747. sc = itProp->second.ScSetValue (*pvarValue);
  748. if (sc)
  749. return (sc);
  750. return sc;
  751. }
  752. /*+-------------------------------------------------------------------------*
  753. * CSnapinProperties::ScGetPropertyComObject
  754. *
  755. * Returns a Property interface on a COM object tied to property identified
  756. * by key. The returned interface is a tear-off interface. The collection
  757. * will not hold a reference to it, but instead will generate a new object
  758. * for each request for a Property.
  759. *--------------------------------------------------------------------------*/
  760. SC CSnapinProperties::ScGetPropertyComObject (
  761. const CPropertyKey& key, /* I:the key for this property */
  762. Property*& rpProperty) /* O:the Property interface */
  763. {
  764. DECLARE_SC (sc, _T("CSnapinProperties::ScGetPropertyComObject"));
  765. /*
  766. * create a CSnapinPropertyComObject if necessary
  767. */
  768. CSnapinPropertyComObject* pComObj = NULL;
  769. typedef CTiedComObjectCreator<CSnapinPropertyComObject> ObjectCreator;
  770. sc = ObjectCreator::ScCreateAndConnect (*this, pComObj);
  771. if (sc)
  772. return (sc);
  773. if (pComObj == NULL)
  774. return (sc = E_UNEXPECTED);
  775. /*
  776. * tell the object what its key is
  777. */
  778. pComObj->SetKey (key);
  779. /*
  780. * put a ref on for the caller (note that the collection will *not*
  781. * hold a reference to the property)
  782. */
  783. rpProperty = pComObj;
  784. rpProperty->AddRef();
  785. return (sc);
  786. }
  787. /*+-------------------------------------------------------------------------*
  788. * CSnapinProperties::Persist
  789. *
  790. * Persists the property collection to/from an XML persistor.
  791. *--------------------------------------------------------------------------*/
  792. void CSnapinProperties::Persist (CPersistor &persistor)
  793. {
  794. if (persistor.IsStoring())
  795. {
  796. for (CPropertyIterator it = m_PropMap.begin(); it != m_PropMap.end(); ++it)
  797. {
  798. if (it->second.GetFlags() & MMC_PROP_PERSIST)
  799. PersistWorker (persistor, it);
  800. }
  801. }
  802. else
  803. {
  804. /*
  805. * clear out any existing properties
  806. */
  807. m_PropMap.clear();
  808. // let the base class do the job
  809. // it will call OnNewElement for every element found
  810. XMLListCollectionBase::Persist(persistor);
  811. }
  812. }
  813. /*+-------------------------------------------------------------------------*
  814. * CSnapinProperties::PersistWorker
  815. *
  816. * Persists an individual element of the CPropertyMap to/from an XML
  817. * persistor. It exists solely to prevent CSnapinProperties::Persist from
  818. * calling W2CT (which implicitly calls _alloca) in a loop.
  819. *--------------------------------------------------------------------------*/
  820. void CSnapinProperties::PersistWorker (CPersistor& persistor, CPropertyIterator it)
  821. {
  822. USES_CONVERSION;
  823. persistor.Persist (it->second, W2CT(it->first.data()));
  824. }
  825. /*+-------------------------------------------------------------------------*
  826. * CSnapinProperties::OnNewElement
  827. *
  828. * XMLListCollectionBase::Persist will call this method for every element
  829. * to be read from the persistor.
  830. *--------------------------------------------------------------------------*/
  831. void CSnapinProperties::OnNewElement(CPersistor& persistor)
  832. {
  833. /*
  834. * read the property name
  835. */
  836. std::wstring strName;
  837. persistor.PersistAttribute (XML_ATTR_SNAPIN_PROP_NAME, strName);
  838. /*
  839. * read the property itself
  840. */
  841. USES_CONVERSION;
  842. CSnapinProperty prop;
  843. persistor.Persist (prop, W2CT(strName.data()));
  844. /*
  845. * put the property in the map
  846. */
  847. m_PropMap[strName] = prop;
  848. }
  849. /*+=========================================================================*/
  850. /* */
  851. /* CSnapinProperty implementation */
  852. /* */
  853. /*==========================================================================*/
  854. /*+-------------------------------------------------------------------------*
  855. * CSnapinProperty::Persist
  856. *
  857. * Persists the property to/from an XML persistor.
  858. *--------------------------------------------------------------------------*/
  859. void CSnapinProperty::Persist (CPersistor &persistor)
  860. {
  861. /*
  862. * persist the value and flags (but not the private ones)
  863. */
  864. DWORD dwFlags;
  865. if (persistor.IsStoring())
  866. dwFlags = m_dwFlags & ~PrivateFlags;
  867. persistor.Persist (m_varValue);
  868. persistor.PersistAttribute (XML_ATTR_SNAPIN_PROP_FLAGS, dwFlags);
  869. if (persistor.IsLoading())
  870. m_dwFlags = dwFlags;
  871. }