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.

780 lines
19 KiB

  1. ///////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright(C) 1997-1998 Microsoft Corporation all rights reserved.
  4. //
  5. // Module: sdocollection.h
  6. //
  7. // Project: Everest
  8. //
  9. // Description: IAS Server Data Object Collection Implementation
  10. //
  11. // Author: TLP 1/23/98
  12. //
  13. ///////////////////////////////////////////////////////////////////////////
  14. #include "stdafx.h"
  15. #include "sdo.h"
  16. #include "sdocollection.h"
  17. #include "sdofactory.h"
  18. #include "sdohelperfuncs.h"
  19. /////////////////////////////////////////////////////////////////////////////
  20. // CSdoCollection Class Implementation
  21. /////////////////////////////////////////////////////////////////////////////
  22. /////////////////////////////////////////////////////////////////////////////
  23. CSdoCollection::CSdoCollection()
  24. : m_fSdoInitialized(false),
  25. m_pDSContainer(NULL),
  26. m_pSdoMachine(NULL),
  27. m_fCreateOnAdd(false)
  28. {
  29. InternalAddRef();
  30. }
  31. /////////////////////////////////////////////////////////////////////////////
  32. CSdoCollection::~CSdoCollection()
  33. {
  34. InternalShutdown();
  35. }
  36. /////////////////////////////////////////////////////////////////////////////
  37. // ISdoCollection Interface Implmentation
  38. /////////////////////////////////////////////////////////////////////////////
  39. /////////////////////////////////////////////////////////////////////////////
  40. STDMETHODIMP CSdoCollection::get_Count(long* pCount)
  41. {
  42. CSdoLock theLock(*this);
  43. // Check precondtions
  44. //
  45. _ASSERT ( m_fSdoInitialized );
  46. if ( ! m_fSdoInitialized )
  47. return E_FAIL;
  48. _ASSERT( NULL != pCount );
  49. if ( NULL == pCount )
  50. return E_POINTER;
  51. *pCount = m_Objects.size();
  52. return S_OK;
  53. }
  54. /////////////////////////////////////////////////////////////////////////////
  55. STDMETHODIMP CSdoCollection::Add(
  56. /*[in]*/ BSTR bstrName,
  57. /*[in/out]*/ IDispatch** ppItem
  58. )
  59. {
  60. CSdoLock theLock(*this);
  61. // Check preconditions
  62. //
  63. _ASSERT ( m_fSdoInitialized );
  64. if ( ! m_fSdoInitialized )
  65. return E_FAIL;
  66. _ASSERT ( NULL != ppItem );
  67. if ( NULL == ppItem )
  68. return E_POINTER;
  69. // Get the Sdo name from the specified object if bstrName is not given
  70. //
  71. HRESULT hr = E_FAIL;
  72. _variant_t vtSdoName;
  73. if ( NULL == bstrName )
  74. {
  75. CComPtr<ISdo> pSdo;
  76. hr = (*ppItem)->QueryInterface(IID_ISdo, (void**)&pSdo);
  77. if ( FAILED(hr) )
  78. {
  79. IASTracePrintf("Error in SDO Collection - Add() - QueryInterface(ISdo) failed!...");
  80. return hr;
  81. }
  82. hr = pSdo->GetProperty(PROPERTY_SDO_NAME, &vtSdoName);
  83. if ( FAILED(hr) )
  84. {
  85. IASTracePrintf("Error in SDO Collection - Add - GetProperty(Name) failed");
  86. return hr;
  87. }
  88. bstrName = V_BSTR(&vtSdoName);
  89. }
  90. // Ensure that the SDO name is unique
  91. //
  92. VARIANT_BOOL boolVal;
  93. hr = InternalIsNameUnique(bstrName, &boolVal);
  94. if ( SUCCEEDED(hr) )
  95. {
  96. if ( VARIANT_TRUE == boolVal )
  97. {
  98. // Can still fail if name is not unique in the underlying data store
  99. //
  100. hr = InternalAdd(bstrName, ppItem);
  101. }
  102. else
  103. {
  104. // Name is not unqiue
  105. //
  106. hr = E_INVALIDARG;
  107. }
  108. }
  109. return hr;
  110. }
  111. /////////////////////////////////////////////////////////////////////////////
  112. STDMETHODIMP CSdoCollection::Remove(IDispatch* pItem)
  113. {
  114. CSdoLock theLock(*this);
  115. HRESULT hr = DISP_E_MEMBERNOTFOUND;
  116. try
  117. {
  118. SDO_TRACE_VERBOSE_2("Removing item at $%p from SDO collection at $%p...", pItem, this);
  119. // Check preconditions
  120. //
  121. _ASSERT ( m_fSdoInitialized );
  122. if ( ! m_fSdoInitialized )
  123. throw _com_error(E_UNEXPECTED);
  124. _ASSERT ( NULL != pItem );
  125. if ( NULL == pItem )
  126. throw _com_error(E_POINTER);
  127. CComPtr<ISdo> pSdo;
  128. hr = pItem->QueryInterface(IID_ISdo, (void**)&pSdo);
  129. if ( FAILED(hr) )
  130. throw _com_error(hr);
  131. VariantArrayIterator p = m_Objects.begin();
  132. while ( p != m_Objects.end() )
  133. {
  134. if ( (*p).pdispVal == pItem )
  135. {
  136. // Remove the object from the underlying datastore (if neccessary)
  137. //
  138. if ( m_pDSContainer )
  139. {
  140. _variant_t vtItemName;
  141. hr = pSdo->GetProperty(PROPERTY_SDO_DATASTORE_NAME, &vtItemName);
  142. if ( FAILED(hr) )
  143. throw _com_error(hr);
  144. hr = m_pDSContainer->Remove(NULL, V_BSTR(&vtItemName));
  145. if ( FAILED(hr) )
  146. throw _com_error(hr);
  147. }
  148. // Remove the object from the collection
  149. //
  150. m_Objects.erase(p);
  151. break;
  152. }
  153. p++;
  154. }
  155. }
  156. catch (_com_error theError)
  157. {
  158. hr = theError.Error();
  159. IASTracePrintf("Error in SDO Collection - Remove() - Caught _com_error exception: %lx...", hr);
  160. }
  161. catch (...)
  162. {
  163. hr = E_UNEXPECTED;
  164. IASTracePrintf("Error in SDO Collection - Remove() - Caught unhandled exception...");
  165. }
  166. return hr;
  167. }
  168. /////////////////////////////////////////////////////////////////////////////
  169. STDMETHODIMP CSdoCollection::RemoveAll(void)
  170. {
  171. CSdoLock theLock(*this);
  172. HRESULT hr = S_OK;
  173. try
  174. {
  175. SDO_TRACE_VERBOSE_1("Clearing the items from the SDO collection at $%p...",this);
  176. _ASSERT ( m_fSdoInitialized );
  177. if ( ! m_fSdoInitialized )
  178. throw _com_error(E_UNEXPECTED);
  179. if ( ! m_Objects.empty() )
  180. {
  181. VariantArrayIterator p = m_Objects.begin();
  182. while( p != m_Objects.end() )
  183. {
  184. if ( m_pDSContainer )
  185. {
  186. CComPtr<ISdo> pSdo;
  187. hr = ((*p).pdispVal)->QueryInterface(IID_ISdo, (void**)&pSdo);
  188. if ( FAILED(hr) )
  189. throw _com_error(E_UNEXPECTED);
  190. _variant_t vtItemName;
  191. hr = pSdo->GetProperty(PROPERTY_SDO_DATASTORE_NAME, &vtItemName);
  192. if ( FAILED(hr) )
  193. throw _com_error(E_UNEXPECTED);
  194. hr = m_pDSContainer->Remove(NULL, V_BSTR(&vtItemName));
  195. if ( FAILED(hr) )
  196. throw _com_error(hr); // Datastore Error
  197. }
  198. p = m_Objects.erase(p);
  199. }
  200. }
  201. }
  202. catch(_com_error theError)
  203. {
  204. hr = theError.Error();
  205. IASTracePrintf("Error in SDO Collection - RemoveAll() - Caught _com_error exception: %lx...", hr);
  206. }
  207. catch(...)
  208. {
  209. hr = E_UNEXPECTED;
  210. IASTracePrintf("Error in SDO Collection - RemoveAll() - Caught unhandled exception...");
  211. }
  212. return hr;
  213. }
  214. //////////////////////////////////////////////////////////////////////////////
  215. STDMETHODIMP CSdoCollection::Reload(void)
  216. {
  217. CSdoLock theLock(*this);
  218. HRESULT hr = S_OK;
  219. try
  220. {
  221. _ASSERT ( m_fSdoInitialized );
  222. if ( ! m_fSdoInitialized )
  223. throw _com_error(E_UNEXPECTED);
  224. if ( m_pDSContainer )
  225. {
  226. ReleaseItems();
  227. hr = Load();
  228. }
  229. }
  230. catch(_com_error theError)
  231. {
  232. hr = theError.Error();
  233. IASTracePrintf("Error in SDO Collection - Reload() - Caught _com_error exception: %lx...", hr);
  234. }
  235. catch(...)
  236. {
  237. hr = E_UNEXPECTED;
  238. IASTracePrintf("Error in SDO Collection - Reload() - Caught unhandled exception...");
  239. }
  240. return hr;
  241. }
  242. //////////////////////////////////////////////////////////////////////////////
  243. STDMETHODIMP CSdoCollection::IsNameUnique(
  244. /*[in]*/ BSTR bstrName,
  245. /*[out]*/ VARIANT_BOOL* pBool
  246. )
  247. {
  248. CSdoLock theLock(*this);
  249. // Check preconditions
  250. //
  251. _ASSERT ( m_fSdoInitialized );
  252. if ( ! m_fSdoInitialized )
  253. return E_FAIL;
  254. _ASSERT ( NULL != bstrName && NULL != pBool );
  255. if ( NULL == bstrName || NULL == pBool )
  256. return E_POINTER;
  257. VARIANT_BOOL boolVal;
  258. HRESULT hr = InternalIsNameUnique(bstrName, &boolVal);
  259. if ( SUCCEEDED(hr) )
  260. *pBool = boolVal;
  261. return hr;
  262. }
  263. /////////////////////////////////////////////////////////////////////////////
  264. STDMETHODIMP CSdoCollection::Item(
  265. /*[in]*/ VARIANT* pName,
  266. /*[out]*/ IDispatch** ppItem
  267. )
  268. {
  269. CSdoLock theLock(*this);
  270. // Check preconditions
  271. //
  272. _ASSERT ( m_fSdoInitialized );
  273. if ( ! m_fSdoInitialized )
  274. return E_FAIL;
  275. _ASSERT ( NULL != pName && NULL != ppItem );
  276. if ( pName == NULL || ppItem == NULL )
  277. return E_POINTER;
  278. if ( VT_BSTR != V_VT(pName) )
  279. return E_INVALIDARG;
  280. SDO_TRACE_VERBOSE_2("Locating item '%ls' in SDO collection at $%p...", V_BSTR(pName), this);
  281. if ( m_Objects.empty() )
  282. {
  283. IASTracePrintf("Error in SDO Collection - Item() - Could not locate the specified item...");
  284. return DISP_E_MEMBERNOTFOUND;
  285. }
  286. HRESULT hr = DISP_E_MEMBERNOTFOUND;
  287. try
  288. {
  289. ISdo* pSdo;
  290. IDispatch* pDispatch;
  291. _variant_t varName;
  292. VariantArrayIterator p = m_Objects.begin();
  293. while ( p != m_Objects.end() )
  294. {
  295. pDispatch = (*p).pdispVal;
  296. hr = pDispatch->QueryInterface(IID_ISdo,(void **)&pSdo);
  297. if ( FAILED(hr) )
  298. break;
  299. hr = pSdo->GetProperty(PROPERTY_SDO_NAME, &varName);
  300. pSdo->Release();
  301. if ( FAILED(hr) )
  302. break;
  303. _ASSERT( V_VT(&varName) == VT_BSTR );
  304. if ( 0 == lstrcmpiW(V_BSTR(pName), V_BSTR(&varName)) )
  305. {
  306. (*ppItem = pDispatch)->AddRef();
  307. hr = S_OK;
  308. break;
  309. }
  310. varName.Clear();
  311. p++;
  312. hr = DISP_E_MEMBERNOTFOUND;
  313. }
  314. if ( FAILED(hr) )
  315. IASTracePrintf("Error in SDO Collection - Item() - Could not locate the specified item...");
  316. }
  317. catch(_com_error theCOMError)
  318. {
  319. hr = theCOMError.Error();
  320. IASTracePrintf("Error in SDO Collection - Item() - Caught COM exception...");
  321. }
  322. catch(...)
  323. {
  324. hr = DISP_E_MEMBERNOTFOUND;
  325. IASTracePrintf("Error in SDO Collection - Item() - Caught unknown exception...");
  326. }
  327. return hr;
  328. }
  329. /////////////////////////////////////////////////////////////////////////////
  330. STDMETHODIMP CSdoCollection::get__NewEnum(IUnknown** ppEnumSdo)
  331. {
  332. CSdoLock theLock(*this);
  333. // Check function preconditions
  334. //
  335. _ASSERT ( m_fSdoInitialized );
  336. if ( ! m_fSdoInitialized )
  337. return E_FAIL;
  338. _ASSERT ( NULL != ppEnumSdo );
  339. if (ppEnumSdo == NULL)
  340. return E_POINTER;
  341. HRESULT hr = E_FAIL;
  342. EnumVARIANT* newEnum = NULL;
  343. try
  344. {
  345. newEnum = new (std::nothrow) CComObject<EnumVARIANT>;
  346. if ( newEnum == NULL )
  347. {
  348. IASTracePrintf("Error in SDO Collection - get__NewEnum() - Out of memory...");
  349. return E_OUTOFMEMORY;
  350. }
  351. hr = newEnum->Init(
  352. m_Objects.begin(),
  353. m_Objects.end(),
  354. static_cast<IUnknown*>(this),
  355. AtlFlagCopy
  356. );
  357. if ( SUCCEEDED(hr) )
  358. {
  359. (*ppEnumSdo = newEnum)->AddRef();
  360. return S_OK;
  361. }
  362. }
  363. catch(...)
  364. {
  365. IASTracePrintf("Error in SDO Collection - get__NewEnum() - Caught unknown exception...");
  366. hr = E_FAIL;
  367. }
  368. if ( NULL != newEnum )
  369. delete newEnum;
  370. return hr;
  371. }
  372. /////////////////////////////////////////////////////////////////////////////
  373. // Collection Initialization / Shutdown Methods
  374. /////////////////////////////////////////////////////////////////////////////
  375. //////////////////////////////////////////////////////////////////////////////
  376. HRESULT CSdoCollection::InternalInitialize(
  377. /*[in]*/ LPCWSTR lpszCreateClassId,
  378. /*[in]*/ ISdoMachine* pSdoMachine,
  379. /*[in]*/ IDataStoreContainer* pDSContainer
  380. )
  381. {
  382. CSdoLock theLock(*this);
  383. // Check preconditions...
  384. //
  385. _ASSERT( ! m_fSdoInitialized );
  386. if ( m_fSdoInitialized )
  387. return S_OK;
  388. HRESULT hr = S_OK;
  389. SDO_TRACE_VERBOSE_1("SDO Collection at $%p is initializing its internal state...",this);
  390. _ASSERT( NULL != pSdoMachine );
  391. m_pSdoMachine = pSdoMachine;
  392. m_pSdoMachine->AddRef();
  393. if ( lpszCreateClassId )
  394. {
  395. m_fCreateOnAdd = true;
  396. m_CreateClassId = lpszCreateClassId;
  397. if ( NULL != pDSContainer )
  398. {
  399. m_DatastoreClass = ::GetDataStoreClass(lpszCreateClassId);
  400. m_pDSContainer = pDSContainer;
  401. m_pDSContainer->AddRef();
  402. hr = Load();
  403. }
  404. }
  405. else
  406. {
  407. // Collection of SDOs for IAS components (auditors, request handlers, protocols).
  408. // New components cannot be added to this collection by a script or UI.
  409. // Instead, component parameters and class information should be added to ias.mdb
  410. _ASSERT( pDSContainer );
  411. m_pDSContainer = pDSContainer;
  412. m_pDSContainer->AddRef();
  413. hr = Load();
  414. }
  415. if ( FAILED(hr) )
  416. InternalShutdown();
  417. else
  418. m_fSdoInitialized = TRUE;
  419. return hr;
  420. }
  421. //////////////////////////////////////////////////////////////////////////////
  422. void CSdoCollection::InternalShutdown()
  423. {
  424. ReleaseItems();
  425. if ( m_pDSContainer )
  426. m_pDSContainer->Release();
  427. if ( m_pSdoMachine )
  428. m_pSdoMachine->Release();
  429. m_fSdoInitialized = FALSE;
  430. }
  431. /////////////////////////////////////////////////////////////////////////////
  432. HRESULT CSdoCollection::InternalAdd(
  433. /*[in]*/ BSTR bstrName,
  434. /*[in/out]*/ IDispatch **ppItem
  435. )
  436. {
  437. HRESULT hr = S_OK;
  438. try
  439. {
  440. do
  441. {
  442. // Does the caller want us to create the item?
  443. //
  444. if ( NULL == *ppItem )
  445. {
  446. // Yes... Attempt to create the item
  447. //
  448. if ( ! m_fCreateOnAdd )
  449. {
  450. IASTracePrintf("Error in SDO Collection - Add() - Cannot create on add...");
  451. hr = E_INVALIDARG;
  452. break;
  453. }
  454. _ASSERT( NULL != bstrName );
  455. if ( NULL == bstrName )
  456. {
  457. IASTracePrintf("Error in SDO Collection - Add() - NULL object name...");
  458. hr = E_INVALIDARG;
  459. break;
  460. }
  461. SDO_TRACE_VERBOSE_1("Creating new item and additing it to SDO collection at $%p...",this);
  462. _variant_t varName = bstrName;
  463. CComPtr<IDataStoreObject> pDSObject;
  464. // Does the collection have a data store container associated with it?
  465. //
  466. if ( m_pDSContainer )
  467. {
  468. // Yes... Create a new data store object and associate it with the SDO
  469. //
  470. hr = m_pDSContainer->Create(
  471. m_DatastoreClass,
  472. bstrName,
  473. &pDSObject
  474. );
  475. if ( FAILED(hr) )
  476. {
  477. IASTracePrintf("Error in SDO Collection - Add() - Could not create a data store object...");
  478. break;
  479. }
  480. }
  481. CComPtr<ISdo> pSdo;
  482. pSdo.p = ::MakeSDO(
  483. bstrName,
  484. m_CreateClassId,
  485. m_pSdoMachine,
  486. pDSObject,
  487. static_cast<ISdoCollection*>(this),
  488. true
  489. );
  490. if ( NULL == pSdo.p )
  491. {
  492. IASTracePrintf("Error in Collection SDO - Add() - MakeSDO() failed...");
  493. hr = E_FAIL;
  494. break;
  495. }
  496. CComPtr<IDispatch> pDispatch;
  497. hr = pSdo->QueryInterface(IID_IDispatch, (void**)&pDispatch);
  498. if ( FAILED(hr) )
  499. {
  500. IASTracePrintf("Error in SDO Collection - Add() - QueryInterface(IID_IDispatch) failed...");
  501. break;
  502. }
  503. m_Objects.push_back((IDispatch*)pDispatch.p);
  504. (*ppItem = pDispatch.p)->AddRef();
  505. }
  506. else
  507. {
  508. // No... Just add the specified item to the collection
  509. //
  510. m_Objects.push_back(*ppItem);
  511. }
  512. } while ( FALSE );
  513. }
  514. catch (bad_alloc)
  515. {
  516. IASTracePrintf("Error in SDO Collection - Add() - Out of memory...");
  517. hr = E_OUTOFMEMORY;
  518. }
  519. catch(...)
  520. {
  521. IASTracePrintf("Error in SDO Collection - Add() - Caught unhandled exception...");
  522. hr = E_FAIL;
  523. }
  524. return hr;
  525. }
  526. //////////////////////////////////////////////////////////////////////////////
  527. HRESULT CSdoCollection::InternalIsNameUnique(
  528. /*[in]*/ BSTR bstrName,
  529. /*[out]*/ VARIANT_BOOL* pBool
  530. )
  531. {
  532. _variant_t vtSdoName;
  533. VariantArrayIterator p = m_Objects.begin();
  534. while ( p != m_Objects.end() )
  535. {
  536. if ( FAILED((dynamic_cast<ISdo*>((*p).pdispVal))->GetProperty(PROPERTY_SDO_NAME, &vtSdoName)) )
  537. {
  538. IASTracePrintf("Error in SDO Collection - GetProperty(PROPERTY_SDO_NAME) failed...");
  539. *pBool = VARIANT_FALSE;
  540. return E_FAIL;
  541. }
  542. if ( 0 == lstrcmpi(bstrName, V_BSTR(&vtSdoName)) )
  543. {
  544. IASTracePrintf("Error in SDO Collection - Add() - Sdo Name is Not Unique...");
  545. *pBool = VARIANT_FALSE;
  546. return S_OK;
  547. }
  548. vtSdoName.Clear();
  549. p++;
  550. }
  551. *pBool = VARIANT_TRUE;
  552. return S_OK;
  553. }
  554. //////////////////////////////////////////////////////////////////////////////
  555. HRESULT CSdoCollection::Load()
  556. {
  557. CSdoLock theLock(*this);
  558. HRESULT hr = E_FAIL;
  559. _ASSERT ( m_pDSContainer );
  560. if ( m_pDSContainer )
  561. {
  562. SDO_TRACE_VERBOSE_1("SDO Collection at $%p is loading its items from the data store...",this);
  563. CComPtr<IUnknown> pUnknown;
  564. hr = m_pDSContainer->get__NewEnum(&pUnknown);
  565. if ( FAILED(hr) )
  566. {
  567. IASTracePrintf("Error in SDO Collection SDO - Load() - IDataStoreContainer::get__NewEnum() failed...");
  568. return E_FAIL;
  569. }
  570. CComPtr<IEnumVARIANT> pEnumVariant;
  571. hr = pUnknown->QueryInterface(IID_IEnumVARIANT, (void**)&pEnumVariant);
  572. if ( FAILED(hr) )
  573. {
  574. IASTracePrintf("Error in SDO Collection SDO - Load() - QueryInterface(IID_IEnumVARIANT) failed...");
  575. return E_FAIL;
  576. }
  577. CComBSTR bstrClassID(SDO_STOCK_PROPERTY_CLASS_ID);
  578. if (!bstrClassID) { return E_OUTOFMEMORY; }
  579. CComPtr<IDataStoreObject> pDSObject;
  580. CComPtr<ISdo> pSdoArchive;
  581. CComPtr<IDispatch> pDispatch;
  582. CComPtr<ISdo> pSdo;
  583. hr = ::SDONextObjectFromContainer(pEnumVariant, &pDSObject);
  584. while ( S_OK == hr )
  585. {
  586. if ( 0 == m_CreateClassId.length() )
  587. {
  588. _variant_t vtComponentClassId;
  589. hr = pDSObject->GetValue(bstrClassID, &vtComponentClassId);
  590. if ( FAILED(hr) )
  591. {
  592. IASTracePrintf("Error in SDO Collection SDO - LoadSdo() - IDataStoreObject::GetValue() failed...");
  593. break;
  594. }
  595. pSdo.p = ::MakeSDO(
  596. NULL,
  597. V_BSTR(&vtComponentClassId),
  598. m_pSdoMachine,
  599. pDSObject.p,
  600. static_cast<ISdoCollection*>(this),
  601. false
  602. );
  603. }
  604. else
  605. {
  606. pSdo.p = ::MakeSDO(
  607. NULL,
  608. m_CreateClassId,
  609. m_pSdoMachine,
  610. pDSObject.p,
  611. static_cast<ISdoCollection*>(this),
  612. false
  613. );
  614. }
  615. if ( NULL == pSdo.p )
  616. {
  617. IASTracePrintf("Error in SDO Collection SDO - LoadSdo() - MakeSDO() failed...");
  618. break;
  619. }
  620. hr = pSdo->QueryInterface(IID_IDispatch, (void**)&pDispatch);
  621. if ( FAILED(hr) )
  622. {
  623. IASTracePrintf("Error in SDO Collection SDO - Load() - QueryInterface(IID_IDispatch) failed...");
  624. break;
  625. }
  626. _variant_t vtName;
  627. hr = pSdo->GetProperty(PROPERTY_SDO_NAME, &vtName);
  628. if ( FAILED(hr) )
  629. {
  630. IASTracePrintf("Error in SDO Collection SDO - Load() - GetProperty(PROPERTY_SDO_NAME) failed...");
  631. break;
  632. }
  633. hr = InternalAdd(V_BSTR(&vtName), &pDispatch.p);
  634. if ( FAILED(hr) )
  635. break;
  636. vtName.Clear();
  637. pDispatch.Release();
  638. pDSObject.Release();
  639. pSdo.Release();
  640. hr = ::SDONextObjectFromContainer(pEnumVariant, &pDSObject);
  641. }
  642. if ( S_FALSE == hr )
  643. hr = S_OK;
  644. }
  645. return hr;
  646. }
  647. //////////////////////////////////////////////////////////////////////////////
  648. void CSdoCollection::ReleaseItems()
  649. {
  650. if ( ! m_Objects.empty() )
  651. {
  652. VariantArrayIterator p = m_Objects.begin();
  653. while( p != m_Objects.end() )
  654. p = m_Objects.erase(p);
  655. }
  656. }