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.

2375 lines
67 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c)1997-2001 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // ClusWrap.cpp
  7. //
  8. // Description:
  9. // Wrapper functions for Cluster APIs.
  10. //
  11. // Author:
  12. // Galen Barbee (galenb) 15-Aug-1998
  13. //
  14. // Notes:
  15. //
  16. /////////////////////////////////////////////////////////////////////////////
  17. #include <windows.h>
  18. #include <tchar.h>
  19. #include <stdio.h>
  20. #include <clusapi.h>
  21. #include "cluswrap.h"
  22. /////////////////////////////////////////////////////////////////////////////
  23. // Type Definitions
  24. /////////////////////////////////////////////////////////////////////////////
  25. /////////////////////////////////////////////////////////////////////////////
  26. //++
  27. //
  28. // WrapGetClusterInformation
  29. //
  30. // Description:
  31. // Wraps the GetClusterInformation function.
  32. //
  33. // Arguments:
  34. //
  35. //
  36. // Return Value:
  37. //
  38. //
  39. //--
  40. /////////////////////////////////////////////////////////////////////////////
  41. DWORD WINAPI WrapGetClusterInformation(
  42. IN HCLUSTER hCluster,
  43. OUT LPWSTR * ppszClusterName,
  44. OUT OPTIONAL LPCLUSTERVERSIONINFO pClusterInfo
  45. )
  46. {
  47. DWORD dwStatus;
  48. LPWSTR pwszName = NULL;
  49. DWORD cchName = 128;
  50. DWORD cchTempName = cchName;
  51. // Zero the out parameter.
  52. if ( ppszClusterName != NULL )
  53. {
  54. *ppszClusterName = NULL;
  55. }
  56. pwszName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchName * sizeof( *pwszName ) );
  57. if ( pwszName != NULL )
  58. {
  59. dwStatus = GetClusterInformation( hCluster, pwszName, &cchTempName, pClusterInfo );
  60. if ( dwStatus == ERROR_MORE_DATA )
  61. {
  62. LocalFree( pwszName );
  63. pwszName = NULL;
  64. cchName = ++cchTempName;
  65. pwszName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchName * sizeof( *pwszName ) );
  66. if ( pwszName != NULL )
  67. {
  68. dwStatus = GetClusterInformation( hCluster, pwszName, &cchTempName, pClusterInfo );
  69. }
  70. else
  71. {
  72. dwStatus = GetLastError();
  73. }
  74. }
  75. }
  76. else
  77. {
  78. dwStatus = GetLastError();
  79. }
  80. if ( ( dwStatus == ERROR_SUCCESS ) && ( ppszClusterName != NULL ) )
  81. {
  82. *ppszClusterName = pwszName;
  83. }
  84. if ( ( dwStatus != ERROR_SUCCESS ) || ( ppszClusterName == NULL ) )
  85. {
  86. LocalFree( pwszName );
  87. }
  88. return dwStatus;
  89. } //*** WrapGetClusterInformation()
  90. /////////////////////////////////////////////////////////////////////////////
  91. //++
  92. //
  93. // WrapGetClusterQuorumResource
  94. //
  95. // Description:
  96. //
  97. // Arguments:
  98. //
  99. //
  100. // Return Value:
  101. //
  102. //
  103. //--
  104. /////////////////////////////////////////////////////////////////////////////
  105. DWORD WINAPI WrapGetClusterQuorumResource(
  106. IN HCLUSTER hCluster,
  107. OUT LPWSTR * ppwszResourceName,
  108. OUT LPWSTR * ppwszDeviceName,
  109. OUT LPDWORD pdwMaxQuorumLogSize
  110. )
  111. {
  112. DWORD dwStatus;
  113. LPWSTR pwszResourceName = NULL;
  114. DWORD cchResourceName = 128;
  115. DWORD cchTempResourceName = cchResourceName;
  116. LPWSTR pwszDeviceName = NULL;
  117. DWORD cchDeviceName = 128;
  118. DWORD cchTempDeviceName = cchDeviceName;
  119. DWORD dwMaxQuorumLogSize = 0;
  120. // Zero the out parameters
  121. if ( ppwszResourceName != NULL )
  122. {
  123. *ppwszResourceName = NULL;
  124. }
  125. if ( ppwszDeviceName != NULL )
  126. {
  127. *ppwszDeviceName = NULL;
  128. }
  129. if ( pdwMaxQuorumLogSize != NULL )
  130. {
  131. *pdwMaxQuorumLogSize = 0;
  132. }
  133. // Allocate the resource name buffer
  134. pwszResourceName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchResourceName * sizeof( *pwszResourceName ) );
  135. if ( pwszResourceName != NULL )
  136. {
  137. // Allocate the device name buffer
  138. pwszDeviceName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchDeviceName * sizeof( *pwszDeviceName ) );
  139. if ( pwszDeviceName != NULL )
  140. {
  141. dwStatus = GetClusterQuorumResource( hCluster,
  142. pwszResourceName,
  143. &cchTempResourceName,
  144. pwszDeviceName,
  145. &cchTempDeviceName,
  146. &dwMaxQuorumLogSize );
  147. if ( dwStatus == ERROR_MORE_DATA )
  148. {
  149. LocalFree( pwszResourceName );
  150. pwszResourceName = NULL;
  151. cchResourceName = ++cchTempResourceName;
  152. // Allocate the resource name buffer
  153. pwszResourceName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchResourceName * sizeof( *pwszResourceName ) );
  154. if ( pwszResourceName != NULL )
  155. {
  156. LocalFree( pwszDeviceName );
  157. pwszDeviceName = NULL;
  158. cchDeviceName = ++cchTempDeviceName;
  159. // Allocate the device name buffer
  160. pwszDeviceName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchDeviceName * sizeof( *pwszDeviceName ) );
  161. if ( pwszDeviceName != NULL )
  162. {
  163. dwStatus = GetClusterQuorumResource( hCluster,
  164. pwszResourceName,
  165. &cchTempResourceName,
  166. pwszDeviceName,
  167. &cchTempDeviceName,
  168. &dwMaxQuorumLogSize );
  169. }
  170. else
  171. {
  172. dwStatus = GetLastError();
  173. }
  174. }
  175. else
  176. {
  177. dwStatus = GetLastError();
  178. }
  179. }
  180. }
  181. else
  182. {
  183. dwStatus = GetLastError();
  184. }
  185. }
  186. else
  187. {
  188. dwStatus = GetLastError();
  189. }
  190. //
  191. // if we succeeded and if the argument is not NULL then return it.
  192. //
  193. if ( ( dwStatus == ERROR_SUCCESS ) && ( ppwszResourceName != NULL ) )
  194. {
  195. *ppwszResourceName = pwszResourceName;
  196. }
  197. //
  198. // if we succeeded and if the argument is not NULL then return it.
  199. //
  200. if ( ( dwStatus == ERROR_SUCCESS ) && ( ppwszDeviceName != NULL ) )
  201. {
  202. *ppwszDeviceName = pwszDeviceName;
  203. }
  204. //
  205. // if we succeeded and if the argument is not NULL then return it.
  206. //
  207. if ( ( dwStatus == ERROR_SUCCESS ) && ( pdwMaxQuorumLogSize != NULL ) )
  208. {
  209. *pdwMaxQuorumLogSize = dwMaxQuorumLogSize;
  210. }
  211. //
  212. // if we didn't succeeded or if the string argument is NULL then free the string.
  213. //
  214. if ( ( dwStatus != ERROR_SUCCESS ) || ( ppwszResourceName == NULL ) )
  215. {
  216. LocalFree( pwszResourceName );
  217. }
  218. //
  219. // if we didn't succeeded or if the string argument is NULL then free the string.
  220. //
  221. if ( ( dwStatus != ERROR_SUCCESS ) || ( ppwszDeviceName == NULL ) )
  222. {
  223. LocalFree( pwszDeviceName );
  224. }
  225. return dwStatus;
  226. } //*** WrapGetClusterQuorumResource()
  227. /////////////////////////////////////////////////////////////////////////////
  228. //++
  229. //
  230. // Function: WrapClusterEnum
  231. //
  232. // Description:
  233. //
  234. // Arguments:
  235. //
  236. //
  237. // Return Value:
  238. //
  239. //
  240. //--
  241. /////////////////////////////////////////////////////////////////////////////
  242. DWORD WINAPI WrapClusterEnum(
  243. IN HCLUSENUM hEnum,
  244. IN DWORD dwIndex,
  245. OUT LPDWORD pdwType,
  246. OUT LPWSTR * ppwszName
  247. )
  248. {
  249. DWORD dwStatus;
  250. DWORD dwType = 0;
  251. LPWSTR pwszName = NULL;
  252. DWORD cchName = 128;
  253. DWORD cchTempName = cchName;
  254. // Zero the out parameters
  255. if ( pdwType != NULL )
  256. {
  257. *pdwType = 0;
  258. }
  259. if ( ppwszName != NULL )
  260. {
  261. *ppwszName = NULL;
  262. }
  263. pwszName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchName * sizeof( *pwszName ) );
  264. if ( pwszName != NULL )
  265. {
  266. dwStatus = ClusterEnum( hEnum, dwIndex, &dwType, pwszName, &cchTempName );
  267. if ( dwStatus == ERROR_MORE_DATA )
  268. {
  269. LocalFree( pwszName );
  270. pwszName = NULL;
  271. cchName = ++cchTempName;
  272. pwszName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchName * sizeof( *pwszName ) );
  273. if ( pwszName != NULL )
  274. {
  275. dwStatus = ClusterEnum( hEnum, dwIndex, &dwType, pwszName, &cchTempName );
  276. }
  277. else
  278. {
  279. dwStatus = GetLastError();
  280. }
  281. }
  282. }
  283. else
  284. {
  285. dwStatus = GetLastError();
  286. }
  287. //
  288. // if we succeeded and if the argument is not NULL then return it.
  289. //
  290. if ( ( dwStatus == ERROR_SUCCESS ) && ( pdwType != NULL ) )
  291. {
  292. *pdwType = dwType;
  293. }
  294. //
  295. // if we succeeded and if the string argument is not NULL then return the string.
  296. //
  297. if ( ( dwStatus == ERROR_SUCCESS ) && ( ppwszName != NULL ) )
  298. {
  299. *ppwszName = pwszName;
  300. }
  301. //
  302. // if we didn't succeeded or if the string argument is NULL then free the string.
  303. //
  304. if ( ( dwStatus != ERROR_SUCCESS ) || ( ppwszName == NULL ) )
  305. {
  306. LocalFree( pwszName );
  307. }
  308. return dwStatus;
  309. } //*** WrapClusterEnum()
  310. /////////////////////////////////////////////////////////////////////////////
  311. //++
  312. //
  313. // WrapGetClusterNodeId
  314. //
  315. // Description:
  316. //
  317. // Arguments:
  318. //
  319. //
  320. // Return Value:
  321. //
  322. //
  323. //--
  324. /////////////////////////////////////////////////////////////////////////////
  325. DWORD WINAPI WrapGetClusterNodeId(
  326. IN HNODE hNode,
  327. OUT LPWSTR * ppwszNodeId
  328. )
  329. {
  330. DWORD dwStatus;
  331. LPWSTR pwszNodeId = NULL;
  332. DWORD cchNodeId = 128;
  333. DWORD cchTempNodeId = cchNodeId;
  334. // Zero the out parameters
  335. if ( ppwszNodeId != NULL )
  336. {
  337. *ppwszNodeId = NULL;
  338. }
  339. pwszNodeId = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchNodeId * sizeof( *pwszNodeId ) );
  340. if ( pwszNodeId != NULL)
  341. {
  342. dwStatus = GetClusterNodeId( hNode, pwszNodeId, &cchTempNodeId );
  343. if ( dwStatus == ERROR_MORE_DATA )
  344. {
  345. LocalFree( pwszNodeId );
  346. pwszNodeId = NULL;
  347. cchNodeId = ++cchTempNodeId;
  348. pwszNodeId = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchNodeId * sizeof( *pwszNodeId ) );
  349. if ( pwszNodeId != NULL)
  350. {
  351. dwStatus = GetClusterNodeId( hNode, pwszNodeId, &cchTempNodeId );
  352. }
  353. else
  354. {
  355. dwStatus = GetLastError();
  356. }
  357. }
  358. }
  359. else
  360. {
  361. dwStatus = GetLastError();
  362. }
  363. //
  364. // if we succeeded and if the argument is not NULL then return it.
  365. //
  366. if ( ( dwStatus == ERROR_SUCCESS ) && ( ppwszNodeId != NULL ) )
  367. {
  368. *ppwszNodeId = pwszNodeId;
  369. }
  370. //
  371. // if we didn't succeeded or if the string argument is NULL then free the string.
  372. //
  373. if ( ( dwStatus != ERROR_SUCCESS ) || ( ppwszNodeId == NULL ) )
  374. {
  375. LocalFree( pwszNodeId );
  376. }
  377. return dwStatus;
  378. } //*** WrapGetClusterNodeId()
  379. /////////////////////////////////////////////////////////////////////////////
  380. //++
  381. //
  382. // WrapGetClusterGroupState
  383. //
  384. // Description:
  385. // Wrapper function for GetClusterGroupState.
  386. //
  387. // Arguments:
  388. // hGroup [IN] - The group handle.
  389. // ppwszNodeName [OUT] - Catches the name of the node that the group
  390. // is online, if not NULL.
  391. //
  392. // Return Value:
  393. // A cluster group state enum.
  394. //
  395. //--
  396. /////////////////////////////////////////////////////////////////////////////
  397. CLUSTER_GROUP_STATE WINAPI WrapGetClusterGroupState(
  398. IN HGROUP hGroup,
  399. OUT OPTIONAL LPWSTR * ppwszNodeName // = NULL
  400. )
  401. {
  402. CLUSTER_GROUP_STATE cState = ClusterGroupStateUnknown;
  403. if ( ppwszNodeName == NULL )
  404. {
  405. // The caller is not interested in the node name.
  406. // So, just call the actual function.
  407. cState = GetClusterGroupState( hGroup, NULL, 0 );
  408. } // if: the pointer to the node name pointer is not provided.
  409. else
  410. {
  411. LPWSTR pwszNodeName = NULL;
  412. DWORD cchNodeName = 128;
  413. DWORD cchTempNodeName = cchNodeName;
  414. // Zero the out parameters
  415. *ppwszNodeName = NULL;
  416. pwszNodeName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchNodeName * sizeof( *pwszNodeName ) );
  417. if ( pwszNodeName != NULL )
  418. {
  419. cState = GetClusterGroupState( hGroup, pwszNodeName, &cchTempNodeName );
  420. if ( GetLastError() == ERROR_MORE_DATA )
  421. {
  422. cState = ClusterGroupStateUnknown; // reset to error condition
  423. LocalFree( pwszNodeName );
  424. cchNodeName = ++cchTempNodeName;
  425. pwszNodeName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchNodeName * sizeof( *pwszNodeName ) );
  426. if ( pwszNodeName != NULL )
  427. {
  428. cState = GetClusterGroupState( hGroup, pwszNodeName, &cchTempNodeName );
  429. }
  430. }
  431. }
  432. //
  433. // if there was not an error, then return the string.
  434. //
  435. if ( cState != ClusterGroupStateUnknown )
  436. {
  437. *ppwszNodeName = pwszNodeName;
  438. }
  439. else
  440. {
  441. LocalFree( pwszNodeName );
  442. }
  443. } // else: the pointer to the node name pointer is not NULL.
  444. return cState;
  445. } //*** WrapGetClusterGroupState()
  446. /////////////////////////////////////////////////////////////////////////////
  447. //++
  448. //
  449. // WrapClusterGroupEnum
  450. //
  451. // Description:
  452. //
  453. // Arguments:
  454. //
  455. //
  456. // Return Value:
  457. //
  458. //
  459. //--
  460. /////////////////////////////////////////////////////////////////////////////
  461. DWORD WINAPI WrapClusterGroupEnum(
  462. IN HGROUPENUM hGroupEnum,
  463. IN DWORD dwIndex,
  464. OUT LPDWORD pdwType,
  465. OUT LPWSTR * ppwszName
  466. )
  467. {
  468. DWORD dwStatus;
  469. DWORD dwType = 0;
  470. LPWSTR pwszName = NULL;
  471. DWORD cchName = 128;
  472. DWORD cchTempName = cchName;
  473. // Zero the out parameters
  474. if ( pdwType != NULL )
  475. {
  476. *pdwType = NULL;
  477. }
  478. if ( ppwszName != NULL )
  479. {
  480. *ppwszName = NULL;
  481. }
  482. pwszName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchName * sizeof( *pwszName ) );
  483. if ( pwszName != NULL )
  484. {
  485. dwStatus = ClusterGroupEnum( hGroupEnum, dwIndex, &dwType, pwszName, &cchTempName );
  486. if ( dwStatus == ERROR_MORE_DATA )
  487. {
  488. LocalFree( pwszName );
  489. pwszName = NULL;
  490. cchName = ++cchTempName;
  491. pwszName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchName * sizeof( *pwszName ) );
  492. if ( pwszName != NULL )
  493. {
  494. dwStatus = ClusterGroupEnum( hGroupEnum, dwIndex, &dwType, pwszName, &cchTempName );
  495. }
  496. else
  497. {
  498. dwStatus = GetLastError();
  499. }
  500. }
  501. }
  502. else
  503. {
  504. dwStatus = GetLastError();
  505. }
  506. //
  507. // if there was not an error and the argument was not NULL, then return the value.
  508. //
  509. if ( ( dwStatus == ERROR_SUCCESS ) && ( pdwType != NULL ) )
  510. {
  511. *pdwType = dwType;
  512. }
  513. //
  514. // if there was not an error and the argument was not NULL, then return the string.
  515. //
  516. if ( ( dwStatus == ERROR_SUCCESS ) && ( ppwszName != NULL ) )
  517. {
  518. *ppwszName = pwszName;
  519. }
  520. //
  521. // if there was an error and the argument was NULL, then free the string.
  522. //
  523. if ( ( dwStatus != ERROR_SUCCESS ) || ( ppwszName == NULL ) )
  524. {
  525. LocalFree( pwszName );
  526. }
  527. return dwStatus;
  528. } //*** WrapClusterGroupEnum()
  529. /////////////////////////////////////////////////////////////////////////////
  530. //++
  531. //
  532. // WrapClusterNetworkEnum
  533. //
  534. // Description:
  535. //
  536. // Arguments:
  537. //
  538. //
  539. // Return Value:
  540. //
  541. //
  542. //--
  543. /////////////////////////////////////////////////////////////////////////////
  544. DWORD WINAPI WrapClusterNetworkEnum(
  545. IN HNETWORKENUM hEnum,
  546. IN DWORD dwIndex,
  547. OUT LPDWORD pdwType,
  548. OUT LPWSTR * ppwszName
  549. )
  550. {
  551. DWORD dwStatus;
  552. DWORD dwType = 0;
  553. LPWSTR pwszName = NULL;
  554. DWORD cchName = 128;
  555. DWORD cchTempName = cchName;
  556. // Zero the out parameters
  557. if ( pdwType != NULL )
  558. {
  559. *pdwType = 0;
  560. }
  561. if ( ppwszName != NULL )
  562. {
  563. *ppwszName = NULL;
  564. }
  565. pwszName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchName * sizeof( *pwszName ) );
  566. if ( pwszName != NULL )
  567. {
  568. dwStatus = ClusterNetworkEnum( hEnum, dwIndex, &dwType, pwszName, &cchTempName );
  569. if ( dwStatus == ERROR_MORE_DATA )
  570. {
  571. LocalFree( pwszName );
  572. pwszName = NULL;
  573. cchName = ++cchTempName;
  574. pwszName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchName * sizeof( *pwszName ) );
  575. if ( pwszName != NULL )
  576. {
  577. dwStatus = ClusterNetworkEnum( hEnum, dwIndex, &dwType, pwszName, &cchTempName );
  578. }
  579. else
  580. {
  581. dwStatus = GetLastError();
  582. }
  583. }
  584. }
  585. else
  586. {
  587. dwStatus = GetLastError();
  588. }
  589. //
  590. // if there was not an error and the argument was not NULL, then return the value.
  591. //
  592. if ( ( dwStatus == ERROR_SUCCESS ) && ( pdwType != NULL ) )
  593. {
  594. *pdwType = dwType;
  595. }
  596. //
  597. // if there was not an error and the argument was not NULL, then return the string.
  598. //
  599. if ( ( dwStatus == ERROR_SUCCESS ) && ( ppwszName != NULL ) )
  600. {
  601. *ppwszName = pwszName;
  602. }
  603. //
  604. // if there was an error and the argument was NULL, then free the string.
  605. //
  606. if ( ( dwStatus != ERROR_SUCCESS ) || ( ppwszName == NULL ) )
  607. {
  608. LocalFree( pwszName );
  609. }
  610. return dwStatus;
  611. } //*** WrapClusterNetworkEnum()
  612. /////////////////////////////////////////////////////////////////////////////
  613. //++
  614. //
  615. // WrapClusterNodeEnum
  616. //
  617. // Description:
  618. //
  619. // Arguments:
  620. //
  621. //
  622. // Return Value:
  623. //
  624. //
  625. //--
  626. /////////////////////////////////////////////////////////////////////////////
  627. DWORD WINAPI WrapClusterNodeEnum(
  628. IN HNODEENUM hEnum,
  629. IN DWORD dwIndex,
  630. OUT LPDWORD pdwType,
  631. OUT LPWSTR * ppwszName
  632. )
  633. {
  634. DWORD dwStatus;
  635. DWORD dwType = 0;
  636. LPWSTR pwszName = NULL;
  637. DWORD cchName = 128;
  638. DWORD cchTempName = cchName;
  639. // Zero the out parameters
  640. if ( pdwType != NULL )
  641. {
  642. *pdwType = 0;
  643. }
  644. if ( ppwszName != NULL )
  645. {
  646. *ppwszName = NULL;
  647. }
  648. pwszName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchName * sizeof( *pwszName ) );
  649. if ( pwszName != NULL )
  650. {
  651. dwStatus = ClusterNodeEnum( hEnum, dwIndex, &dwType, pwszName, &cchTempName );
  652. if ( dwStatus == ERROR_MORE_DATA )
  653. {
  654. LocalFree( pwszName );
  655. pwszName = NULL;
  656. cchName = ++cchTempName;
  657. pwszName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchName * sizeof( *pwszName ) );
  658. if ( pwszName != NULL )
  659. {
  660. dwStatus = ClusterNodeEnum( hEnum, dwIndex, &dwType, pwszName, &cchTempName );
  661. }
  662. else
  663. {
  664. dwStatus = GetLastError();
  665. }
  666. }
  667. }
  668. else
  669. {
  670. dwStatus = GetLastError();
  671. }
  672. //
  673. // if there was not an error and the argument was not NULL, then return the value.
  674. //
  675. if ( ( dwStatus == ERROR_SUCCESS ) && ( pdwType != NULL ) )
  676. {
  677. *pdwType = dwType;
  678. }
  679. //
  680. // if there was not an error and the argument was not NULL, then return the string.
  681. //
  682. if ( ( dwStatus == ERROR_SUCCESS ) && ( ppwszName != NULL ) )
  683. {
  684. *ppwszName = pwszName;
  685. }
  686. //
  687. // if there was an error and the argument was NULL, then free the string.
  688. //
  689. if ( ( dwStatus != ERROR_SUCCESS ) || ( ppwszName == NULL ) )
  690. {
  691. LocalFree( pwszName );
  692. }
  693. return dwStatus;
  694. } //*** WrapClusterNodeEnum()
  695. /////////////////////////////////////////////////////////////////////////////
  696. //++
  697. //
  698. // WrapGetClusterResourceState
  699. //
  700. // Description:
  701. //
  702. // Arguments:
  703. //
  704. //
  705. // Return Value:
  706. //
  707. //
  708. //--
  709. /////////////////////////////////////////////////////////////////////////////
  710. CLUSTER_RESOURCE_STATE WINAPI WrapGetClusterResourceState(
  711. IN HRESOURCE hResource,
  712. OUT OPTIONAL LPWSTR * ppwszNodeName,
  713. OUT OPTIONAL LPWSTR * ppwszGroupName
  714. )
  715. {
  716. CLUSTER_RESOURCE_STATE cState = ClusterResourceStateUnknown;
  717. LPWSTR pwszNodeName = NULL;
  718. DWORD cchNodeName = 128;
  719. LPWSTR pwszGroupName = NULL;
  720. DWORD cchGroupName = 128;
  721. DWORD cchTempNodeName = cchNodeName;
  722. DWORD cchTempGroupName = cchGroupName;
  723. // Zero the out parameters
  724. if ( ppwszNodeName != NULL )
  725. {
  726. *ppwszNodeName = NULL;
  727. }
  728. if ( ppwszGroupName != NULL )
  729. {
  730. *ppwszGroupName = NULL;
  731. }
  732. pwszNodeName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchNodeName * sizeof( *pwszNodeName ) );
  733. if ( pwszNodeName != NULL )
  734. {
  735. pwszGroupName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchGroupName * sizeof( *pwszGroupName ) );
  736. if ( pwszGroupName != NULL )
  737. {
  738. cState = GetClusterResourceState( hResource, pwszNodeName, &cchTempNodeName, pwszGroupName, &cchTempGroupName );
  739. if ( GetLastError() == ERROR_MORE_DATA )
  740. {
  741. cState = ClusterResourceStateUnknown; // reset to error condition
  742. LocalFree( pwszNodeName );
  743. pwszNodeName = NULL;
  744. cchNodeName = ++cchTempNodeName;
  745. LocalFree( pwszGroupName );
  746. pwszGroupName = NULL;
  747. cchGroupName = ++cchTempGroupName;
  748. pwszNodeName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchNodeName * sizeof( *pwszNodeName ) );
  749. if ( pwszNodeName != NULL )
  750. {
  751. pwszGroupName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchGroupName * sizeof( *pwszGroupName ) );
  752. if ( pwszGroupName != NULL )
  753. {
  754. cState = GetClusterResourceState( hResource,
  755. pwszNodeName,
  756. &cchNodeName,
  757. pwszGroupName,
  758. &cchGroupName );
  759. }
  760. }
  761. }
  762. }
  763. }
  764. //
  765. // if there was not an error and the argument was not NULL, then return the string.
  766. //
  767. if ( ( cState != ClusterResourceStateUnknown ) && ( ppwszNodeName != NULL ) )
  768. {
  769. *ppwszNodeName = pwszNodeName;
  770. }
  771. //
  772. // if there was not an error and the argument was not NULL, then return the string.
  773. //
  774. if ( ( cState != ClusterResourceStateUnknown ) && ( ppwszGroupName != NULL ) )
  775. {
  776. *ppwszGroupName = pwszGroupName;
  777. }
  778. //
  779. // if there was an error or the argument was NULL, then free the string.
  780. //
  781. if ( ( cState == ClusterResourceStateUnknown ) || ( ppwszNodeName == NULL ) )
  782. {
  783. LocalFree( pwszNodeName );
  784. }
  785. //
  786. // if there was an error or the argument was NULL, then free the string.
  787. //
  788. if ( ( cState == ClusterResourceStateUnknown ) || ( ppwszGroupName == NULL ) )
  789. {
  790. LocalFree( pwszGroupName );
  791. }
  792. return cState;
  793. } //*** WrapGetClusterResourceState()
  794. /*
  795. /////////////////////////////////////////////////////////////////////////////
  796. //++
  797. //
  798. // WrapGetClusterNetInterfaceState
  799. //
  800. // Description:
  801. //
  802. // Arguments:
  803. //
  804. //
  805. // Return Value:
  806. //
  807. //
  808. //--
  809. /////////////////////////////////////////////////////////////////////////////
  810. CLUSTER_NETINTERFACE_STATE WINAPI WrapGetClusterNetInterfaceState(
  811. IN HNETINTERFACE hNetInterface
  812. )
  813. {
  814. return GetClusterNetInterfaceState( hNetInterface );
  815. } //*** WrapGetClusterNetInterfaceState()
  816. /////////////////////////////////////////////////////////////////////////////
  817. //++
  818. //
  819. // WrapGetClusterNetworkState
  820. //
  821. // Description:
  822. //
  823. // Arguments:
  824. //
  825. //
  826. // Return Value:
  827. //
  828. //
  829. //--
  830. /////////////////////////////////////////////////////////////////////////////
  831. CLUSTER_NETWORK_STATE WINAPI WrapGetClusterNetworkState(
  832. IN HNETWORK hNetwork
  833. )
  834. {
  835. return GetClusterNetworkState( hNetwork );
  836. } //*** WrapGetClusterNetworkState()
  837. */
  838. /////////////////////////////////////////////////////////////////////////////
  839. //++
  840. //
  841. // WrapClusterResourceEnum
  842. //
  843. // Description:
  844. //
  845. // Arguments:
  846. //
  847. //
  848. // Return Value:
  849. //
  850. //
  851. //--
  852. /////////////////////////////////////////////////////////////////////////////
  853. DWORD WINAPI WrapClusterResourceEnum(
  854. IN HRESENUM hResEnum,
  855. IN DWORD dwIndex,
  856. OUT LPDWORD pdwType,
  857. OUT LPWSTR * ppwszName
  858. )
  859. {
  860. DWORD dwStatus;
  861. DWORD dwType = 0;
  862. LPWSTR pwszName = NULL;
  863. DWORD cchName = 128;
  864. DWORD cchTempName = cchName;
  865. // Zero the out parameters
  866. if ( pdwType != NULL )
  867. {
  868. *pdwType = 0;
  869. }
  870. if ( ppwszName != NULL )
  871. {
  872. *ppwszName = NULL;
  873. }
  874. pwszName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchName * sizeof( *pwszName ) );
  875. if ( pwszName != NULL )
  876. {
  877. dwStatus = ClusterResourceEnum( hResEnum, dwIndex, &dwType, pwszName, &cchTempName );
  878. if ( dwStatus == ERROR_MORE_DATA )
  879. {
  880. LocalFree( pwszName );
  881. pwszName = NULL;
  882. cchName = ++cchTempName;
  883. pwszName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchName * sizeof( *pwszName ) );
  884. if ( pwszName != NULL )
  885. {
  886. dwStatus = ClusterResourceEnum( hResEnum, dwIndex, &dwType, pwszName, &cchTempName );
  887. }
  888. else
  889. {
  890. dwStatus = GetLastError();
  891. }
  892. }
  893. }
  894. else
  895. {
  896. dwStatus = GetLastError();
  897. }
  898. //
  899. // if there was not an error and the argument was not NULL, then return the value.
  900. //
  901. if ( ( dwStatus == ERROR_SUCCESS ) && ( pdwType != NULL ) )
  902. {
  903. *pdwType = dwType;
  904. }
  905. //
  906. // if there was not an error and the argument was not NULL, then return the string.
  907. //
  908. if ( ( dwStatus == ERROR_SUCCESS ) && ( ppwszName != NULL ) )
  909. {
  910. *ppwszName = pwszName;
  911. }
  912. //
  913. // if there was an error and the argument was NULL, then free the string.
  914. //
  915. if ( ( dwStatus != ERROR_SUCCESS ) || ( ppwszName == NULL ) )
  916. {
  917. LocalFree( pwszName );
  918. }
  919. return dwStatus;
  920. } //*** WrapClusterResourceEnum()
  921. /////////////////////////////////////////////////////////////////////////////
  922. //++
  923. //
  924. // WrapClusterResourceTypeEnum
  925. //
  926. // Description:
  927. //
  928. // Arguments:
  929. //
  930. //
  931. // Return Value:
  932. //
  933. //
  934. //--
  935. /////////////////////////////////////////////////////////////////////////////
  936. DWORD WINAPI WrapClusterResourceTypeEnum(
  937. IN HRESTYPEENUM hResEnum,
  938. IN DWORD dwIndex,
  939. OUT LPDWORD pdwType,
  940. OUT LPWSTR * ppwszName
  941. )
  942. {
  943. DWORD dwStatus;
  944. DWORD dwType = 0;
  945. LPWSTR pwszName = NULL;
  946. DWORD cchName = 128;
  947. DWORD cchTempName = cchName;
  948. // Zero the out parameters
  949. if ( pdwType != NULL )
  950. {
  951. *pdwType = 0;
  952. }
  953. if ( ppwszName != NULL )
  954. {
  955. *ppwszName = NULL;
  956. }
  957. pwszName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchName * sizeof( *pwszName ) );
  958. if ( pwszName != NULL )
  959. {
  960. dwStatus = ClusterResourceTypeEnum( hResEnum, dwIndex, &dwType, pwszName, &cchTempName );
  961. if ( dwStatus == ERROR_MORE_DATA )
  962. {
  963. LocalFree( pwszName );
  964. pwszName = NULL;
  965. cchName = ++cchTempName;
  966. pwszName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, cchName * sizeof( *pwszName ) );
  967. if ( pwszName != NULL )
  968. {
  969. dwStatus = ClusterResourceTypeEnum( hResEnum, dwIndex, &dwType, pwszName, &cchTempName );
  970. }
  971. else
  972. {
  973. dwStatus = GetLastError();
  974. }
  975. }
  976. }
  977. else
  978. {
  979. dwStatus = GetLastError();
  980. }
  981. //
  982. // if there was not an error and the argument was not NULL, then return the value.
  983. //
  984. if ( ( dwStatus == ERROR_SUCCESS ) && ( pdwType != NULL ) )
  985. {
  986. *pdwType = dwType;
  987. }
  988. //
  989. // if there was not an error and the argument was not NULL, then return the string.
  990. //
  991. if ( ( dwStatus == ERROR_SUCCESS ) && ( ppwszName != NULL ) )
  992. {
  993. *ppwszName = pwszName;
  994. }
  995. //
  996. // if there was an error and the argument was NULL, then free the string.
  997. //
  998. if ( ( dwStatus != ERROR_SUCCESS ) || ( ppwszName == NULL ) )
  999. {
  1000. LocalFree( pwszName );
  1001. }
  1002. return dwStatus;
  1003. } //*** WrapClusterResourceTypeEnum()
  1004. //*************************************************************************//
  1005. /////////////////////////////////////////////////////////////////////////////
  1006. // Misc helper functions, etc.
  1007. /////////////////////////////////////////////////////////////////////////////
  1008. /////////////////////////////////////////////////////////////////////////////
  1009. // CClusterNotifyPort
  1010. /////////////////////////////////////////////////////////////////////////////
  1011. /////////////////////////////////////////////////////////////////////////////
  1012. //++
  1013. //
  1014. // CClusterNotifyPort::CClusterNotifyPort
  1015. //
  1016. // Description: This class is a wrapper for the cluster notify port
  1017. //
  1018. // Arguments:
  1019. //
  1020. //
  1021. // Return Value:
  1022. //
  1023. //
  1024. //--
  1025. /////////////////////////////////////////////////////////////////////////////
  1026. CClusterNotifyPort::CClusterNotifyPort( void )
  1027. {
  1028. m_dwNotifyKey = 0;
  1029. m_dwFilterType = 0;
  1030. m_szName = NULL;
  1031. m_cchName = 0;
  1032. m_hChange = NULL;
  1033. } //*** CClusterNotifyPort::CClusterNotifyPort()
  1034. /////////////////////////////////////////////////////////////////////////////
  1035. //++
  1036. //
  1037. // CClusterNotifyPort::~CClusterNotifyPort
  1038. //
  1039. // Description:
  1040. //
  1041. // Arguments:
  1042. //
  1043. //
  1044. // Return Value:
  1045. //
  1046. //
  1047. //--
  1048. /////////////////////////////////////////////////////////////////////////////
  1049. CClusterNotifyPort::~CClusterNotifyPort( void )
  1050. {
  1051. if( NULL != m_szName )
  1052. {
  1053. delete [] m_szName;
  1054. }
  1055. Close();
  1056. } //*** CClusterNotifyPort::~CClusterNotifyPort()
  1057. /////////////////////////////////////////////////////////////////////////////
  1058. //++
  1059. //
  1060. // CClusterNotifyPort::Create
  1061. //
  1062. // Description:
  1063. //
  1064. // Arguments:
  1065. //
  1066. //
  1067. // Return Value:
  1068. //
  1069. //
  1070. //--
  1071. /////////////////////////////////////////////////////////////////////////////
  1072. DWORD CClusterNotifyPort::Create(
  1073. HCHANGE hChange,
  1074. HCLUSTER hCluster,
  1075. DWORD dwFilter,
  1076. DWORD_PTR dwNotifyKey
  1077. )
  1078. {
  1079. DWORD sc = ERROR_SUCCESS;
  1080. m_hChange = CreateClusterNotifyPort( hChange, hCluster, dwFilter, dwNotifyKey );
  1081. if ( m_hChange == NULL )
  1082. {
  1083. sc = GetLastError();
  1084. }
  1085. return sc;
  1086. } //*** CClusterNotifyPort::Create()
  1087. /////////////////////////////////////////////////////////////////////////////
  1088. //++
  1089. //
  1090. // CClusterNotifyPort::Close
  1091. //
  1092. // Description:
  1093. //
  1094. // Arguments:
  1095. //
  1096. //
  1097. // Return Value:
  1098. //
  1099. //
  1100. //--
  1101. /////////////////////////////////////////////////////////////////////////////
  1102. DWORD CClusterNotifyPort::Close( void )
  1103. {
  1104. DWORD sc = ERROR_SUCCESS;
  1105. if ( m_hChange != NULL )
  1106. {
  1107. sc = CloseClusterNotifyPort( m_hChange );
  1108. }
  1109. return sc;
  1110. } //*** CClusterNotifyPort::Close()
  1111. /////////////////////////////////////////////////////////////////////////////
  1112. //++
  1113. //
  1114. // CClusterNotifyPort::Register
  1115. //
  1116. // Description:
  1117. //
  1118. // Arguments:
  1119. //
  1120. //
  1121. // Return Value:
  1122. //
  1123. //
  1124. //--
  1125. /////////////////////////////////////////////////////////////////////////////
  1126. DWORD CClusterNotifyPort::Register(
  1127. DWORD dwFilterType,
  1128. HANDLE hObject,
  1129. DWORD_PTR dwNotifyKey
  1130. )
  1131. {
  1132. return RegisterClusterNotify( m_hChange, dwFilterType, hObject, dwNotifyKey );
  1133. } //*** CClusterNotifyPort::Register()
  1134. /////////////////////////////////////////////////////////////////////////////
  1135. //++
  1136. //
  1137. // CClusterNotifyPort::GetNotify
  1138. //
  1139. // Description:
  1140. //
  1141. // Arguments:
  1142. //
  1143. //
  1144. // Return Value:
  1145. //
  1146. //
  1147. //--
  1148. /////////////////////////////////////////////////////////////////////////////
  1149. DWORD CClusterNotifyPort::GetNotify( void )
  1150. {
  1151. DWORD sc = ERROR_SUCCESS;
  1152. DWORD cchName;
  1153. cchName = m_cchName;
  1154. //
  1155. // Wait until state changes or 1 second elapses
  1156. //
  1157. sc = GetClusterNotify( m_hChange, &m_dwNotifyKey, &m_dwFilterType, m_szName, &cchName, 1000 );
  1158. //
  1159. // If we got an error_more_data or we passed in a NULL buffer pointer and got error_success
  1160. // then we have to resize our buffer. Member m_szName is initialized to NULL.
  1161. //
  1162. if ( sc == ERROR_MORE_DATA ||
  1163. ( m_szName == NULL && sc == ERROR_SUCCESS ) )
  1164. {
  1165. //
  1166. // resize the buffer
  1167. //
  1168. delete [] m_szName;
  1169. cchName++; // add one for NULL
  1170. m_cchName = cchName;
  1171. m_szName = new WCHAR[ m_cchName ];
  1172. if ( m_szName == NULL )
  1173. {
  1174. sc = ERROR_NOT_ENOUGH_MEMORY;
  1175. } // if:
  1176. else
  1177. {
  1178. cchName = m_cchName;
  1179. sc = GetClusterNotify( m_hChange, &m_dwNotifyKey, &m_dwFilterType, m_szName, &cchName, 0 );
  1180. } // else:
  1181. } // if:
  1182. return sc;
  1183. } //*** CClusterNotifyPort::GetNotify()
  1184. /////////////////////////////////////////////////////////////////////////////
  1185. //++
  1186. //
  1187. // WaitForResourceStateChange
  1188. //
  1189. // Description:
  1190. // Wait for the resource state to change to a non pending state.
  1191. //
  1192. // Arguments:
  1193. // hCluster [IN] - handle to the cluster
  1194. // pwszName [IN] - name of the resource to wait on
  1195. // pPort [IN] - notification port to use
  1196. // pnWait [IN OUT] - ~ number of seconds to wait
  1197. //
  1198. // Return Value:
  1199. // ERROR_SUCCESS or other Win32 error
  1200. //
  1201. //--
  1202. /////////////////////////////////////////////////////////////////////////////
  1203. static DWORD WaitForResourceStateChange(
  1204. IN HCLUSTER hCluster,
  1205. IN LPWSTR pwszName,
  1206. IN CClusterNotifyPort * pPort,
  1207. IN OUT DWORD * pnWait
  1208. )
  1209. {
  1210. CLUSTER_RESOURCE_STATE crs = ClusterResourceStateUnknown;
  1211. HRESOURCE hResource = NULL;
  1212. DWORD _sc = ERROR_SUCCESS;
  1213. if ( pnWait != NULL )
  1214. {
  1215. hResource = OpenClusterResource( hCluster, pwszName );
  1216. if ( hResource != NULL )
  1217. {
  1218. while ( *pnWait > 0 )
  1219. {
  1220. crs = WrapGetClusterResourceState( hResource, NULL, NULL );
  1221. if ( crs != ClusterResourceStateUnknown )
  1222. {
  1223. //
  1224. // if the state is greater than ClusterResourcePending then it's
  1225. // in a pending state and we want to wait for the next notification.
  1226. //
  1227. if ( crs > ClusterResourcePending )
  1228. {
  1229. pPort->GetNotify(); // this will only wait for up to 1 second.
  1230. --(*pnWait);
  1231. } // if: resource is in pending state
  1232. else
  1233. {
  1234. break;
  1235. } // else if: resource is no longer in a pending state
  1236. } // if: WrapClusterResourceState
  1237. else
  1238. {
  1239. _sc = GetLastError();
  1240. break;
  1241. } // else: WrapClusterResourceState failed
  1242. } // while: *pnWait > 0
  1243. CloseClusterResource( hResource );
  1244. } // if: OpenClusterResource ok
  1245. else
  1246. {
  1247. _sc = GetLastError();
  1248. } // else: OpenClusterResource failed
  1249. } // if: pnWait not NULL, this is for safety only
  1250. return _sc;
  1251. } //*** WaitForResourceStateChange()
  1252. /////////////////////////////////////////////////////////////////////////////
  1253. //++
  1254. //
  1255. // HrWaitForResourceStateChange
  1256. //
  1257. // Description:
  1258. // Wrapper for WaitForResourceStateChange.
  1259. //
  1260. // Arguments:
  1261. // hCluster [IN] - handle to the cluster
  1262. // pwszName [IN] - name of the resource to wait on
  1263. // pPort [IN] - notification port to use
  1264. // pnWait [IN OUT] - ~ number of seconds to wait
  1265. //
  1266. // Return Value:
  1267. // S_OK or other Win32 HRESULT error
  1268. //
  1269. //--
  1270. /////////////////////////////////////////////////////////////////////////////
  1271. static HRESULT HrWaitForResourceStateChange(
  1272. IN HCLUSTER hCluster,
  1273. IN LPWSTR pwszName,
  1274. IN CClusterNotifyPort * pPort,
  1275. IN OUT DWORD * pnWait
  1276. )
  1277. {
  1278. DWORD _sc = WaitForResourceStateChange( hCluster, pwszName, pPort, pnWait );
  1279. return HRESULT_FROM_WIN32( _sc );
  1280. } //*** HrWaitForResourceStateChange()
  1281. /////////////////////////////////////////////////////////////////////////////
  1282. //++
  1283. //
  1284. // WaitForResourceGroupStateChange
  1285. //
  1286. // Description:
  1287. // Wait for the resource group state to change to a non pending state.
  1288. //
  1289. // Arguments:
  1290. // hCluster [IN] - handle to the cluster
  1291. // hGroup [IN] - handle to the group to wait on
  1292. // pnWait [IN OUT] - ~ number of seconds to wait
  1293. //
  1294. // Return Value:
  1295. // ERROR_SUCCESS or other Win32 error
  1296. //
  1297. //--
  1298. /////////////////////////////////////////////////////////////////////////////
  1299. static DWORD WaitForResourceGroupStateChange(
  1300. IN HCLUSTER hCluster,
  1301. IN HGROUP hGroup,
  1302. IN OUT DWORD * pnWait
  1303. )
  1304. {
  1305. CLUSTER_GROUP_STATE _cgs = ClusterGroupStateUnknown;
  1306. DWORD _sc = ERROR_SUCCESS;
  1307. if ( pnWait != NULL )
  1308. {
  1309. CClusterNotifyPort _port; // Wait for a group state change event
  1310. _sc = _port.Create( (HCHANGE) INVALID_HANDLE_VALUE, hCluster );
  1311. if ( _sc == ERROR_SUCCESS )
  1312. {
  1313. _sc = _port.Register( CLUSTER_CHANGE_GROUP_STATE, hGroup );
  1314. if ( _sc == ERROR_SUCCESS )
  1315. {
  1316. while ( *pnWait > 0 )
  1317. {
  1318. _cgs = WrapGetClusterGroupState( hGroup, NULL );
  1319. if ( _cgs != ClusterGroupStateUnknown )
  1320. {
  1321. //
  1322. // if the state is ClusterGroupPending then it's
  1323. // in a pending state and we want to wait for the next notification.
  1324. //
  1325. if ( _cgs == ClusterGroupPending )
  1326. {
  1327. _port.GetNotify(); // this will only wait for up to 1 second.
  1328. --(*pnWait);
  1329. } // if: resource is in pending state
  1330. else
  1331. {
  1332. break;
  1333. } // else if: resource is no longer in a pending state
  1334. } // if: WrapClusterResourceState
  1335. else
  1336. {
  1337. _sc = GetLastError();
  1338. break;
  1339. } // else: WrapClusterResourceState failed
  1340. } // while: *pnWait > 0
  1341. } // if: port created
  1342. else
  1343. {
  1344. _sc = GetLastError();
  1345. } // else: port registration failed
  1346. } // if: create notification port
  1347. } // if: pnWait not NULL, this is for safety only
  1348. return _sc;
  1349. } //*** WaitForResourceGroupStateChange()
  1350. /////////////////////////////////////////////////////////////////////////////
  1351. //++
  1352. //
  1353. // HrWaitForResourceGroupStateChange
  1354. //
  1355. // Description:
  1356. // Wrapper for WaitForResourceGroupStateChange
  1357. //
  1358. // Arguments:
  1359. // hCluster [IN] - handle to the cluster
  1360. // hGroup [IN] - handle to the group to wait on
  1361. // pnWait [IN OUT] - ~ number of seconds to wait
  1362. //
  1363. // Return Value:
  1364. // S_OK or other Win32 HRESULT error
  1365. //
  1366. //--
  1367. /////////////////////////////////////////////////////////////////////////////
  1368. static HRESULT HrWaitForResourceGroupStateChange(
  1369. IN HCLUSTER hCluster,
  1370. IN HGROUP hGroup,
  1371. IN OUT DWORD * pnWait
  1372. )
  1373. {
  1374. DWORD _sc = WaitForResourceGroupStateChange( hCluster, hGroup, pnWait );
  1375. return HRESULT_FROM_WIN32( _sc );
  1376. } //*** HrWaitForResourceGroupStateChange()
  1377. /////////////////////////////////////////////////////////////////////////////
  1378. //++
  1379. //
  1380. // WaitForGroupToQuiesce
  1381. //
  1382. // Description:
  1383. // Wait for each of the resources in the group to leave a pending state.
  1384. //
  1385. // Arguments:
  1386. // hCluster [IN] - handle to the cluster
  1387. // hGroup [IN] - handle to the group
  1388. // pnWait [IN OUT] - ~ seconds to wait
  1389. //
  1390. // Return Value:
  1391. // ERROR_SUCCESS or error code
  1392. //
  1393. //--
  1394. /////////////////////////////////////////////////////////////////////////////
  1395. static DWORD WaitForGroupToQuiesce(
  1396. IN HCLUSTER hCluster,
  1397. IN HGROUP hGroup,
  1398. IN OUT DWORD * pnWait
  1399. )
  1400. {
  1401. HGROUPENUM hEnum = NULL;
  1402. DWORD _sc = ERROR_SUCCESS;
  1403. if ( ( pnWait != NULL ) && ( *pnWait > 0 ) )
  1404. {
  1405. hEnum = ClusterGroupOpenEnum( hGroup, CLUSTER_GROUP_ENUM_CONTAINS );
  1406. if ( hEnum != NULL)
  1407. {
  1408. CClusterNotifyPort port; // Wait for a group state change event
  1409. _sc = port.Create( (HCHANGE) INVALID_HANDLE_VALUE, hCluster );
  1410. if ( _sc == ERROR_SUCCESS )
  1411. {
  1412. LPWSTR pwszName = NULL;
  1413. DWORD dwIndex = 0;
  1414. DWORD dwType = 0;
  1415. _sc = port.Register( CLUSTER_CHANGE_GROUP_STATE, hGroup );
  1416. if ( _sc == ERROR_SUCCESS )
  1417. {
  1418. for ( dwIndex = 0; _sc == ERROR_SUCCESS; dwIndex++ )
  1419. {
  1420. _sc = WrapClusterGroupEnum( hEnum, dwIndex, &dwType, &pwszName );
  1421. if ( _sc == ERROR_NO_MORE_ITEMS )
  1422. {
  1423. _sc = ERROR_SUCCESS;
  1424. break;
  1425. } // if: WrapClusterGroupEnum out of items -- leave! we are done...
  1426. else if ( _sc == ERROR_SUCCESS )
  1427. {
  1428. _sc = WaitForResourceStateChange( hCluster, pwszName, &port, pnWait );
  1429. ::LocalFree( pwszName );
  1430. pwszName = NULL;
  1431. } // if: WrapClusterGroupEnum succeeded
  1432. else
  1433. {
  1434. _sc = GetLastError();
  1435. } // else: WrapClusterGroupEnum failed!
  1436. } // for: enum the resources in the group
  1437. } // if: notification port registered
  1438. else
  1439. {
  1440. _sc = GetLastError();
  1441. } // else: port registration failed
  1442. } // if: create notification port
  1443. ClusterGroupCloseEnum( hEnum );
  1444. } // if: ClusterGroupOpenEnum succeeds
  1445. else
  1446. {
  1447. _sc = GetLastError();
  1448. } // else: ClusterGroupOpenEnum failed
  1449. } // if: no wait time....
  1450. return _sc;
  1451. } //*** WaitForGroupToQuiesce()
  1452. /////////////////////////////////////////////////////////////////////////////
  1453. //++
  1454. //
  1455. // HrWaitForGroupToQuiesce
  1456. //
  1457. // Description:
  1458. // Wrapper for WaitForGroupToQuiesce
  1459. //
  1460. // Arguments:
  1461. // hCluster [IN] - handle to the cluster
  1462. // hGroup [IN] - handle to the group
  1463. // pnWait [IN OUT] - ~ seconds to wait
  1464. //
  1465. // Return Value:
  1466. // S_OK or Win32 error code
  1467. //
  1468. //--
  1469. /////////////////////////////////////////////////////////////////////////////
  1470. static HRESULT HrWaitForGroupToQuiesce(
  1471. IN HCLUSTER hCluster,
  1472. IN HGROUP hGroup,
  1473. IN OUT DWORD * pnWait
  1474. )
  1475. {
  1476. DWORD _sc = WaitForGroupToQuiesce( hCluster, hGroup, pnWait );
  1477. return HRESULT_FROM_WIN32( _sc );
  1478. } //*** HrWaitForGroupToQuiesce()
  1479. /////////////////////////////////////////////////////////////////////////////
  1480. //++
  1481. //
  1482. // WaitForResourceToQuiesce
  1483. //
  1484. // Description:
  1485. // Wrapper function that is called after OnlineClusterResouce and
  1486. // OfflineClusterResource that waits for the resource to finish its
  1487. // state change. Returns the pending state of the resource after the
  1488. // wait period has expired and the state has not changed.
  1489. //
  1490. // Arguments:
  1491. // hCluster [IN] - the cluster handle
  1492. // hResource [IN] - the resource handle to take on or offline
  1493. // pnWait [IN, OUT] - ~ how many seconds to wait
  1494. // pbPending [OUT] - true if the resource is in a pending state
  1495. //
  1496. // Return Value:
  1497. // ERROR_SUCCESS or Win32 error code
  1498. //
  1499. //--
  1500. /////////////////////////////////////////////////////////////////////////////
  1501. static DWORD WaitForResourceToQuiesce(
  1502. IN HCLUSTER hCluster,
  1503. IN HRESOURCE hResource,
  1504. IN OUT DWORD * pnWait,
  1505. OUT long * pbPending
  1506. )
  1507. {
  1508. CLUSTER_RESOURCE_STATE crs = ClusterResourceStateUnknown;
  1509. DWORD _sc = ERROR_SUCCESS;
  1510. if ( ( pnWait != NULL ) && ( *pnWait > 0 ) )
  1511. {
  1512. CClusterNotifyPort port; // if wait is specified open a notify port.
  1513. _sc = port.Create( (HCHANGE) INVALID_HANDLE_VALUE, hCluster );
  1514. if ( _sc == ERROR_SUCCESS )
  1515. {
  1516. _sc = port.Register( CLUSTER_CHANGE_RESOURCE_STATE, hResource );
  1517. if ( _sc == ERROR_SUCCESS )
  1518. {
  1519. //
  1520. // Check the state before we check the notification port.
  1521. //
  1522. crs = WrapGetClusterResourceState( hResource, NULL, NULL );
  1523. if ( crs != ClusterResourceStateUnknown )
  1524. {
  1525. while ( ( *pnWait > 0 ) && ( crs > ClusterResourcePending ) )
  1526. {
  1527. port.GetNotify(); // waits for ~ 1 second
  1528. crs = WrapGetClusterResourceState( hResource, NULL, NULL );
  1529. --(*pnWait);
  1530. } // while:
  1531. } // if: get resource state
  1532. else
  1533. {
  1534. _sc = GetLastError();
  1535. } // else: get resource state failed
  1536. } // if: port was registered ok
  1537. } // if: port was created ok
  1538. } // if: *pnWait > 0
  1539. else
  1540. {
  1541. crs = ClusterResourceOnlinePending;
  1542. } // else: no time to wait and the resource is/was ERROR_IO_PENDING
  1543. //
  1544. // return the pending state if the caller has asked for it
  1545. //
  1546. if ( pbPending != NULL )
  1547. {
  1548. if ( crs > ClusterResourcePending )
  1549. {
  1550. *pbPending = TRUE;
  1551. } // if: is the resource still in a pending state
  1552. } // if: does the argument exist?
  1553. return _sc;
  1554. } //*** WaitForResourceToQuiesce()
  1555. /////////////////////////////////////////////////////////////////////////////
  1556. //++
  1557. //
  1558. // HrWaitForResourceToQuiesce
  1559. //
  1560. // Description:
  1561. // Wrapper function for WaitForResourceToQuiesce
  1562. //
  1563. // Arguments:
  1564. // hCluster [IN] - the cluster handle
  1565. // hResource [IN] - the resource handle to take on or offline
  1566. // pnWait [IN, OUT] - ~ how many seconds to wait
  1567. // pbPending [OUT] - true if the resource is in a pending state
  1568. //
  1569. // Return Value:
  1570. // S_OK or Win32 error code
  1571. //
  1572. //--
  1573. /////////////////////////////////////////////////////////////////////////////
  1574. static HRESULT HrWaitForResourceToQuiesce(
  1575. IN HCLUSTER hCluster,
  1576. IN HRESOURCE hResource,
  1577. IN OUT DWORD * pnWait,
  1578. OUT long * pbPending
  1579. )
  1580. {
  1581. DWORD _sc = WaitForResourceToQuiesce( hCluster, hResource, pnWait, pbPending );
  1582. return HRESULT_FROM_WIN32( _sc );
  1583. } //*** HrWaitForResourceToQuiesce()
  1584. /////////////////////////////////////////////////////////////////////////////
  1585. //++
  1586. //
  1587. // ScWrapOnlineClusterResource
  1588. //
  1589. // Description:
  1590. // Wrapper function for OnlineClusterResouce that returns the pending
  1591. // state of the resource after the wait period has expired.
  1592. //
  1593. // Arguments:
  1594. // hCluster [IN] - the cluster handle
  1595. // hResource [IN] - the resource handle to take on or offline
  1596. // nWait [IN] - ~ how many seconds to wait
  1597. // pbPending [OUT] - true if the resource is in a pending state
  1598. //
  1599. // Return Value:
  1600. // ERROR_SUCCESS or Win32 error code
  1601. //
  1602. //--
  1603. /////////////////////////////////////////////////////////////////////////////
  1604. DWORD ScWrapOnlineClusterResource(
  1605. IN HCLUSTER hCluster,
  1606. IN HRESOURCE hResource,
  1607. IN DWORD nWait, //=0
  1608. OUT long * pbPending //=NULL
  1609. )
  1610. {
  1611. DWORD _sc = ERROR_SUCCESS;
  1612. _sc = OnlineClusterResource( hResource );
  1613. if ( _sc == ERROR_IO_PENDING )
  1614. {
  1615. _sc = WaitForResourceToQuiesce( hCluster, hResource, &nWait, pbPending );
  1616. } // if: ERROR_IO_PENDING
  1617. else if ( _sc == ERROR_SUCCESS )
  1618. {
  1619. if ( pbPending != NULL )
  1620. {
  1621. *pbPending = FALSE;
  1622. }
  1623. } // else if: ERROR_SUCCESS, resource must be online!
  1624. return _sc;
  1625. } //*** ScWrapOnlineClusterResource()
  1626. /////////////////////////////////////////////////////////////////////////////
  1627. //++
  1628. //
  1629. // HrWrapOnlineClusterResource
  1630. //
  1631. // Description:
  1632. // Wrapper function for WrapOnlineClusterResouce
  1633. //
  1634. // Arguments:
  1635. // hCluster [IN] - the cluster handle
  1636. // hResource [IN] - the resource handle to take on or offline
  1637. // nWait [IN] - ~ how many seconds to wait
  1638. // pbPending [OUT] - true if the resource is in a pending state
  1639. //
  1640. // Return Value:
  1641. // S_OK or Win32 error code
  1642. //
  1643. //--
  1644. /////////////////////////////////////////////////////////////////////////////
  1645. HRESULT HrWrapOnlineClusterResource(
  1646. IN HCLUSTER hCluster,
  1647. IN HRESOURCE hResource,
  1648. IN DWORD nWait, //=0
  1649. OUT long * pbPending //=NULL
  1650. )
  1651. {
  1652. DWORD _sc = ScWrapOnlineClusterResource( hCluster, hResource, nWait, pbPending );
  1653. return HRESULT_FROM_WIN32( _sc );
  1654. } //*** HrWrapOnlineClusterResource()
  1655. /////////////////////////////////////////////////////////////////////////////
  1656. //++
  1657. //
  1658. // ScWrapOfflineClusterResource
  1659. //
  1660. // Description:
  1661. // Wrapper function for OfflineClusterResouce that returns the pending
  1662. // state of the resource after the wait period has expired.
  1663. //
  1664. // Arguments:
  1665. // hCluster [IN] - the cluster handle
  1666. // hResource [IN] - the resource handle to take on or offline
  1667. // pnWait [IN] - ~ how many seconds to wait
  1668. // pbPending [OUT] - true if the resource is in a pending state
  1669. //
  1670. // Return Value:
  1671. // ERROR_SUCCESS or Win32 error code
  1672. //
  1673. //--
  1674. /////////////////////////////////////////////////////////////////////////////
  1675. DWORD ScWrapOfflineClusterResource(
  1676. IN HCLUSTER hCluster,
  1677. IN HRESOURCE hResource,
  1678. IN DWORD nWait, //=0
  1679. OUT long * pbPending //=NULL
  1680. )
  1681. {
  1682. DWORD _sc = ERROR_SUCCESS;
  1683. _sc = OfflineClusterResource( hResource );
  1684. if ( _sc == ERROR_IO_PENDING )
  1685. {
  1686. _sc = WaitForResourceToQuiesce( hCluster, hResource, &nWait, pbPending );
  1687. } // if: ERROR_IO_PENDING
  1688. else if ( _sc == ERROR_SUCCESS )
  1689. {
  1690. if ( pbPending != NULL )
  1691. {
  1692. *pbPending = FALSE;
  1693. }
  1694. } // else if: ERROR_SUCCESS, resource must be online!
  1695. return _sc;
  1696. } //*** ScWrapOfflineClusterResource()
  1697. /////////////////////////////////////////////////////////////////////////////
  1698. //++
  1699. //
  1700. // HrWrapOfflineClusterResource
  1701. //
  1702. // Description:
  1703. // Wrapper function for ScWrapOfflineClusterResource
  1704. //
  1705. // Arguments:
  1706. // hCluster [IN] - the cluster handle
  1707. // hResource [IN] - the resource handle to take on or offline
  1708. // pnWait [IN] - ~ how many seconds to wait
  1709. // pbPending [OUT] - true if the resource is in a pending state
  1710. //
  1711. // Return Value:
  1712. // S_OK or Win32 error code
  1713. //
  1714. //--
  1715. /////////////////////////////////////////////////////////////////////////////
  1716. HRESULT HrWrapOfflineClusterResource(
  1717. IN HCLUSTER hCluster,
  1718. IN HRESOURCE hResource,
  1719. IN DWORD nWait, //=0
  1720. OUT long * pbPending //=NULL
  1721. )
  1722. {
  1723. DWORD _sc = ScWrapOfflineClusterResource( hCluster, hResource, nWait, pbPending );
  1724. return HRESULT_FROM_WIN32( _sc );
  1725. } //*** HrWrapOfflineClusterResource()
  1726. /////////////////////////////////////////////////////////////////////////////
  1727. //++
  1728. //
  1729. // ScWrapOnlineClusterGroup
  1730. //
  1731. // Description:
  1732. // Wrapper function for OnlineClusterGroup that returns the pending state
  1733. // of the group after the wait period has expired.
  1734. //
  1735. // Arguments:
  1736. // hCluster [IN] - the cluster handle
  1737. // hGroup [IN] - the group handle to online
  1738. // hNode [IN] - the node the group should be brought online
  1739. // pnWait [IN] - ~ how many seconds to wait
  1740. // pbPending [OUT] - true if the resource is in a pending state
  1741. //
  1742. // Return Value:
  1743. // ERROR_SUCCESS or Win32 error code
  1744. //
  1745. //--
  1746. /////////////////////////////////////////////////////////////////////////////
  1747. DWORD ScWrapOnlineClusterGroup(
  1748. IN HCLUSTER hCluster,
  1749. IN HGROUP hGroup,
  1750. IN HNODE hNode, //=NULL
  1751. IN DWORD nWait, //=0
  1752. OUT long * pbPending //=NULL
  1753. )
  1754. {
  1755. CLUSTER_GROUP_STATE cgs = ClusterGroupStateUnknown;
  1756. DWORD _sc = ERROR_SUCCESS;
  1757. BOOL bPending = FALSE;
  1758. _sc = OnlineClusterGroup( hGroup, hNode );
  1759. if ( _sc == ERROR_IO_PENDING )
  1760. {
  1761. //
  1762. // is a wait time provided?
  1763. //
  1764. if ( nWait > 0 )
  1765. {
  1766. //
  1767. // Check the group state before we check the state of the resources. When reporting the
  1768. // group state the cluster API pulls the resource states online and offline pending up
  1769. // to online or offline respectivly. It also pulls the failed state up to offline. This
  1770. // means that a group state of online or offline is misleading because one or more
  1771. // resources could be in a pending state. The only absolute state is PartialOnline, at
  1772. // least one resource is offline (or failed).
  1773. //
  1774. cgs = WrapGetClusterGroupState( hGroup, NULL );
  1775. if ( cgs == ClusterGroupPending )
  1776. {
  1777. _sc = WaitForResourceGroupStateChange( hCluster, hGroup, &nWait );
  1778. } // if: group state is pending
  1779. else if ( ( cgs == ClusterGroupOnline ) || ( cgs == ClusterGroupPartialOnline ) )
  1780. {
  1781. _sc = WaitForGroupToQuiesce( hCluster, hGroup, &nWait );
  1782. if ( _sc == ERROR_SUCCESS )
  1783. {
  1784. bPending = ( nWait == 0 ); // if we ran out of time then something isn't online
  1785. } // if: HrWaitForGroupToQuiesce ok
  1786. } // else if: group is online -- we have to check all of the resources, on downlevel clusters...
  1787. else if ( cgs == ClusterGroupStateUnknown )
  1788. {
  1789. _sc = GetLastError();
  1790. } // else if: get group state failed
  1791. } // if: pnWait > 0
  1792. else
  1793. {
  1794. bPending = TRUE;
  1795. } // if: no wait was specified
  1796. } // if: OnlineClusterGroup returned ERROR_IO_PENDING
  1797. //
  1798. // return the pending state if the caller has asked for it
  1799. //
  1800. if ( pbPending != NULL )
  1801. {
  1802. *pbPending = bPending;
  1803. } // if: does the argument exist?
  1804. return _sc;
  1805. } //*** ScWrapOnlineClusterGroup()
  1806. /////////////////////////////////////////////////////////////////////////////
  1807. //++
  1808. //
  1809. // HrWrapOnlineClusterGroup
  1810. //
  1811. // Description:
  1812. // Wrapper function for ScWrapOnlineClusterGroup
  1813. //
  1814. // Arguments:
  1815. // hCluster [IN] - the cluster handle
  1816. // hGroup [IN] - the group handle to online
  1817. // hNode [IN] - the node the group should be brought online
  1818. // pnWait [IN] - ~ how many seconds to wait
  1819. // pbPending [OUT] - true if the resource is in a pending state
  1820. //
  1821. // Return Value:
  1822. // S_OK or Win32 error code
  1823. //
  1824. //--
  1825. /////////////////////////////////////////////////////////////////////////////
  1826. HRESULT HrWrapOnlineClusterGroup(
  1827. IN HCLUSTER hCluster,
  1828. IN HGROUP hGroup,
  1829. IN HNODE hNode, //=NULL
  1830. IN DWORD nWait, //=0
  1831. OUT long * pbPending //=NULL
  1832. )
  1833. {
  1834. DWORD _sc = ScWrapOnlineClusterGroup( hCluster, hGroup, hNode, nWait, pbPending );
  1835. return HRESULT_FROM_WIN32( _sc );
  1836. } //*** HrWrapOnlineClusterGroup()
  1837. /////////////////////////////////////////////////////////////////////////////
  1838. //++
  1839. //
  1840. // ScWrapOfflineClusterGroup
  1841. //
  1842. // Description:
  1843. // Wrapper function for OfflineClusterGroup that returns the pending
  1844. // state of the group after the wait period has expired.
  1845. //
  1846. // Arguments:
  1847. // hCluster [IN] - the cluster handle
  1848. // hGroup [IN] - the group handle to online
  1849. // pnWait [IN] - ~ how many seconds to wait
  1850. // pbPending [OUT] - true if the resource is in a pending state
  1851. //
  1852. // Return Value:
  1853. // ERROR_SUCCESS or Win32 error code
  1854. //
  1855. //--
  1856. /////////////////////////////////////////////////////////////////////////////
  1857. DWORD ScWrapOfflineClusterGroup(
  1858. IN HCLUSTER hCluster,
  1859. IN HGROUP hGroup,
  1860. IN DWORD nWait, //=0
  1861. OUT long * pbPending //=NULL
  1862. )
  1863. {
  1864. CLUSTER_GROUP_STATE cgs = ClusterGroupStateUnknown;
  1865. DWORD _sc = ERROR_SUCCESS;
  1866. BOOL bPending = FALSE;
  1867. _sc = OfflineClusterGroup( hGroup );
  1868. if ( _sc == ERROR_IO_PENDING )
  1869. {
  1870. //
  1871. // is a wait time provided?
  1872. //
  1873. if ( nWait > 0 )
  1874. {
  1875. //
  1876. // Check the group state before we check the state of the resources. When reporting the
  1877. // group state the cluster API pulls the resource states online and offline pending up
  1878. // to online or offline respectivly. It also pulls the failed state up to offline. This
  1879. // means that a group state of online or offline is misleading because one or more
  1880. // resources could be in a pending state.
  1881. //
  1882. cgs = WrapGetClusterGroupState( hGroup, NULL );
  1883. if ( cgs == ClusterGroupPending )
  1884. {
  1885. _sc = WaitForResourceGroupStateChange( hCluster, hGroup, &nWait );
  1886. } // if: group state is pending
  1887. else if ( cgs == ClusterGroupStateUnknown )
  1888. {
  1889. _sc = GetLastError();
  1890. } // else if: get group state failed
  1891. else if ( ( cgs == ClusterGroupOffline ) || ( cgs == ClusterGroupPartialOnline ) )
  1892. {
  1893. _sc = WaitForGroupToQuiesce( hCluster, hGroup, &nWait );
  1894. if ( _sc == ERROR_SUCCESS )
  1895. {
  1896. bPending = ( nWait == 0 ); // if we ran out of time then something isn't online
  1897. } // if: HrWaitForGroupToQuiesce ok
  1898. } // else if: group is offline -- we have to check all of the resources...
  1899. } // if: pnWait > 0
  1900. else
  1901. {
  1902. bPending = TRUE;
  1903. } // if: no wait was specified
  1904. } // if: OfflineClusterGroup returned ERROR_IO_PENDING
  1905. //
  1906. // return the pending state if the caller has asked for it
  1907. //
  1908. if ( pbPending != NULL )
  1909. {
  1910. *pbPending = bPending;
  1911. } // if: does the argument exist?
  1912. return _sc;
  1913. } //*** ScWrapOfflineClusterGroup()
  1914. /////////////////////////////////////////////////////////////////////////////
  1915. //++
  1916. //
  1917. // HrWrapOfflineClusterGroup
  1918. //
  1919. // Description:
  1920. // Wrapper function for OfflineClusterGroup that returns the pending
  1921. // state of the group after the wait period has expired.
  1922. //
  1923. // Arguments:
  1924. // hCluster [IN] - the cluster handle
  1925. // hGroup [IN] - the group handle to online
  1926. // pnWait [IN] - ~ how many seconds to wait
  1927. // pbPending [OUT] - true if the resource is in a pending state
  1928. //
  1929. // Return Value:
  1930. // S_OK or Win32 error code
  1931. //
  1932. //--
  1933. /////////////////////////////////////////////////////////////////////////////
  1934. HRESULT HrWrapOfflineClusterGroup(
  1935. IN HCLUSTER hCluster,
  1936. IN HGROUP hGroup,
  1937. IN DWORD nWait, //=0
  1938. OUT long * pbPending //=NULL
  1939. )
  1940. {
  1941. DWORD _sc = ScWrapOfflineClusterGroup( hCluster, hGroup, nWait, pbPending );
  1942. return HRESULT_FROM_WIN32( _sc );
  1943. } //*** HrWrapOfflineClusterGroup()
  1944. /////////////////////////////////////////////////////////////////////////////
  1945. //++
  1946. //
  1947. // ScWrapMoveClusterGroup
  1948. //
  1949. // Description:
  1950. // Wrapper function for MoveClusterGroup that returns the pending state
  1951. // of the group after the wait period has expired.
  1952. //
  1953. // Arguments:
  1954. // hCluster [IN] - the cluster handle
  1955. // hGroup [IN] - the group handle to online
  1956. // hNode [IN] - the node the group should be brought online
  1957. // pnWait [IN] - ~ how many seconds to wait
  1958. // pbPending [OUT] - true if the resource is in a pending state
  1959. //
  1960. // Return Value:
  1961. // ERROR_SUCCESS or Win32 error code
  1962. //
  1963. //--
  1964. /////////////////////////////////////////////////////////////////////////////
  1965. DWORD ScWrapMoveClusterGroup(
  1966. IN HCLUSTER hCluster,
  1967. IN HGROUP hGroup,
  1968. IN HNODE hNode, //=NULL
  1969. IN DWORD nWait, //=0
  1970. OUT long * pbPending //=NULL
  1971. )
  1972. {
  1973. LPWSTR pszOriginNodeName = NULL;
  1974. BOOL bPending = FALSE;
  1975. DWORD _sc;
  1976. do // dummy do-while look to avoid gotos.
  1977. {
  1978. CLUSTER_GROUP_STATE cgsInitialState = ClusterGroupStateUnknown;
  1979. CLUSTER_GROUP_STATE cgsCurrentState = ClusterGroupStateUnknown;
  1980. LPWSTR pszCurrentNodeName = NULL;
  1981. // Get the initial group state.
  1982. cgsInitialState = WrapGetClusterGroupState( hGroup, &pszOriginNodeName );
  1983. if ( cgsInitialState == ClusterGroupStateUnknown )
  1984. {
  1985. // Error getting the group state
  1986. _sc = GetLastError();
  1987. break;
  1988. }
  1989. // Move the cluster group.
  1990. _sc = MoveClusterGroup( hGroup, hNode );
  1991. //
  1992. // When MoveClusterGroup returns ERROR_SUCCESS, it just means that the group
  1993. // has changed ownership successfully, but it does not mean that the group is
  1994. // back to the state it was in before the move. Therefore, we still need to
  1995. // wait, if a wait time is provided. If not, we are done.
  1996. //
  1997. if ( nWait <= 0 )
  1998. {
  1999. break;
  2000. }
  2001. //
  2002. // MoveClusterGroup is not done yet
  2003. //
  2004. if ( _sc == ERROR_IO_PENDING )
  2005. {
  2006. _sc = ERROR_SUCCESS;
  2007. do // while (nWait > 0)
  2008. {
  2009. //
  2010. // Get the name of the node which currently owns this group.
  2011. //
  2012. cgsCurrentState = WrapGetClusterGroupState( hGroup, &pszCurrentNodeName );
  2013. if ( cgsCurrentState == ClusterGroupStateUnknown )
  2014. {
  2015. // Error getting the group state
  2016. _sc = GetLastError();
  2017. break;
  2018. }
  2019. if ( lstrcmpiW( pszOriginNodeName, pszCurrentNodeName ) != 0 )
  2020. {
  2021. //
  2022. // If the current owner node is not the original owner, then the call to
  2023. // move group has succeeded. So quit this loop (we still have to see
  2024. // if the group is stable though)
  2025. //
  2026. break;
  2027. } // if: current owner node is not the same as the original owner node
  2028. else
  2029. {
  2030. //
  2031. // Current owner is the same as the original owner.
  2032. // Wait for one second and check again.
  2033. //
  2034. LocalFree( pszCurrentNodeName );
  2035. pszCurrentNodeName = NULL; // Required to prevent freeing memory twice
  2036. --nWait;
  2037. Sleep( 1000 );
  2038. } // if: current owner node is the same as the original owner node
  2039. }
  2040. while ( nWait > 0 );
  2041. LocalFree( pszCurrentNodeName );
  2042. //
  2043. // If we ran out of time waiting for MoveClusterGroup to complete, then
  2044. // set the pending flag and quit.
  2045. //
  2046. if ( nWait <= 0 )
  2047. {
  2048. bPending = TRUE;
  2049. break;
  2050. }
  2051. } // if: MoveClusterGroup returned ERROR_IO_PENDING
  2052. else
  2053. {
  2054. cgsCurrentState = WrapGetClusterGroupState( hGroup, NULL );
  2055. if ( cgsCurrentState == ClusterGroupStateUnknown )
  2056. {
  2057. // Error getting the group state
  2058. _sc = GetLastError();
  2059. }
  2060. } // else: MoveClusterGroup returned ERROR_SUCCESS
  2061. //
  2062. // if something went wrong with MoveClusterGroup, while waiting
  2063. // for it to comeplete or with WrapGetClusterGroupState, then quit.
  2064. //
  2065. if ( _sc != ERROR_SUCCESS )
  2066. {
  2067. break;
  2068. }
  2069. //
  2070. // If the state of the group on the destination node is ClusterGroupFailed
  2071. // then there is nothing much we can do.
  2072. //
  2073. if ( cgsCurrentState == ClusterGroupFailed )
  2074. {
  2075. break;
  2076. }
  2077. //
  2078. // Check the group state before we check the state of the resources. When reporting the
  2079. // group state the cluster API of a NT4 node pulls the resource states online and offline
  2080. // pending up to online or offline respectivly. It also pulls the failed state up to offline.
  2081. // This means that a group state of online or offline is misleading because one or more
  2082. // resources could be in a pending state. The only absolute state is PartialOnline, at
  2083. // least one resource is offline (or failed).
  2084. //
  2085. if ( cgsCurrentState == ClusterGroupPending )
  2086. {
  2087. // The current state is pending. So wait for a state change.
  2088. _sc = WaitForResourceGroupStateChange( hCluster, hGroup, &nWait );
  2089. } // if: the group state is pending.
  2090. else
  2091. {
  2092. _sc = WaitForGroupToQuiesce( hCluster, hGroup, &nWait );
  2093. } // else: group state is online, offline or partial online
  2094. if ( _sc == ERROR_SUCCESS )
  2095. {
  2096. bPending = ( nWait == 0 );
  2097. } // if: everything ok so far
  2098. }
  2099. while ( FALSE ); // dummy do-while look to avoid gotos
  2100. LocalFree( pszOriginNodeName );
  2101. //
  2102. // return the pending state if the caller has asked for it
  2103. //
  2104. if ( pbPending != NULL )
  2105. {
  2106. *pbPending = bPending;
  2107. } // if: does the argument exist?
  2108. return _sc;
  2109. } //*** ScWrapMoveClusterGroup()
  2110. /////////////////////////////////////////////////////////////////////////////
  2111. //++
  2112. //
  2113. // HrWrapMoveClusterGroup
  2114. //
  2115. // Description:
  2116. // Wrapper function for ScWrapMoveClusterGroup that returns the pending state
  2117. // of the group after the wait period has expired.
  2118. //
  2119. // Arguments:
  2120. // hCluster [IN] - the cluster handle
  2121. // hGroup [IN] - the group handle to online
  2122. // hNode [IN] - the node the group should be brought online
  2123. // pnWait [IN] - ~ how many seconds to wait
  2124. // pbPending [OUT] - true if the resource is in a pending state
  2125. //
  2126. // Return Value:
  2127. // S_OK or Win32 error code
  2128. //
  2129. //--
  2130. /////////////////////////////////////////////////////////////////////////////
  2131. HRESULT HrWrapMoveClusterGroup(
  2132. IN HCLUSTER hCluster,
  2133. IN HGROUP hGroup,
  2134. IN HNODE hNode, //=NULL
  2135. IN DWORD nWait, //=0
  2136. OUT long * pbPending //=NULL
  2137. )
  2138. {
  2139. DWORD _sc = ScWrapMoveClusterGroup ( hCluster, hGroup, hNode, nWait, pbPending );
  2140. return HRESULT_FROM_WIN32( _sc );
  2141. } //*** HrWrapMoveClusterGroup()