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.

2214 lines
67 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1997-2002 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // ClusResG.cpp
  7. //
  8. // Description:
  9. // Implementation of the resource group classes for the MSCLUS
  10. // automation classes.
  11. //
  12. // Author:
  13. // Charles Stacy Harris (stacyh) 28-Feb-1997
  14. // Galen Barbee (galenb) July 1998
  15. //
  16. // Revision History:
  17. // July 1998 GalenB Maaaaaajjjjjjjjjoooooorrrr clean up
  18. //
  19. // Notes:
  20. //
  21. /////////////////////////////////////////////////////////////////////////////
  22. #include "stdafx.h"
  23. #include "ClusterObject.h"
  24. #include "property.h"
  25. #include "clusres.h"
  26. #include "clusresg.h"
  27. #include "clusneti.h"
  28. #include "clusnode.h"
  29. /////////////////////////////////////////////////////////////////////////////
  30. // Global variables
  31. /////////////////////////////////////////////////////////////////////////////
  32. static const IID * iidCClusResGroup[] =
  33. {
  34. &IID_ISClusResGroup
  35. };
  36. static const IID * iidCClusResGroups[] =
  37. {
  38. &IID_ISClusResGroups
  39. };
  40. //*************************************************************************//
  41. /////////////////////////////////////////////////////////////////////////////
  42. // CClusResGroup class
  43. /////////////////////////////////////////////////////////////////////////////
  44. /////////////////////////////////////////////////////////////////////////////
  45. //++
  46. //
  47. // CClusResGroup::CClusResGroup
  48. //
  49. // Description:
  50. // Constructor.
  51. //
  52. // Arguments:
  53. // None.
  54. //
  55. // Return Value:
  56. // None.
  57. //
  58. //--
  59. /////////////////////////////////////////////////////////////////////////////
  60. CClusResGroup::CClusResGroup( void )
  61. {
  62. m_hGroup = NULL;
  63. m_pClusRefObject = NULL;
  64. m_pClusterResources = NULL;
  65. m_pPreferredOwnerNodes = NULL;
  66. m_pCommonProperties = NULL;
  67. m_pPrivateProperties = NULL;
  68. m_pCommonROProperties = NULL;
  69. m_pPrivateROProperties = NULL;
  70. m_piids = (const IID *) iidCClusResGroup;
  71. m_piidsSize = ARRAYSIZE( iidCClusResGroup );
  72. } //*** CClusResGroup::CClusResGroup()
  73. /////////////////////////////////////////////////////////////////////////////
  74. //++
  75. //
  76. // CClusResGroup::~CClusResGroup
  77. //
  78. // Description:
  79. // Destructor.
  80. //
  81. // Arguments:
  82. // None.
  83. //
  84. // Return Value:
  85. // None.
  86. //
  87. //--
  88. /////////////////////////////////////////////////////////////////////////////
  89. CClusResGroup::~CClusResGroup( void )
  90. {
  91. // m_hGroup will be auto released
  92. if ( m_pClusterResources != NULL )
  93. {
  94. m_pClusterResources->Release();
  95. m_pClusterResources = NULL;
  96. }
  97. if ( m_pPreferredOwnerNodes != NULL )
  98. {
  99. m_pPreferredOwnerNodes->Release();
  100. m_pPreferredOwnerNodes = NULL;
  101. }
  102. if ( m_pCommonProperties != NULL )
  103. {
  104. m_pCommonProperties->Release();
  105. m_pCommonProperties = NULL;
  106. } // if: release the property collection
  107. if ( m_pPrivateProperties != NULL )
  108. {
  109. m_pPrivateProperties->Release();
  110. m_pPrivateProperties = NULL;
  111. } // if: release the property collection
  112. if ( m_pCommonROProperties != NULL )
  113. {
  114. m_pCommonROProperties->Release();
  115. m_pCommonROProperties = NULL;
  116. } // if: release the property collection
  117. if ( m_pPrivateROProperties != NULL )
  118. {
  119. m_pPrivateROProperties->Release();
  120. m_pPrivateROProperties = NULL;
  121. } // if: release the property collection
  122. if ( m_pClusRefObject != NULL )
  123. {
  124. m_pClusRefObject->Release();
  125. m_pClusRefObject = NULL;
  126. }
  127. } //*** CClusResGroup::~CClusResGroup()
  128. /////////////////////////////////////////////////////////////////////////////
  129. //++
  130. //
  131. // CClusResGroup::Create
  132. //
  133. // Description:
  134. // Finish the heavy weight construction.
  135. //
  136. // Arguments:
  137. // pClusRefObject [IN] - Wraps the cluster handle.
  138. // bstrGroupName [IN] - The name of this group.
  139. //
  140. // Return Value:
  141. // S_OK if successful, E_POINTER, or Win32 error as HRESULT.
  142. //
  143. //--
  144. /////////////////////////////////////////////////////////////////////////////
  145. HRESULT CClusResGroup::Create(
  146. IN ISClusRefObject * pClusRefObject,
  147. IN BSTR bstrGroupName
  148. )
  149. {
  150. ASSERT( pClusRefObject != NULL );
  151. ASSERT( bstrGroupName != NULL );
  152. HRESULT _hr = E_POINTER;
  153. if ( ( pClusRefObject != NULL ) && ( bstrGroupName != NULL ) )
  154. {
  155. m_pClusRefObject = pClusRefObject;
  156. m_pClusRefObject->AddRef();
  157. HCLUSTER _hCluster = 0;
  158. _hr = m_pClusRefObject->get_Handle((ULONG_PTR *) &_hCluster);
  159. if ( SUCCEEDED( _hr ) )
  160. {
  161. HGROUP hGroup = ::CreateClusterGroup( _hCluster, bstrGroupName );
  162. if ( hGroup == 0 )
  163. {
  164. DWORD _sc = GetLastError();
  165. _hr = HRESULT_FROM_WIN32( _sc );
  166. }
  167. else
  168. {
  169. m_hGroup = CRefCountedHandle<GroupHandle>::Create(hGroup);
  170. if (m_hGroup == 0)
  171. {
  172. DWORD _sc = GetLastError();
  173. ::CloseClusterGroup(hGroup);
  174. _hr = HRESULT_FROM_WIN32( _sc );
  175. }
  176. else
  177. {
  178. m_bstrGroupName = bstrGroupName;
  179. _hr = S_OK;
  180. }
  181. }
  182. }
  183. }
  184. /*
  185. if ( _hr == S_OK )
  186. {
  187. OutputDebugStringW( L"CClusResGroup::Create() succeeded.\n" );
  188. } // if: success!
  189. else
  190. {
  191. WCHAR sz[ 256 ];
  192. _snwprintf( sz, RTL_NUMBER_OF( sz ), L"CClusResGroup::Create() failed. (hr = %#08x)\n", _hr );
  193. OutputDebugStringW( sz );
  194. } // else: failure...
  195. */
  196. return _hr;
  197. } //*** CClusResGroup::Create()
  198. /////////////////////////////////////////////////////////////////////////////
  199. //++
  200. //
  201. // CClusResGroup::Open
  202. //
  203. // Description:
  204. // Open the passed group on the cluster.
  205. //
  206. // Arguments:
  207. // pClusRefObject [IN] - Wraps the cluster handle.
  208. // bstrGroupName [IN] - The name of this group.
  209. //
  210. // Return Value:
  211. // S_OK if successful, E_POINTER, or Win32 error as HRESULT.
  212. //
  213. //--
  214. /////////////////////////////////////////////////////////////////////////////
  215. HRESULT CClusResGroup::Open(
  216. IN ISClusRefObject * pClusRefObject,
  217. IN BSTR bstrGroupName
  218. )
  219. {
  220. ASSERT( pClusRefObject != NULL );
  221. ASSERT( bstrGroupName != NULL );
  222. HRESULT _hr = E_POINTER;
  223. if ( ( pClusRefObject != NULL ) && ( bstrGroupName != NULL ) )
  224. {
  225. m_pClusRefObject = pClusRefObject;
  226. m_pClusRefObject->AddRef();
  227. HCLUSTER _hCluster = NULL;
  228. _hr = m_pClusRefObject->get_Handle( (ULONG_PTR *) &_hCluster );
  229. if ( SUCCEEDED( _hr ) )
  230. {
  231. HGROUP hGroup = ::OpenClusterGroup( _hCluster, bstrGroupName );
  232. if ( hGroup == NULL )
  233. {
  234. DWORD _sc = GetLastError();
  235. _hr = HRESULT_FROM_WIN32( _sc );
  236. }
  237. else
  238. {
  239. m_hGroup = CRefCountedHandle<GroupHandle>::Create(hGroup);
  240. if ( m_hGroup == NULL )
  241. {
  242. DWORD _sc = GetLastError();
  243. ::CloseClusterGroup(hGroup);
  244. _hr = HRESULT_FROM_WIN32( _sc );
  245. }
  246. else
  247. {
  248. m_bstrGroupName = bstrGroupName;
  249. _hr = S_OK;
  250. }
  251. }
  252. }
  253. }
  254. return _hr;
  255. } //*** CClusResGroup::Open()
  256. /////////////////////////////////////////////////////////////////////////////
  257. //++
  258. //
  259. // CClusResGroup::GetProperties
  260. //
  261. // Description:
  262. // Creates a property collection for this object type (Resource Group).
  263. //
  264. // Arguments:
  265. // ppProperties [OUT] - Catches the newly created collection.
  266. // bPrivate [IN] - Are these private properties? Or Common?
  267. // bReadOnly [IN] - Are these read only properties?
  268. //
  269. // Return Value:
  270. // S_OK if successful, or other HRESULT error.
  271. //
  272. //--
  273. /////////////////////////////////////////////////////////////////////////////
  274. HRESULT CClusResGroup::GetProperties(
  275. ISClusProperties ** ppProperties,
  276. BOOL bPrivate,
  277. BOOL bReadOnly
  278. )
  279. {
  280. //ASSERT( ppProperties != NULL );
  281. HRESULT _hr = E_POINTER;
  282. if ( ppProperties != NULL )
  283. {
  284. CComObject<CClusProperties> * pProperties = NULL;
  285. *ppProperties = NULL;
  286. _hr = CComObject< CClusProperties >::CreateInstance( &pProperties );
  287. if ( SUCCEEDED( _hr ) )
  288. {
  289. CSmartPtr< CComObject< CClusProperties > > ptrProperties( pProperties );
  290. _hr = ptrProperties->Create( this, bPrivate, bReadOnly );
  291. if ( SUCCEEDED( _hr ) )
  292. {
  293. _hr = ptrProperties->Refresh();
  294. if ( SUCCEEDED( _hr ) )
  295. {
  296. _hr = ptrProperties->QueryInterface( IID_ISClusProperties, (void **) ppProperties );
  297. if ( SUCCEEDED( _hr ) )
  298. {
  299. ptrProperties->AddRef();
  300. if ( bPrivate )
  301. {
  302. if ( bReadOnly )
  303. {
  304. m_pPrivateROProperties = pProperties;
  305. }
  306. else
  307. {
  308. m_pPrivateProperties = pProperties;
  309. }
  310. }
  311. else
  312. {
  313. if ( bReadOnly )
  314. {
  315. m_pCommonROProperties = pProperties;
  316. }
  317. else
  318. {
  319. m_pCommonProperties = pProperties;
  320. }
  321. }
  322. }
  323. }
  324. }
  325. }
  326. }
  327. return _hr;
  328. } //*** CClusResGroup::GetProperties()
  329. /////////////////////////////////////////////////////////////////////////////
  330. //++
  331. //
  332. // CClusResGroup::get_Handle
  333. //
  334. // Description:
  335. // Returns the handle to this object (Group).
  336. //
  337. // Arguments:
  338. // phandle [OUT] - Catches the handle.
  339. //
  340. // Return Value:
  341. // S_OK if successful, or E_POINTER if not.
  342. //
  343. //--
  344. /////////////////////////////////////////////////////////////////////////////
  345. STDMETHODIMP CClusResGroup::get_Handle( OUT ULONG_PTR * phandle )
  346. {
  347. //ASSERT( phandle != NULL );
  348. HRESULT _hr = E_POINTER;
  349. if ( phandle != NULL )
  350. {
  351. *phandle = (ULONG_PTR)m_hGroup->get_Handle();
  352. _hr = S_OK;
  353. }
  354. return _hr;
  355. } //*** CClusResGroup::get_Handle()
  356. /////////////////////////////////////////////////////////////////////////////
  357. //++
  358. //
  359. // CClusResGroup::Close
  360. //
  361. // Description:
  362. // Close the handle to the cluster object (Group).
  363. //
  364. // Arguments:
  365. // None.
  366. //
  367. // Return Value:
  368. // S_OK if successful, or Win32 error as HRESULT if not.
  369. //
  370. //--
  371. /////////////////////////////////////////////////////////////////////////////
  372. STDMETHODIMP CClusResGroup::Close( void )
  373. {
  374. if ( m_pClusRefObject )
  375. {
  376. m_pClusRefObject->Release();
  377. m_pClusRefObject = NULL;
  378. }
  379. // SmartPointer will deref the handle properly when assigned NULL
  380. m_hGroup = NULL;
  381. return S_OK;
  382. } //*** CClusResGroup::Close()
  383. /////////////////////////////////////////////////////////////////////////////
  384. //++
  385. //
  386. // CClusResGroup::put_Name
  387. //
  388. // Description:
  389. // Change the name of this object (Group).
  390. //
  391. // Arguments:
  392. // bstrGroupName [IN] - The new name.
  393. //
  394. // Return Value:
  395. // S_OK if successful, E_POINTER, or Win32 error as HRESULT if not.
  396. //
  397. //--
  398. /////////////////////////////////////////////////////////////////////////////
  399. STDMETHODIMP CClusResGroup::put_Name( IN BSTR bstrGroupName )
  400. {
  401. //ASSERT( bstrGroupName != NULL );
  402. HRESULT _hr = E_POINTER;
  403. if ( bstrGroupName != NULL )
  404. {
  405. DWORD _sc = ::SetClusterGroupName( m_hGroup->get_Handle(), bstrGroupName );
  406. if ( _sc == ERROR_SUCCESS )
  407. {
  408. m_bstrGroupName = bstrGroupName;
  409. }
  410. _hr = HRESULT_FROM_WIN32( _sc );
  411. }
  412. return _hr;
  413. } //*** CClusResGroup::put_Name()
  414. /////////////////////////////////////////////////////////////////////////////
  415. //++
  416. //
  417. // CClusResGroup::get_Name
  418. //
  419. // Description:
  420. // Return the name of this object (Resource Group).
  421. //
  422. // Arguments:
  423. // pbstrGroupName [OUT] - Catches the name of this object.
  424. //
  425. // Return Value:
  426. // S_OK if successful, or E_POINTER if not.
  427. //
  428. //--
  429. /////////////////////////////////////////////////////////////////////////////
  430. STDMETHODIMP CClusResGroup::get_Name( OUT BSTR * pbstrGroupName )
  431. {
  432. //ASSERT( pbstrGroupName != NULL );
  433. HRESULT _hr = E_POINTER;
  434. if ( pbstrGroupName != NULL )
  435. {
  436. *pbstrGroupName = m_bstrGroupName.Copy();
  437. _hr = S_OK;
  438. }
  439. return _hr;
  440. } //*** CClusResGroup::get_Name()
  441. /////////////////////////////////////////////////////////////////////////////
  442. //++
  443. //
  444. // CClusResGroup::get_State
  445. //
  446. // Description:
  447. // Returns the current cluster group state for this group.
  448. //
  449. // Arguments:
  450. // pcgsState [OUT] - Catches the cluster group state.
  451. //
  452. // Return Value:
  453. // S_OK if successful, E_POINTER, or Win32 error as HRESULT if not.
  454. //
  455. //--
  456. /////////////////////////////////////////////////////////////////////////////
  457. STDMETHODIMP CClusResGroup::get_State( OUT CLUSTER_GROUP_STATE * pcgsState )
  458. {
  459. //ASSERT( pcgsState != NULL );
  460. HRESULT _hr = E_POINTER;
  461. if ( pcgsState != NULL )
  462. {
  463. CLUSTER_GROUP_STATE _cgsState = ::WrapGetClusterGroupState( m_hGroup->get_Handle(), NULL );
  464. if ( _cgsState == ClusterGroupStateUnknown )
  465. {
  466. DWORD _sc = GetLastError();
  467. _hr = HRESULT_FROM_WIN32( _sc );
  468. }
  469. else
  470. {
  471. *pcgsState = _cgsState;
  472. _hr = S_OK;
  473. }
  474. }
  475. return _hr;
  476. } //*** CClusResGroup::get_State()
  477. /////////////////////////////////////////////////////////////////////////////
  478. //++
  479. //
  480. // CClusResGroup::get_OwnerNode
  481. //
  482. // Description:
  483. // Returns the owner node for this group. The owner node is the node
  484. // where the group is currently online.
  485. //
  486. // Arguments:
  487. // ppOwnerNode [OUT[ - Catches the owner node interface.
  488. //
  489. // Return Value:
  490. // S_OK if successful, E_POINTER, or Win32 error as HRESULT if not.
  491. //
  492. //--
  493. /////////////////////////////////////////////////////////////////////////////
  494. STDMETHODIMP CClusResGroup::get_OwnerNode( OUT ISClusNode ** ppOwnerNode )
  495. {
  496. //ASSERT( ppOwnerNode != NULL );
  497. HRESULT _hr = E_POINTER;
  498. if ( ppOwnerNode != NULL )
  499. {
  500. DWORD _sc = 0;
  501. PWCHAR pwszNodeName = NULL;
  502. CLUSTER_GROUP_STATE cgs = ClusterGroupStateUnknown;
  503. cgs = WrapGetClusterGroupState( m_hGroup->get_Handle(), &pwszNodeName );
  504. if ( cgs != ClusterGroupStateUnknown )
  505. {
  506. CComObject<CClusNode> * pNode = NULL;
  507. *ppOwnerNode = NULL;
  508. _hr = CComObject<CClusNode>::CreateInstance( &pNode );
  509. if ( SUCCEEDED( _hr ) )
  510. {
  511. CSmartPtr< ISClusRefObject > ptrRefObject( m_pClusRefObject );
  512. BSTR bstr = NULL;
  513. bstr = SysAllocString( pwszNodeName );
  514. if ( bstr == NULL )
  515. {
  516. _hr = E_OUTOFMEMORY;
  517. }
  518. else
  519. {
  520. pNode->AddRef();
  521. _hr = pNode->Open( ptrRefObject, bstr );
  522. if ( SUCCEEDED( _hr ) )
  523. {
  524. _hr = pNode->QueryInterface( IID_ISClusNode, (void **) ppOwnerNode );
  525. }
  526. pNode->Release();
  527. SysFreeString( bstr );
  528. }
  529. }
  530. ::LocalFree( pwszNodeName );
  531. }
  532. else
  533. {
  534. _sc = GetLastError();
  535. _hr = HRESULT_FROM_WIN32( _sc );
  536. }
  537. }
  538. return _hr;
  539. } //*** CClusResGroup::get_OwnerNode()
  540. /////////////////////////////////////////////////////////////////////////////
  541. //++
  542. //
  543. // CClusResGroup::get_Resources
  544. //
  545. // Description:
  546. // Returns the collection of resources that belong to this group.
  547. //
  548. // Arguments:
  549. // ppClusterGroupResources [OUT] - Catches the collection.
  550. //
  551. // Return Value:
  552. // S_OK if successful, E_POINTER, or other HRESULT error if not.
  553. //
  554. //--
  555. /////////////////////////////////////////////////////////////////////////////
  556. STDMETHODIMP CClusResGroup::get_Resources(
  557. OUT ISClusResGroupResources ** ppClusterGroupResources
  558. )
  559. {
  560. return ::HrCreateResourceCollection< CClusResGroupResources, ISClusResGroupResources, CRefcountedHGROUP >(
  561. &m_pClusterResources,
  562. m_hGroup,
  563. ppClusterGroupResources,
  564. IID_ISClusResGroupResources,
  565. m_pClusRefObject
  566. );
  567. } //*** CClusResGroup::get_Resources()
  568. /////////////////////////////////////////////////////////////////////////////
  569. //++
  570. //
  571. // CClusResGroup::get_PreferredOwnerNodes
  572. //
  573. // Description:
  574. // Returns the collection of preferred owner nodes for this group.
  575. //
  576. // Arguments:
  577. // ppOwnerNodes [OUT] - Catches the collection.
  578. //
  579. // Return Value:
  580. // S_OK if successful, E_POINTER, or other HRESULT error if not.
  581. //
  582. //--
  583. /////////////////////////////////////////////////////////////////////////////
  584. STDMETHODIMP CClusResGroup::get_PreferredOwnerNodes(
  585. ISClusResGroupPreferredOwnerNodes ** ppOwnerNodes
  586. )
  587. {
  588. return ::HrCreateResourceCollection< CClusResGroupPreferredOwnerNodes, ISClusResGroupPreferredOwnerNodes, CRefcountedHGROUP >(
  589. &m_pPreferredOwnerNodes,
  590. m_hGroup,
  591. ppOwnerNodes,
  592. IID_ISClusResGroupPreferredOwnerNodes,
  593. m_pClusRefObject
  594. );
  595. } //*** CClusResGroup::get_PreferredOwnerNodes()
  596. /////////////////////////////////////////////////////////////////////////////
  597. //++
  598. //
  599. // CClusResGroup::Delete
  600. //
  601. // Description:
  602. // Removes this object (Resource Group) from the cluster.
  603. //
  604. // Arguments:
  605. // None.
  606. //
  607. // Return Value:
  608. // S_OK if successful, or other HRESULT error.
  609. //
  610. //--
  611. /////////////////////////////////////////////////////////////////////////////
  612. STDMETHODIMP CClusResGroup::Delete( void )
  613. {
  614. DWORD _sc = ERROR_INVALID_HANDLE;
  615. if ( m_hGroup != NULL )
  616. {
  617. _sc = DeleteClusterGroup( m_hGroup->get_Handle() );
  618. if ( _sc == ERROR_SUCCESS )
  619. {
  620. m_hGroup = NULL;
  621. }
  622. }
  623. /*
  624. if ( _sc == ERROR_SUCCESS )
  625. {
  626. OutputDebugStringW( L"CClusResGroup::Delete() succeeded.\n" );
  627. } // if: success
  628. else
  629. {
  630. WCHAR sz[ 256 ];
  631. _snwprintf( sz, RTL_NUMBER_OF( sz ), L"CClusResGroup::Delete() failed. (handle = %d) (sc = %#08x)\n", m_hGroup->get_Handle(), _sc );
  632. OutputDebugStringW( sz );
  633. } // else: failure...
  634. */
  635. return HRESULT_FROM_WIN32( _sc );
  636. } //*** CClusResGroup::Delete()
  637. /////////////////////////////////////////////////////////////////////////////
  638. //++
  639. //
  640. // CClusResGroup::Online
  641. //
  642. // Description:
  643. // Bring this group online on the passed in node, or on to the node
  644. // it is currently offline if no node is specified.
  645. //
  646. // Arguments:
  647. // varTimeout [IN] - How long in seconds to wait for the group to
  648. // come online.
  649. // varNode [IN] - Node to bring the group online.
  650. // pvarPending [OUT] - Catches the pending state. True if we timed
  651. // out before the group came completely online.
  652. //
  653. // Return Value:
  654. // S_OK if successful, or other Win32 error as HRESULT.
  655. //
  656. //--
  657. /////////////////////////////////////////////////////////////////////////////
  658. STDMETHODIMP CClusResGroup::Online(
  659. IN VARIANT varTimeout,
  660. IN VARIANT varNode,
  661. OUT VARIANT * pvarPending
  662. )
  663. {
  664. //ASSERT( pNode != NULL );
  665. //ASSERT( pvarPending != NULL );
  666. HRESULT _hr = E_POINTER;
  667. if ( pvarPending != NULL )
  668. {
  669. _hr = ::VariantChangeTypeEx( &varTimeout, &varTimeout, LOCALE_SYSTEM_DEFAULT, 0, VT_I4 );
  670. if ( SUCCEEDED( _hr ) )
  671. {
  672. HNODE _hNode = NULL;
  673. HCLUSTER _hCluster = NULL;
  674. CComObject< CClusNode > * _pcnNode = NULL;
  675. ISClusNode * _piscNode = NULL;
  676. pvarPending->vt = VT_BOOL;
  677. pvarPending->boolVal = VARIANT_FALSE;
  678. _hr = m_pClusRefObject->get_Handle( (ULONG_PTR *) &_hCluster );
  679. if ( SUCCEEDED( _hr ) )
  680. {
  681. if ( varNode.vt == ( VT_VARIANT | VT_BYREF ) )
  682. {
  683. if ( varNode.pvarVal != NULL )
  684. {
  685. IDispatch * _pidNode = varNode.pvarVal->pdispVal;
  686. _hr = _pidNode->QueryInterface( IID_ISClusNode, (void **) &_piscNode );
  687. if ( SUCCEEDED( _hr ) )
  688. {
  689. _hr = _piscNode->get_Handle( (ULONG_PTR *) &_hNode );
  690. _piscNode->Release();
  691. } // if: did we get the ISClusNode interface?
  692. } // if: we have a variant value pointer
  693. } // if: was the option parameter present?
  694. else if ( varNode.vt == VT_DISPATCH )
  695. {
  696. IDispatch * _pidNode = varNode.pdispVal;
  697. _hr = _pidNode->QueryInterface( IID_ISClusNode, (void **) &_piscNode );
  698. if ( SUCCEEDED( _hr ) )
  699. {
  700. _hr = _piscNode->get_Handle( (ULONG_PTR *) &_hNode );
  701. _piscNode->Release();
  702. } // if: did we get the ISClusNode interface?
  703. } // else if: we have a dispatch variant
  704. else if ( varNode.vt == VT_BSTR )
  705. {
  706. _hr = CComObject< CClusNode >::CreateInstance( &_pcnNode );
  707. if ( SUCCEEDED( _hr ) )
  708. {
  709. _pcnNode->AddRef();
  710. _hr = _pcnNode->Open( m_pClusRefObject, ( varNode.vt & VT_BYREF) ? (*varNode.pbstrVal) : varNode.bstrVal );
  711. if ( SUCCEEDED( _hr ) )
  712. {
  713. _hr = _pcnNode->get_Handle( (ULONG_PTR *) &_hNode );
  714. } // if:
  715. } // if:
  716. } // else if: we have a string variant
  717. else if ( varNode.vt == VT_EMPTY )
  718. {
  719. _hNode = NULL;
  720. } // else if: it is empty
  721. else if ( ( varNode.vt == VT_ERROR ) && ( varNode.scode == DISP_E_PARAMNOTFOUND ) )
  722. {
  723. _hNode = NULL;
  724. } // else if: the optional parameter was not specified
  725. else
  726. {
  727. _hr = ::VariantChangeTypeEx( &varNode, &varNode, LOCALE_SYSTEM_DEFAULT, 0, VT_I4 );
  728. if ( SUCCEEDED( _hr ) )
  729. {
  730. if ( varNode.lVal != 0 )
  731. {
  732. _hr = E_INVALIDARG;
  733. } // if: this is not zero then we cannot accept this parameter format. If varNode.lVal was zero then we could assume it was a NULL arg...
  734. } // if: coerce to a long
  735. } // else: the node variant could be invalid -- check for a zero, and if found treat it like a NULL...
  736. if ( SUCCEEDED( _hr ) )
  737. {
  738. BOOL bPending = FALSE;
  739. _hr = ::HrWrapOnlineClusterGroup(
  740. _hCluster,
  741. m_hGroup->get_Handle(),
  742. _hNode,
  743. varTimeout.lVal,
  744. (long *) &bPending
  745. );
  746. if ( SUCCEEDED( _hr ) )
  747. {
  748. if ( bPending )
  749. {
  750. pvarPending->boolVal = VARIANT_TRUE;
  751. } // if: pending?
  752. } // if: online succeeded
  753. } // if: we have a node handle
  754. } // if: get_Handle() -- cluster handle
  755. if ( _pcnNode != NULL )
  756. {
  757. _pcnNode->Release();
  758. } // if: did we create a node?
  759. } // if: wasn't the right type
  760. } //if: pvarPending != NULL
  761. return _hr;
  762. } //*** CClusResGroup::Online()
  763. /////////////////////////////////////////////////////////////////////////////
  764. //++
  765. //
  766. // CClusResGroup::Move
  767. //
  768. // Description:
  769. // Move this group to the passed in node, or to the best available node
  770. // if no node was passed, and restore its online state.
  771. //
  772. // Arguments:
  773. // varTimeout [IN] - How long in seconds to wait for the group to
  774. // come move and complete stat restoration.
  775. // varNode [IN] - Node to move the group to.
  776. // pvarPending [OUT] - Catches the pending state. True if we timed
  777. // out before the group came completely online.
  778. //
  779. // Return Value:
  780. // S_OK if successful, or other Win32 error as HRESULT.
  781. //
  782. //--
  783. /////////////////////////////////////////////////////////////////////////////
  784. STDMETHODIMP CClusResGroup::Move(
  785. IN VARIANT varTimeout,
  786. IN VARIANT varNode,
  787. OUT VARIANT * pvarPending
  788. )
  789. {
  790. //ASSERT( pNode != NULL );
  791. //ASSERT( pvarPending != NULL );
  792. HRESULT _hr = E_POINTER;
  793. if ( pvarPending != NULL )
  794. {
  795. _hr = ::VariantChangeTypeEx( &varTimeout, &varTimeout, LOCALE_SYSTEM_DEFAULT, 0, VT_I4 );
  796. if ( SUCCEEDED( _hr ) )
  797. {
  798. HNODE _hNode = NULL;
  799. HCLUSTER _hCluster = NULL;
  800. CComObject< CClusNode > * _pcnNode = NULL;
  801. ISClusNode * _piscNode = NULL;
  802. pvarPending->vt = VT_BOOL;
  803. pvarPending->boolVal = VARIANT_FALSE;
  804. _hr = m_pClusRefObject->get_Handle( (ULONG_PTR *) &_hCluster );
  805. if ( SUCCEEDED( _hr ) )
  806. {
  807. if ( varNode.vt == ( VT_VARIANT | VT_BYREF ) )
  808. {
  809. ASSERT( varNode.pvarVal != NULL );
  810. VARIANT * _pvar = varNode.pvarVal;
  811. if ( _pvar->vt == VT_DISPATCH )
  812. {
  813. IDispatch * _pidNode = _pvar->pdispVal;
  814. _hr = _pidNode->QueryInterface( IID_ISClusNode, (void **) &_piscNode );
  815. if ( SUCCEEDED( _hr ) )
  816. {
  817. _hr = _piscNode->get_Handle( (ULONG_PTR *) &_hNode );
  818. _piscNode->Release();
  819. } // if: did we get the ISClusNode interface?
  820. } // if: variant value point is to an IDispatch
  821. else if ( _pvar->vt == VT_BSTR )
  822. {
  823. _hr = CComObject< CClusNode >::CreateInstance( &_pcnNode );
  824. if ( SUCCEEDED( _hr ) )
  825. {
  826. _pcnNode->AddRef();
  827. _hr = _pcnNode->Open( m_pClusRefObject, _pvar->bstrVal );
  828. if ( SUCCEEDED( _hr ) )
  829. {
  830. _hr = _pcnNode->get_Handle( (ULONG_PTR *) &_hNode );
  831. } // if:
  832. } // if:
  833. } // else if:
  834. } // if: was the option parameter present?
  835. else if ( varNode.vt == VT_DISPATCH )
  836. {
  837. IDispatch * _pidNode = varNode.pdispVal;
  838. _hr = _pidNode->QueryInterface( IID_ISClusNode, (void **) &_piscNode );
  839. if ( SUCCEEDED( _hr ) )
  840. {
  841. _hr = _piscNode->get_Handle( (ULONG_PTR *) &_hNode );
  842. _piscNode->Release();
  843. } // if: did we get the ISClusNode interface?
  844. } // else if: we have a dispatch variant
  845. else if ( varNode.vt == VT_BSTR )
  846. {
  847. _hr = CComObject< CClusNode >::CreateInstance( &_pcnNode );
  848. if ( SUCCEEDED( _hr ) )
  849. {
  850. _pcnNode->AddRef();
  851. _hr = _pcnNode->Open( m_pClusRefObject, ( varNode.vt & VT_BYREF) ? (*varNode.pbstrVal) : varNode.bstrVal );
  852. if ( SUCCEEDED( _hr ) )
  853. {
  854. _hr = _pcnNode->get_Handle( (ULONG_PTR *) &_hNode );
  855. } // if:
  856. } // if:
  857. } // else if: we have a string variant
  858. else if ( varNode.vt == VT_EMPTY )
  859. {
  860. _hNode = NULL;
  861. } // else if: it is empty
  862. else if ( ( varNode.vt == VT_ERROR ) && ( varNode.scode == DISP_E_PARAMNOTFOUND ) )
  863. {
  864. _hNode = NULL;
  865. } // else if: the optional parameter was not specified
  866. else
  867. {
  868. _hr = ::VariantChangeTypeEx( &varNode, &varNode, LOCALE_SYSTEM_DEFAULT, 0, VT_I4 );
  869. if ( SUCCEEDED( _hr ) )
  870. {
  871. if ( varNode.lVal != 0 )
  872. {
  873. _hr = E_INVALIDARG;
  874. } // if: this is not zero then we cannot accept this parameter format. If varNode.lVal was zero then we could assume it was a NULL arg...
  875. } // if: coerce to a long
  876. } // else: the node variant could be invalid -- check for a zero, and if found treat it like a NULL...
  877. if ( SUCCEEDED( _hr ) )
  878. {
  879. BOOL bPending = FALSE;
  880. _hr = ::HrWrapMoveClusterGroup(
  881. _hCluster,
  882. m_hGroup->get_Handle(),
  883. _hNode,
  884. varTimeout.lVal,
  885. (long *) &bPending
  886. );
  887. if ( SUCCEEDED( _hr ) )
  888. {
  889. if ( bPending )
  890. {
  891. pvarPending->boolVal = VARIANT_TRUE;
  892. } // if: pending?
  893. } // if: Move group succeeded
  894. } // if: we have all handles
  895. } // if: get_Handle() -- cluster handle
  896. if ( _pcnNode != NULL )
  897. {
  898. _pcnNode->Release();
  899. } // if: did we create a node?
  900. } // if: wasn't the right type
  901. } //if: pvarPending != NULL
  902. return _hr;
  903. } //*** CClusResGroup::Move()
  904. /////////////////////////////////////////////////////////////////////////////
  905. //++
  906. //
  907. // CClusResGroup::Offline
  908. //
  909. // Description:
  910. // Take the group offline.
  911. //
  912. // Arguments:
  913. // varTimeout [IN] - How long in seconds to wait for the group to
  914. // go offline.
  915. // pvarPending [OUT] - Catches the pending state. True if we timed
  916. // out before the group came completely online.
  917. //
  918. // Return Value:
  919. // S_OK if successful, or other Win32 error as HRESULT.
  920. //
  921. //--
  922. /////////////////////////////////////////////////////////////////////////////
  923. STDMETHODIMP CClusResGroup::Offline(
  924. IN VARIANT varTimeout,
  925. OUT VARIANT * pvarPending
  926. )
  927. {
  928. //ASSERT( nTimeout >= 0 );
  929. //ASSERT( pvarPending != NULL );
  930. HRESULT _hr = E_POINTER;
  931. if ( pvarPending != NULL )
  932. {
  933. _hr = ::VariantChangeTypeEx( &varTimeout, &varTimeout, LOCALE_SYSTEM_DEFAULT, 0, VT_I4 );
  934. if ( SUCCEEDED( _hr ) )
  935. {
  936. HCLUSTER _hCluster;
  937. pvarPending->vt = VT_BOOL;
  938. pvarPending->boolVal = VARIANT_FALSE;
  939. _hr = m_pClusRefObject->get_Handle( (ULONG_PTR *) &_hCluster );
  940. if ( SUCCEEDED( _hr ) )
  941. {
  942. BOOL bPending = FALSE;
  943. _hr = ::HrWrapOfflineClusterGroup( _hCluster, m_hGroup->get_Handle(),
  944. varTimeout.lVal, (long *) &bPending );
  945. if ( SUCCEEDED( _hr ) )
  946. {
  947. if ( bPending )
  948. {
  949. pvarPending->boolVal = VARIANT_TRUE;
  950. } // if: pending?
  951. } // if: offline group succeeded
  952. } // if: get_Handle() -- cluster handle
  953. } // if: wasn't the right type
  954. } //if: pvarPending != NULL
  955. return _hr;
  956. } //*** CClusResGroup::Offline()
  957. /////////////////////////////////////////////////////////////////////////////
  958. //++
  959. //
  960. // CClusResGroup::get_CommonProperties
  961. //
  962. // Description:
  963. // Get this object's (Resource Group) common properties collection.
  964. //
  965. // Arguments:
  966. // ppProperties [OUT] - Catches the properties collection.
  967. //
  968. // Return Value:
  969. // S_OK if successful, or other HRESULT error.
  970. //
  971. //--
  972. /////////////////////////////////////////////////////////////////////////////
  973. STDMETHODIMP CClusResGroup::get_CommonProperties(
  974. OUT ISClusProperties ** ppProperties
  975. )
  976. {
  977. //ASSERT( ppProperties != NULL );
  978. HRESULT _hr = E_POINTER;
  979. if ( ppProperties != NULL )
  980. {
  981. if ( m_pCommonProperties )
  982. {
  983. _hr = m_pCommonProperties->QueryInterface( IID_ISClusProperties, (void **) ppProperties );
  984. }
  985. else
  986. {
  987. _hr = GetProperties( ppProperties, FALSE, FALSE );
  988. }
  989. }
  990. return _hr;
  991. } //*** CClusResGroup::get_CommonProperties()
  992. /////////////////////////////////////////////////////////////////////////////
  993. //++
  994. //
  995. // CClusResGroup::get_PrivateProperties
  996. //
  997. // Description:
  998. // Get this object's (Resource Group) private properties collection.
  999. //
  1000. // Arguments:
  1001. // ppProperties [OUT] - Catches the properties collection.
  1002. //
  1003. // Return Value:
  1004. // S_OK if successful, or other HRESULT error.
  1005. //
  1006. //--
  1007. /////////////////////////////////////////////////////////////////////////////
  1008. STDMETHODIMP CClusResGroup::get_PrivateProperties(
  1009. OUT ISClusProperties ** ppProperties
  1010. )
  1011. {
  1012. //ASSERT( ppProperties != NULL );
  1013. HRESULT _hr = E_POINTER;
  1014. if ( ppProperties != NULL )
  1015. {
  1016. if ( m_pPrivateProperties )
  1017. {
  1018. _hr = m_pPrivateProperties->QueryInterface( IID_ISClusProperties, (void **) ppProperties );
  1019. }
  1020. else
  1021. {
  1022. _hr = GetProperties( ppProperties, TRUE, FALSE );
  1023. }
  1024. }
  1025. return _hr;
  1026. } //*** CClusResGroup::get_PrivateProperties()
  1027. /////////////////////////////////////////////////////////////////////////////
  1028. //++
  1029. //
  1030. // CClusResGroup::get_CommonROProperties
  1031. //
  1032. // Description:
  1033. // Get this object's (Resource Group) common read only properties collection.
  1034. //
  1035. // Arguments:
  1036. // ppProperties [OUT] - Catches the properties collection.
  1037. //
  1038. // Return Value:
  1039. // S_OK if successful, or other HRESULT error.
  1040. //
  1041. //--
  1042. /////////////////////////////////////////////////////////////////////////////
  1043. STDMETHODIMP CClusResGroup::get_CommonROProperties(
  1044. OUT ISClusProperties ** ppProperties
  1045. )
  1046. {
  1047. //ASSERT( ppProperties != NULL );
  1048. HRESULT _hr = E_POINTER;
  1049. if ( ppProperties != NULL )
  1050. {
  1051. if ( m_pCommonROProperties )
  1052. {
  1053. _hr = m_pCommonROProperties->QueryInterface( IID_ISClusProperties, (void **) ppProperties );
  1054. }
  1055. else
  1056. {
  1057. _hr = GetProperties( ppProperties, FALSE, TRUE );
  1058. }
  1059. }
  1060. return _hr;
  1061. } //*** CClusResGroup::get_CommonROProperties()
  1062. /////////////////////////////////////////////////////////////////////////////
  1063. //++
  1064. //
  1065. // CClusResGroup::get_PrivateROProperties
  1066. //
  1067. // Description:
  1068. // Get this object's (Resource Group) private read only properties collection.
  1069. //
  1070. // Arguments:
  1071. // ppProperties [OUT] - Catches the properties collection.
  1072. //
  1073. // Return Value:
  1074. // S_OK if successful, or other HRESULT error.
  1075. //
  1076. //--
  1077. /////////////////////////////////////////////////////////////////////////////
  1078. STDMETHODIMP CClusResGroup::get_PrivateROProperties(
  1079. OUT ISClusProperties ** ppProperties
  1080. )
  1081. {
  1082. //ASSERT( ppProperties != NULL );
  1083. HRESULT _hr = E_POINTER;
  1084. if ( ppProperties != NULL )
  1085. {
  1086. if ( m_pPrivateROProperties )
  1087. {
  1088. _hr = m_pPrivateROProperties->QueryInterface( IID_ISClusProperties, (void **) ppProperties );
  1089. }
  1090. else
  1091. {
  1092. _hr = GetProperties( ppProperties, TRUE, TRUE );
  1093. }
  1094. }
  1095. return _hr;
  1096. } //*** CClusResGroup::get_PrivateROProperties()
  1097. /////////////////////////////////////////////////////////////////////////////
  1098. //++
  1099. //
  1100. // CClusResGroup::get_Cluster
  1101. //
  1102. // Description:
  1103. // Returns the cluster object for the cluster where this group lives.
  1104. //
  1105. // Arguments:
  1106. // ppCluster [OUT] - Catches the cluster object.
  1107. //
  1108. // Return Value:
  1109. // S_OK if successful, E_POINTER, or other HRESULT error.
  1110. //
  1111. //--
  1112. /////////////////////////////////////////////////////////////////////////////
  1113. STDMETHODIMP CClusResGroup::get_Cluster( OUT ISCluster ** ppCluster )
  1114. {
  1115. return ::HrGetCluster( ppCluster, m_pClusRefObject );
  1116. } //*** CClusResGroup::get_Cluster()
  1117. /////////////////////////////////////////////////////////////////////////////
  1118. //++
  1119. //
  1120. // CClusResGroup::HrLoadProperties
  1121. //
  1122. // Description:
  1123. // This virtual function does the actual load of the property list from
  1124. // the cluster.
  1125. //
  1126. // Arguments:
  1127. // rcplPropList [IN OUT] - The property list to load.
  1128. // bReadOnly [IN] - Load the read only properties?
  1129. // bPrivate [IN] - Load the common or the private properties?
  1130. //
  1131. // Return Value:
  1132. // S_OK if successful, or other HRESULT error.
  1133. //
  1134. //--
  1135. /////////////////////////////////////////////////////////////////////////////
  1136. HRESULT CClusResGroup::HrLoadProperties(
  1137. IN OUT CClusPropList & rcplPropList,
  1138. IN BOOL bReadOnly,
  1139. IN BOOL bPrivate
  1140. )
  1141. {
  1142. HRESULT _hr = S_FALSE;
  1143. DWORD _dwControlCode = 0;
  1144. DWORD _sc = ERROR_SUCCESS;
  1145. if ( bReadOnly )
  1146. {
  1147. _dwControlCode = bPrivate
  1148. ? CLUSCTL_GROUP_GET_RO_PRIVATE_PROPERTIES
  1149. : CLUSCTL_GROUP_GET_RO_COMMON_PROPERTIES;
  1150. }
  1151. else
  1152. {
  1153. _dwControlCode = bPrivate
  1154. ? CLUSCTL_GROUP_GET_PRIVATE_PROPERTIES
  1155. : CLUSCTL_GROUP_GET_COMMON_PROPERTIES;
  1156. }
  1157. _sc = rcplPropList.ScGetGroupProperties( m_hGroup->get_Handle(), _dwControlCode );
  1158. _hr = HRESULT_FROM_WIN32( _sc );
  1159. return _hr;
  1160. } //*** CClusResGroup::HrLoadProperties()
  1161. /////////////////////////////////////////////////////////////////////////////
  1162. //++
  1163. //
  1164. // CClusResGroup::ScWriteProperties
  1165. //
  1166. // Description:
  1167. // This virtual function does the actual saving of the property list to
  1168. // the cluster.
  1169. //
  1170. // Arguments:
  1171. // rcplPropList [IN] - The property list to save.
  1172. // bPrivate [IN] - Save the common or the private properties?
  1173. //
  1174. // Return Value:
  1175. // S_OK if successful, or other Win32 error as HRESULT error.
  1176. //
  1177. //--
  1178. /////////////////////////////////////////////////////////////////////////////
  1179. DWORD CClusResGroup::ScWriteProperties(
  1180. const CClusPropList & rcplPropList,
  1181. BOOL bPrivate
  1182. )
  1183. {
  1184. DWORD dwControlCode = bPrivate ? CLUSCTL_GROUP_SET_PRIVATE_PROPERTIES : CLUSCTL_GROUP_SET_COMMON_PROPERTIES;
  1185. DWORD nBytesReturned = 0;
  1186. DWORD _sc = ERROR_SUCCESS;
  1187. _sc = ClusterGroupControl(
  1188. m_hGroup->get_Handle(),
  1189. NULL,
  1190. dwControlCode,
  1191. rcplPropList,
  1192. rcplPropList.CbBufferSize(),
  1193. 0,
  1194. 0,
  1195. &nBytesReturned
  1196. );
  1197. return _sc;
  1198. } //*** CClusResGroup::ScWriteProperties()
  1199. //*************************************************************************//
  1200. /////////////////////////////////////////////////////////////////////////////
  1201. // CClusResGroups class
  1202. /////////////////////////////////////////////////////////////////////////////
  1203. /////////////////////////////////////////////////////////////////////////////
  1204. //++
  1205. //
  1206. // CClusResGroups::CClusResGroups
  1207. //
  1208. // Description:
  1209. // Constructor.
  1210. //
  1211. // Arguments:
  1212. // None.
  1213. //
  1214. // Return Value:
  1215. // None.
  1216. //
  1217. //--
  1218. /////////////////////////////////////////////////////////////////////////////
  1219. CClusResGroups::CClusResGroups( void )
  1220. {
  1221. m_pClusRefObject = NULL;
  1222. m_piids = (const IID *) iidCClusResGroups;
  1223. m_piidsSize = ARRAYSIZE( iidCClusResGroups );
  1224. } //*** CClusResGroups::CClusResGroups()
  1225. /////////////////////////////////////////////////////////////////////////////
  1226. //++
  1227. //
  1228. // CClusResGroups::~CClusResGroups
  1229. //
  1230. // Description:
  1231. // Destructor.
  1232. //
  1233. // Arguments:
  1234. // None.
  1235. //
  1236. // Return Value:
  1237. // None.
  1238. //
  1239. //--
  1240. /////////////////////////////////////////////////////////////////////////////
  1241. CClusResGroups::~CClusResGroups( void )
  1242. {
  1243. Clear();
  1244. if ( m_pClusRefObject != NULL )
  1245. {
  1246. m_pClusRefObject->Release();
  1247. m_pClusRefObject = NULL;
  1248. }
  1249. } //*** CClusResGroups::~CClusResGroups()
  1250. /////////////////////////////////////////////////////////////////////////////
  1251. //++
  1252. //
  1253. // CClusResGroups::Create
  1254. //
  1255. // Description:
  1256. // Finish the heavy weight construction.
  1257. //
  1258. // Arguments:
  1259. // pClusRefObject [IN] - Wraps the cluster handle.
  1260. // pwszNodeName [IN] - Optional node name. If this argument
  1261. // is supplied then this is a collection of
  1262. // groups that are owned by that node.
  1263. //
  1264. // Return Value:
  1265. // S_OK if successful, or E_POINTER if not.
  1266. //
  1267. //--
  1268. /////////////////////////////////////////////////////////////////////////////
  1269. HRESULT CClusResGroups::Create(
  1270. IN ISClusRefObject * pClusRefObject,
  1271. IN LPCWSTR pwszNodeName
  1272. )
  1273. {
  1274. ASSERT( pClusRefObject != NULL );
  1275. //ASSERT( pwszNodeName != NULL );
  1276. HRESULT _hr = E_POINTER;
  1277. if ( ( pClusRefObject != NULL ) /*&& ( pwszNodeName != NULL )*/ )
  1278. {
  1279. m_pClusRefObject= pClusRefObject;
  1280. m_pClusRefObject->AddRef();
  1281. m_bstrNodeName = pwszNodeName;
  1282. _hr = S_OK;
  1283. }
  1284. return _hr;
  1285. } //*** CClusResGroups::Create()
  1286. /////////////////////////////////////////////////////////////////////////////
  1287. //++
  1288. //
  1289. // CClusResGroups::FindItem
  1290. //
  1291. // Description:
  1292. // Find the passed in group in the collection.
  1293. //
  1294. // Arguments:
  1295. // pszGroupName [IN] - The name of the group to find.
  1296. // pnIndex [OUT] - Catches the index of the group.
  1297. //
  1298. // Return Value:
  1299. // S_OK if successful, E_POINTER, or E_INVALIDARG if the group was
  1300. // not found.
  1301. //
  1302. //--
  1303. /////////////////////////////////////////////////////////////////////////////
  1304. HRESULT CClusResGroups::FindItem(
  1305. IN LPWSTR pszGroupName,
  1306. OUT ULONG * pnIndex
  1307. )
  1308. {
  1309. //ASSERT( pszGroupName != NULL );
  1310. //ASSERT( pnIndex != NULL );
  1311. HRESULT _hr = E_POINTER;
  1312. if ( ( pszGroupName != NULL ) && ( pnIndex != NULL ) )
  1313. {
  1314. CComObject<CClusResGroup> * pGroup = NULL;
  1315. int nMax = m_ResourceGroups.size();
  1316. _hr = E_INVALIDARG;
  1317. for( int i = 0; i < nMax; i++ )
  1318. {
  1319. pGroup = m_ResourceGroups[ i ];
  1320. if ( pGroup && ( lstrcmpi( pszGroupName, pGroup->Name() ) == 0 ) )
  1321. {
  1322. *pnIndex = i;
  1323. _hr = S_OK;
  1324. break;
  1325. }
  1326. }
  1327. }
  1328. return _hr;
  1329. } //*** CClusResGroups::FindItem()
  1330. /////////////////////////////////////////////////////////////////////////////
  1331. //++
  1332. //
  1333. // CClusResGroups::FindItem
  1334. //
  1335. // Description:
  1336. // Find the passed in group in the collection.
  1337. //
  1338. // Arguments:
  1339. // pResourceGroup [IN] - The group to find.
  1340. // pnIndex [OUT] - Catches the index of the group.
  1341. //
  1342. // Return Value:
  1343. // S_OK if successful, E_POINTER, or E_INVALIDARG is the group was
  1344. // not found.
  1345. //--
  1346. /////////////////////////////////////////////////////////////////////////////
  1347. HRESULT CClusResGroups::FindItem(
  1348. IN ISClusResGroup * pResourceGroup,
  1349. OUT ULONG * pnIndex
  1350. )
  1351. {
  1352. //ASSERT( pResourceGroup != NULL );
  1353. //ASSERT( pnIndex != NULL );
  1354. HRESULT _hr = E_POINTER;
  1355. if ( ( pResourceGroup != NULL ) && ( pnIndex != NULL ) )
  1356. {
  1357. CComBSTR _bstrName;
  1358. _hr = pResourceGroup->get_Name( &_bstrName );
  1359. if ( SUCCEEDED( _hr ) )
  1360. {
  1361. _hr = FindItem( _bstrName, pnIndex );
  1362. }
  1363. }
  1364. return _hr;
  1365. } //*** CClusResGroups::FindItem()
  1366. /////////////////////////////////////////////////////////////////////////////
  1367. //++
  1368. //
  1369. // CClusResGroups::GetIndex
  1370. //
  1371. // Description:
  1372. // Get the index from the passed in variant.
  1373. //
  1374. // Arguments:
  1375. // varIndex [IN] - Hold the index. This is a one based number,
  1376. // or the name of the group as a string.
  1377. // pnIndex [OUT] - Catches the zero based index in the collection.
  1378. //
  1379. // Return Value:
  1380. // S_OK if successful, E_POINTER, or E_INVALIDARG if the index is out
  1381. // of range.
  1382. //
  1383. //--
  1384. /////////////////////////////////////////////////////////////////////////////
  1385. HRESULT CClusResGroups::GetIndex(
  1386. IN VARIANT varIndex,
  1387. OUT ULONG * pnIndex
  1388. )
  1389. {
  1390. //ASSERT( pnIndex != NULL );
  1391. HRESULT _hr = E_POINTER;
  1392. if ( pnIndex != NULL )
  1393. {
  1394. CComVariant v;
  1395. ULONG nIndex = 0;
  1396. *pnIndex = 0;
  1397. v.Copy( &varIndex );
  1398. // Check to see if the index is a number.
  1399. _hr = v.ChangeType( VT_I4 );
  1400. if ( SUCCEEDED( _hr ) )
  1401. {
  1402. nIndex = v.lVal;
  1403. nIndex--; // Adjust index to be 0 relative instead of 1 relative
  1404. }
  1405. else
  1406. {
  1407. // Check to see if the index is a string.
  1408. _hr = v.ChangeType( VT_BSTR );
  1409. if ( SUCCEEDED( _hr ) )
  1410. {
  1411. // Search for the string.
  1412. _hr = FindItem( v.bstrVal, &nIndex );
  1413. }
  1414. }
  1415. // We found an index, now check the range.
  1416. if ( SUCCEEDED( _hr ) )
  1417. {
  1418. if ( nIndex < m_ResourceGroups.size() )
  1419. {
  1420. *pnIndex = nIndex;
  1421. }
  1422. else
  1423. {
  1424. _hr = E_INVALIDARG;
  1425. }
  1426. }
  1427. }
  1428. return _hr;
  1429. } //*** CClusResGroups::GetIndex()
  1430. /////////////////////////////////////////////////////////////////////////////
  1431. //++
  1432. //
  1433. // CClusResGroups::RemoveAt
  1434. //
  1435. // Description:
  1436. // Remove the object (Group) at the passed in index/position from the
  1437. // collection.
  1438. //
  1439. // Arguments:
  1440. // nPos [IN] - Index of the object to remove.
  1441. //
  1442. // Return Value:
  1443. // S_OK if successful, or E_INVALIDARG is the index is out of range.
  1444. //
  1445. //--
  1446. /////////////////////////////////////////////////////////////////////////////
  1447. HRESULT CClusResGroups::RemoveAt( IN size_t pos )
  1448. {
  1449. CComObject<CClusResGroup> * pResourceGroup = NULL;
  1450. ResourceGroupList::iterator first = m_ResourceGroups.begin();
  1451. ResourceGroupList::iterator last = m_ResourceGroups.end();
  1452. HRESULT _hr = E_INVALIDARG;
  1453. for ( size_t t = 0; ( t < pos ) && ( first != last ); t++, first++ );
  1454. if ( first != last )
  1455. {
  1456. pResourceGroup = *first;
  1457. if ( pResourceGroup )
  1458. {
  1459. pResourceGroup->Release();
  1460. }
  1461. m_ResourceGroups.erase( first );
  1462. _hr = S_OK;
  1463. }
  1464. return _hr;
  1465. } //*** CClusResGroups::RemoveAt()
  1466. /////////////////////////////////////////////////////////////////////////////
  1467. //++
  1468. //
  1469. // CClusResGroups::get_Count
  1470. //
  1471. // Description:
  1472. // Returns the count of elements (Groups) in the collection.
  1473. //
  1474. // Arguments:
  1475. // plCount [OUT] - Catches the count.
  1476. //
  1477. // Return Value:
  1478. // S_OK if successful, or E_POINTER if not.
  1479. //
  1480. //--
  1481. /////////////////////////////////////////////////////////////////////////////
  1482. STDMETHODIMP CClusResGroups::get_Count( OUT long * plCount )
  1483. {
  1484. //ASSERT( plCount != NULL );
  1485. HRESULT _hr = E_POINTER;
  1486. if ( plCount != NULL )
  1487. {
  1488. *plCount = m_ResourceGroups.size();
  1489. _hr = S_OK;
  1490. }
  1491. return _hr;
  1492. } //*** CClusResGroups::get_Count()
  1493. /////////////////////////////////////////////////////////////////////////////
  1494. //++
  1495. //
  1496. // CClusResGroups::Clear
  1497. //
  1498. // Description:
  1499. // Clean out the vector of ClusResGroup objects.
  1500. //
  1501. // Arguments:
  1502. // None.
  1503. //
  1504. // Return Value:
  1505. // None.
  1506. //
  1507. //--
  1508. /////////////////////////////////////////////////////////////////////////////
  1509. void CClusResGroups::Clear( void )
  1510. {
  1511. ::ReleaseAndEmptyCollection< ResourceGroupList, CComObject< CClusResGroup > >( m_ResourceGroups );
  1512. } //*** CClusResGroups::Clear()
  1513. /////////////////////////////////////////////////////////////////////////////
  1514. //++
  1515. //
  1516. // CClusResGroups::get_Item
  1517. //
  1518. // Description:
  1519. // Returns the object (Group) at the passed in index.
  1520. //
  1521. // Arguments:
  1522. // varIndex [IN] - Hold the index. This is a one based number, or
  1523. // a string that is the name of the group to get.
  1524. // ppProperty [OUT] - Catches the property.
  1525. //
  1526. // Return Value:
  1527. // S_OK if successful, E_POINTER, or E_INVALIDARG if the index is out
  1528. // of range, or other HRESULT error.
  1529. //
  1530. //--
  1531. /////////////////////////////////////////////////////////////////////////////
  1532. STDMETHODIMP CClusResGroups::get_Item(
  1533. IN VARIANT varIndex,
  1534. OUT ISClusResGroup ** ppResourceGroup
  1535. )
  1536. {
  1537. //ASSERT( ppResourceGroup != NULL );
  1538. HRESULT _hr = E_POINTER;
  1539. if ( ppResourceGroup != NULL )
  1540. {
  1541. CComObject<CClusResGroup> * pGroup = NULL;
  1542. // Zero the out param
  1543. *ppResourceGroup = NULL;
  1544. ULONG nIndex = 0;
  1545. _hr = GetIndex( varIndex, &nIndex );
  1546. if ( SUCCEEDED( _hr ) )
  1547. {
  1548. pGroup = m_ResourceGroups[ nIndex ];
  1549. _hr = pGroup->QueryInterface( IID_ISClusResGroup, (void **) ppResourceGroup );
  1550. }
  1551. }
  1552. /*
  1553. if ( _hr == S_OK )
  1554. {
  1555. OutputDebugStringW( L"CClusResGroups::get_Item() succeeded.\n" );
  1556. } // if: success!
  1557. else
  1558. {
  1559. WCHAR sz[ 256 ];
  1560. _snwprintf( sz, RTL_NUMBER_OF( sz ), L"CClusResGroups::get_Item() failed. (hr = %#08x)\n", _hr );
  1561. OutputDebugStringW( sz );
  1562. } // else: failure...
  1563. */
  1564. return _hr;
  1565. } //*** CClusResGroups::get_Item()
  1566. /////////////////////////////////////////////////////////////////////////////
  1567. //++
  1568. //
  1569. // CClusResGroups::get__NewEnum
  1570. //
  1571. // Description:
  1572. // Create and return a new enumeration for this collection.
  1573. //
  1574. // Arguments:
  1575. // ppunk [OUT] - Catches the new enumeration.
  1576. //
  1577. // Return Value:
  1578. // S_OK if successful, E_POINTER, or other HRESULT error.
  1579. //
  1580. //--
  1581. /////////////////////////////////////////////////////////////////////////////
  1582. STDMETHODIMP CClusResGroups::get__NewEnum(
  1583. IUnknown ** ppunk
  1584. )
  1585. {
  1586. return ::HrNewIDispatchEnum< ResourceGroupList, CComObject< CClusResGroup > >( ppunk, m_ResourceGroups );
  1587. } //*** CClusResGroups::get__NewEnum()
  1588. /////////////////////////////////////////////////////////////////////////////
  1589. //++
  1590. //
  1591. // CClusResGroups::CreateItem
  1592. //
  1593. // Description:
  1594. // Create a new object (Group) and add it to the collection.
  1595. //
  1596. // Arguments:
  1597. // bstrResourceGroupName [IN] - The name of the new group.
  1598. // ppResourceGroup [OUT] - Catches the new object.
  1599. //
  1600. // Return Value:
  1601. // S_OK if successful, E_POINTER, or Win32 error as HRESULT.
  1602. //
  1603. //--
  1604. /////////////////////////////////////////////////////////////////////////////
  1605. STDMETHODIMP CClusResGroups::CreateItem(
  1606. IN BSTR bstrResourceGroupName,
  1607. OUT ISClusResGroup ** ppResourceGroup
  1608. )
  1609. {
  1610. //ASSERT( bstrResourceGroupName != NULL );
  1611. //ASSERT( ppResourceGroup != NULL );
  1612. HRESULT _hr = E_POINTER;
  1613. if ( ( bstrResourceGroupName != NULL ) && ( ppResourceGroup != NULL ) )
  1614. {
  1615. ULONG nIndex;
  1616. *ppResourceGroup = NULL;
  1617. _hr = FindItem( bstrResourceGroupName, &nIndex );
  1618. if ( FAILED( _hr ) )
  1619. {
  1620. CComObject< CClusResGroup > * pResourceGroup = NULL;
  1621. _hr = CComObject< CClusResGroup >::CreateInstance( &pResourceGroup );
  1622. if ( SUCCEEDED( _hr ) )
  1623. {
  1624. CSmartPtr< ISClusRefObject > ptrRefObject( m_pClusRefObject );
  1625. CSmartPtr< CComObject< CClusResGroup > > ptrGroup( pResourceGroup );
  1626. _hr = ptrGroup->Create( ptrRefObject, bstrResourceGroupName );
  1627. if ( SUCCEEDED( _hr ) )
  1628. {
  1629. _hr = ptrGroup->QueryInterface( IID_ISClusResGroup, (void **) ppResourceGroup );
  1630. if ( SUCCEEDED( _hr ) )
  1631. {
  1632. ptrGroup->AddRef();
  1633. m_ResourceGroups.insert( m_ResourceGroups.end(), ptrGroup );
  1634. }
  1635. }
  1636. }
  1637. } // if: group already exists
  1638. else
  1639. {
  1640. CComObject< CClusResGroup > * pResourceGroup = NULL;
  1641. pResourceGroup = m_ResourceGroups[ nIndex ];
  1642. _hr = pResourceGroup->QueryInterface( IID_ISClusResGroup, (void **) ppResourceGroup );
  1643. }
  1644. }
  1645. /*
  1646. if ( _hr == S_OK )
  1647. {
  1648. OutputDebugStringW( L"ClusResGroups::CreateItem() succeeded.\n" );
  1649. } // if: success!
  1650. else
  1651. {
  1652. WCHAR sz[ 256 ];
  1653. _snwprintf( sz, RTL_NUMBER_OF( sz ), L"Error creating group. (hr = %#08x)\n", _hr );
  1654. OutputDebugStringW( sz );
  1655. } // else: failure...
  1656. */
  1657. return _hr;
  1658. } //*** CClusResGroups::CreateItem()
  1659. /////////////////////////////////////////////////////////////////////////////
  1660. //++
  1661. //
  1662. // CClusResGroups::DeleteItem
  1663. //
  1664. // Description:
  1665. // Deletes the object (group) at the passed in index.
  1666. //
  1667. // Arguments:
  1668. // varIndex [IN] - The index of the object to delete.
  1669. //
  1670. // Return Value:
  1671. // S_OK if successful, E_INVALIDARG, or Win32 error as HRESULT.
  1672. //
  1673. //--
  1674. /////////////////////////////////////////////////////////////////////////////
  1675. STDMETHODIMP CClusResGroups::DeleteItem( IN VARIANT varIndex )
  1676. {
  1677. HRESULT _hr = S_OK;
  1678. ULONG nIndex = 0;
  1679. _hr = GetIndex( varIndex, &nIndex );
  1680. if ( SUCCEEDED( _hr ) )
  1681. {
  1682. ISClusResGroup * pResourceGroup = (ISClusResGroup *) m_ResourceGroups[ nIndex ];
  1683. // Delete the resource group.
  1684. _hr = pResourceGroup->Delete();
  1685. if ( SUCCEEDED( _hr ) )
  1686. {
  1687. RemoveAt( nIndex );
  1688. }
  1689. }
  1690. /*
  1691. if ( _hr == S_OK )
  1692. {
  1693. OutputDebugStringW( L"CClusResGroups::DeleteItem() succeeded.\n" );
  1694. } // if: success!
  1695. else
  1696. {
  1697. WCHAR sz[ 128 ];
  1698. _snwprintf( sz, RTL_NUMBER_OF( sz ), L"CClusResGroups::DeleteItem() failed. (hr = %#08x)\n", _hr );
  1699. OutputDebugStringW( sz );
  1700. } // else: failure...
  1701. */
  1702. return _hr;
  1703. } //*** CClusResGroups::DeleteItem()
  1704. /////////////////////////////////////////////////////////////////////////////
  1705. //++
  1706. //
  1707. // CClusResGroups::Refresh
  1708. //
  1709. // Description:
  1710. // Load the collection from the cluster.
  1711. //
  1712. // Arguments:
  1713. // None.
  1714. //
  1715. // Return Value:
  1716. // S_OK is successful, or Win32 error as HRESULT if not.
  1717. //
  1718. //--
  1719. /////////////////////////////////////////////////////////////////////////////
  1720. STDMETHODIMP CClusResGroups::Refresh( void )
  1721. {
  1722. Clear();
  1723. if ( m_pClusRefObject == NULL )
  1724. {
  1725. return E_POINTER;
  1726. } // if: we have a cluster handle wrapper
  1727. if ( m_bstrNodeName == (BSTR) NULL )
  1728. {
  1729. return RefreshCluster();
  1730. } // if: this collection is for a cluster
  1731. else
  1732. {
  1733. return RefreshNode();
  1734. } // else: this collection is for a node
  1735. } //*** CClusResGroups::Refresh()
  1736. /////////////////////////////////////////////////////////////////////////////
  1737. //++
  1738. //
  1739. // CClusResGroups::RefreshCluster
  1740. //
  1741. // Description:
  1742. // Load all of the groups in the cluster into this collection.
  1743. //
  1744. // Arguments:
  1745. // None.
  1746. //
  1747. // Return Value:
  1748. // S_OK is successful, or Win32 error as HRESULT if not.
  1749. //
  1750. //--
  1751. /////////////////////////////////////////////////////////////////////////////
  1752. HRESULT CClusResGroups::RefreshCluster( void )
  1753. {
  1754. HCLUSTER _hCluster = NULL;
  1755. HRESULT _hr;
  1756. ASSERT( m_pClusRefObject != NULL );
  1757. _hr = m_pClusRefObject->get_Handle( (ULONG_PTR *) &_hCluster );
  1758. if ( SUCCEEDED( _hr ) )
  1759. {
  1760. HCLUSENUM hEnum = NULL;
  1761. DWORD _sc = ERROR_SUCCESS;
  1762. hEnum = ::ClusterOpenEnum( _hCluster, CLUSTER_ENUM_GROUP );
  1763. if ( hEnum != NULL )
  1764. {
  1765. DWORD dwType;
  1766. LPWSTR pwszName = NULL;
  1767. CComObject< CClusResGroup > * pResourceGroup = NULL;
  1768. int nIndex;
  1769. for( nIndex = 0, _hr = S_OK; SUCCEEDED( _hr ); nIndex++ )
  1770. {
  1771. _sc = ::WrapClusterEnum( hEnum, nIndex, &dwType, &pwszName );
  1772. if ( _sc == ERROR_NO_MORE_ITEMS)
  1773. {
  1774. _hr = S_OK;
  1775. break;
  1776. } // if: Enumerator is empty. Time to leave...
  1777. else if ( _sc == ERROR_SUCCESS )
  1778. {
  1779. _hr = CComObject< CClusResGroup >::CreateInstance( &pResourceGroup );
  1780. if ( SUCCEEDED( _hr ) )
  1781. {
  1782. CSmartPtr< ISClusRefObject > ptrRefObject( m_pClusRefObject );
  1783. CSmartPtr< CComObject< CClusResGroup > > ptrGroup( pResourceGroup );
  1784. BSTR bstr = NULL;
  1785. bstr = SysAllocString( pwszName );
  1786. if ( bstr == NULL )
  1787. {
  1788. _hr = E_OUTOFMEMORY;
  1789. } // if: failed to allocate a bstr
  1790. else
  1791. {
  1792. _hr = ptrGroup->Open( ptrRefObject, bstr );
  1793. if ( SUCCEEDED( _hr ) )
  1794. {
  1795. ptrGroup->AddRef();
  1796. m_ResourceGroups.insert( m_ResourceGroups.end(), ptrGroup );
  1797. } // if: successfully opened the group
  1798. else if ( HRESULT_CODE( _hr ) == ERROR_GROUP_NOT_FOUND )
  1799. {
  1800. //
  1801. // It is possible for the group to have been deleted from the cluster
  1802. // in the time between creating the enum and opening the group. When
  1803. // that happens we need to simply skip that group and continue
  1804. // enumerating.
  1805. //
  1806. _hr = S_FALSE; // success code to keep us in the loop
  1807. } // else if: the cluster group was not found
  1808. SysFreeString( bstr );
  1809. } // else: successfully allocated a bstr
  1810. } // if: successfully created an instance of a group object
  1811. ::LocalFree( pwszName );
  1812. pwszName = NULL;
  1813. } // else if: successfully got a group from the enumerator
  1814. else
  1815. {
  1816. _hr = HRESULT_FROM_WIN32( _sc );
  1817. } // else: failed to get a group from the enumerator
  1818. } // for: each group in the enumerator
  1819. ::ClusterCloseEnum( hEnum ) ;
  1820. } // if: successfully created the groups enumerator
  1821. else
  1822. {
  1823. _sc = GetLastError();
  1824. _hr = HRESULT_FROM_WIN32( _sc );
  1825. } // else: failed to create the groups enumerator
  1826. } // if: successfully got the cluster handle
  1827. return _hr;
  1828. } //*** CClusResGroups::RefreshCluster()
  1829. /////////////////////////////////////////////////////////////////////////////
  1830. //++
  1831. //
  1832. // CClusResGroups::RefreshNode
  1833. //
  1834. // Description:
  1835. // Load all of the groups owned by the node at m_bstrNodeName.
  1836. //
  1837. // Arguments:
  1838. // None.
  1839. //
  1840. // Return Value:
  1841. // S_OK is successful, or Win32 error as HRESULT if not.
  1842. //
  1843. //--
  1844. /////////////////////////////////////////////////////////////////////////////
  1845. HRESULT CClusResGroups::RefreshNode( void )
  1846. {
  1847. HCLUSTER _hCluster = NULL;
  1848. HRESULT _hr;
  1849. ASSERT( m_pClusRefObject != NULL );
  1850. _hr = m_pClusRefObject->get_Handle( (ULONG_PTR *) &_hCluster );
  1851. if ( SUCCEEDED( _hr ) )
  1852. {
  1853. HCLUSENUM hEnum = NULL;
  1854. DWORD _sc = ERROR_SUCCESS;
  1855. hEnum = ::ClusterOpenEnum( _hCluster, CLUSTER_ENUM_GROUP );
  1856. if ( hEnum != NULL )
  1857. {
  1858. DWORD dwType;
  1859. LPWSTR pwszName = NULL;
  1860. LPWSTR pwszNodeName = NULL;
  1861. CComObject< CClusResGroup > * pResourceGroup = NULL;
  1862. CLUSTER_GROUP_STATE cgs = ClusterGroupStateUnknown;
  1863. int _nIndex;
  1864. for( _nIndex = 0, _hr = S_OK; SUCCEEDED( _hr ); _nIndex++ )
  1865. {
  1866. _sc = ::WrapClusterEnum( hEnum, _nIndex, &dwType, &pwszName );
  1867. if ( _sc == ERROR_NO_MORE_ITEMS )
  1868. {
  1869. _hr = S_OK;
  1870. break;
  1871. } // if: enum is empty. Time to leave...
  1872. else if ( _sc == ERROR_SUCCESS )
  1873. {
  1874. _hr = CComObject< CClusResGroup >::CreateInstance( &pResourceGroup );
  1875. if ( SUCCEEDED( _hr ) )
  1876. {
  1877. CSmartPtr< ISClusRefObject > ptrRefObject( m_pClusRefObject );
  1878. CSmartPtr< CComObject< CClusResGroup > > ptrGroup( pResourceGroup );
  1879. BSTR bstr = NULL;
  1880. bstr = SysAllocString( pwszName );
  1881. if ( bstr == NULL )
  1882. {
  1883. _hr = E_OUTOFMEMORY;
  1884. } // if: could not allocate a bstr
  1885. else
  1886. {
  1887. _hr = ptrGroup->Open( ptrRefObject, bstr );
  1888. if ( SUCCEEDED( _hr ) )
  1889. {
  1890. cgs = WrapGetClusterGroupState( ptrGroup->Hgroup(), &pwszNodeName );
  1891. if ( cgs != ClusterGroupStateUnknown )
  1892. {
  1893. if ( lstrcmpi( m_bstrNodeName, pwszNodeName ) == 0 )
  1894. {
  1895. ptrGroup->AddRef();
  1896. m_ResourceGroups.insert( m_ResourceGroups.end(), ptrGroup );
  1897. } // if: the group is owned by this node
  1898. ::LocalFree( pwszNodeName );
  1899. pwszNodeName = NULL;
  1900. } // if: the group state is not unknown
  1901. } // if: the group was opened
  1902. else if ( HRESULT_CODE( _hr ) == ERROR_GROUP_NOT_FOUND )
  1903. {
  1904. //
  1905. // It is possible for the group to have been deleted from the cluster
  1906. // in the time between creating the enum and opening the group. When
  1907. // that happens we need to simply skip that group and continue
  1908. // enumerating.
  1909. //
  1910. _hr = S_FALSE; // success code to keep us in the loop
  1911. } // else if: the cluster group was not found
  1912. SysFreeString( bstr );
  1913. } // else: could allocated a bstr
  1914. } // if: sucessfully created a group object instance
  1915. ::LocalFree( pwszName );
  1916. pwszName = NULL;
  1917. } // else if: successfully got a group from the enumerator
  1918. else
  1919. {
  1920. _hr = HRESULT_FROM_WIN32( _sc );
  1921. } // else: failed to get a group from the enumerator
  1922. } // for: each group in the enumerator
  1923. ::ClusterCloseEnum( hEnum );
  1924. } // if: successfully created a group enumerator
  1925. else
  1926. {
  1927. _sc = GetLastError();
  1928. _hr = HRESULT_FROM_WIN32( _sc );
  1929. } // else: failed to create a group enumerator
  1930. } // if: got the cluster handle from the ref counted container
  1931. /*
  1932. if ( _hr == S_OK )
  1933. {
  1934. OutputDebugStringW( L"CClusResGroups::RefreshNode() succeeded.\n" );
  1935. } // if: success!
  1936. else
  1937. {
  1938. WCHAR sz[ 128 ];
  1939. _snwprintf( sz, RTL_NUMBER_OF( sz ), L"CClusResGroups::RefreshNode() failed. (hr = %#08x)\n", _hr );
  1940. OutputDebugStringW( sz );
  1941. } // else: failure...
  1942. */
  1943. return _hr;
  1944. } //*** CClusResGroups::RefreshNode()