Source code of Windows XP (NT5)
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.

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