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.

1000 lines
24 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. clusinfo.c
  6. Abstract:
  7. Retrieves cluster information: net name and TCP/IP address.
  8. Public functions from this module:
  9. bGetClusterNameInfo
  10. This code is a total hack. It relies on internal knowledge about
  11. the registry structure of clustering and NetworkName and TCP/IP adddress:
  12. Questionable Assumptions:
  13. Directly under the resource GUID there will be a value called
  14. "Type" that holds the fixed resource name string.
  15. The resource type names "Network Name" and "IP Address" will
  16. never change or be localized. (They shouldn't be localized, since
  17. they are keys, but I don't see a description value in the registry.)
  18. There will be a key called "Parameters" that will never change
  19. (or get localized).
  20. Bad Assumptions:
  21. IP Address resource stores a value "Address" that holds
  22. a REG_SZ string of the tcpip address.
  23. Network Name resource stores a value "Name" that holds a REG_SZ
  24. string of the network name.
  25. General strategy:
  26. 1. Open self resource based on resource string from SplSvcOpen.
  27. 2. Enumerate dependencies looking for net name.
  28. 3. Find net name and save group name.
  29. 4. Enumerate dependencies of net name looking for IP addresses.
  30. 5. Save all found IP addresses.
  31. Author:
  32. Albert Ting (AlbertT) 25-Sept-96
  33. Revision History:
  34. --*/
  35. #include "precomp.hxx"
  36. #pragma hdrstop
  37. #include "clusinfo.hxx"
  38. #include "alloc.hxx"
  39. #define GROUP_NAME_LEN_HINT MAX_PATH
  40. #define RESOURCE_NAME_LEN_HINT MAX_PATH
  41. #define TYPE_NAME_LEN_HINT MAX_PATH
  42. LPCTSTR gszType = TEXT( "Type" );
  43. LPCTSTR gszParameters = TEXT( "Parameters" );
  44. DWORD kGuidStringByteSize = 100;
  45. /********************************************************************
  46. Callback for Querying cluster registry.
  47. ********************************************************************/
  48. typedef struct _REG_QUERY_VALUE {
  49. HKEY hKey;
  50. LPCTSTR pszValue;
  51. } REG_QUERY_VALUE, *PREG_QUERY_VALUE;
  52. BOOL
  53. bAllocClusterRegQueryValue(
  54. HANDLE hUserData,
  55. PALLOC_DATA pAllocData
  56. )
  57. {
  58. DWORD dwStatus;
  59. PREG_QUERY_VALUE pRegQueryValue = (PREG_QUERY_VALUE)hUserData;
  60. dwStatus = ClusterRegQueryValue( pRegQueryValue->hKey,
  61. pRegQueryValue->pszValue,
  62. NULL,
  63. pAllocData->pBuffer,
  64. &pAllocData->cbBuffer );
  65. if( dwStatus != NO_ERROR ){
  66. SetLastError( dwStatus );
  67. return FALSE;
  68. }
  69. return TRUE;
  70. }
  71. /********************************************************************
  72. Callback for retrieving group name: GetClusterResourceState.
  73. ********************************************************************/
  74. BOOL
  75. bAllocGetClusterResourceState(
  76. HANDLE hUserData,
  77. PALLOC_DATA pAllocData
  78. )
  79. {
  80. DWORD cchGroupName = pAllocData->cbBuffer / sizeof( TCHAR );
  81. CLUSTER_RESOURCE_STATE crs;
  82. crs = GetClusterResourceState( (HRESOURCE)hUserData,
  83. NULL,
  84. 0,
  85. (LPTSTR)pAllocData->pBuffer,
  86. &cchGroupName );
  87. pAllocData->cbBuffer = cchGroupName * sizeof( TCHAR );
  88. return crs != ClusterResourceStateUnknown;
  89. }
  90. /********************************************************************
  91. Callback for enumerating group resources.
  92. ********************************************************************/
  93. typedef struct _RESOURCE_ENUM {
  94. HRESENUM hResEnum;
  95. DWORD dwIndex;
  96. } RESOURCE_ENUM, *PRESOURCE_ENUM;
  97. BOOL
  98. bAllocClusterResourceEnum(
  99. HANDLE hUserData,
  100. PALLOC_DATA pAllocData
  101. )
  102. {
  103. PRESOURCE_ENUM pResourceEnum = (PRESOURCE_ENUM)hUserData;
  104. DWORD dwStatus;
  105. DWORD cchName = pAllocData->cbBuffer / sizeof( TCHAR );
  106. DWORD dwType;
  107. dwStatus = ClusterResourceEnum( pResourceEnum->hResEnum,
  108. pResourceEnum->dwIndex,
  109. &dwType,
  110. (LPTSTR)pAllocData->pBuffer,
  111. &cchName );
  112. pAllocData->cbBuffer = cchName * sizeof( TCHAR );
  113. if( dwStatus != NO_ERROR ){
  114. SetLastError( dwStatus );
  115. return FALSE;
  116. }
  117. return TRUE;
  118. }
  119. /********************************************************************
  120. End callbacks.
  121. ********************************************************************/
  122. typedef struct _CLUSINFO_DATA {
  123. LPCTSTR pszResource;
  124. LPCTSTR pszValue;
  125. } CLUSINFO_DATA, *PCLUSINFO_DATA;
  126. CLUSINFO_DATA gaClusInfoDataMain[] = {
  127. { TEXT( "Network Name" ), TEXT( "Name" ) },
  128. { NULL, NULL }
  129. };
  130. CLUSINFO_DATA gaClusInfoDataNetName[] = {
  131. { TEXT( "IP Address" ), TEXT( "Address" ) },
  132. { NULL, NULL }
  133. };
  134. enum {
  135. ClusInfoName = 0,
  136. ClusInfoAddress,
  137. ClusInfoMax
  138. };
  139. typedef struct _CLUSINFO_DATAOUT {
  140. UINT cbData;
  141. LPCTSTR pszData;
  142. } CLUSINFO_DATAOUT, *PCLUSINFO_DATAOUT;
  143. BOOL
  144. bProcessResourceRegKey(
  145. IN HKEY hKey,
  146. IN PCLUSINFO_DATA pClusInfoData,
  147. IN OUT PCLUSINFO_DATAOUT pClusInfoDataOut
  148. )
  149. /*++
  150. Routine Description:
  151. Checks whether a resource in a cluster matches any of the ClusInfoData
  152. resources. If it does, fill one parameter into the ClusInfoDataOut
  153. parameter (comma delimited string).
  154. Arguments:
  155. hKey - Key to read.
  156. pClusInfoData - Array of different ClusInfoData types that we
  157. want to look for.
  158. pClusInfoDataOut - Container that receives data we have found.
  159. This should be valid on input, since we append to form
  160. a comma delimited string.
  161. Return Value:
  162. TRUE - Success: this may or may not have filled in one of the OUT
  163. parameters, but we didn't encounter any errors trying to read
  164. the resource.
  165. FALSE - Failure (LastError set).
  166. --*/
  167. {
  168. HKEY hKeyParameters = NULL;
  169. LPCTSTR pszType = NULL;
  170. BOOL bStatus = TRUE;
  171. REG_QUERY_VALUE rqv;
  172. DWORD dwStatus;
  173. UINT i;
  174. LPCTSTR pszNewSingleData = NULL;
  175. LPTSTR pszNewData = NULL;
  176. UINT cbNewSingleData;
  177. UINT cbNewData;
  178. rqv.hKey = hKey;
  179. rqv.pszValue = gszType;
  180. pszType = (LPCTSTR)pAllocRead( &rqv,
  181. bAllocClusterRegQueryValue,
  182. TYPE_NAME_LEN_HINT,
  183. NULL );
  184. if( !pszType ){
  185. DBGMSG( DBG_WARN,
  186. ( "bProcessResourceRegKey: ClusterRegOpenKey failed %d\n",
  187. GetLastError() ));
  188. bStatus = FALSE;
  189. goto Done;
  190. }
  191. //
  192. // Walk through the list and check if there is a match.
  193. //
  194. for( i=0; bStatus && pClusInfoData[i].pszResource; ++i ){
  195. UINT cchLen;
  196. if( lstrcmp( pszType, pClusInfoData[i].pszResource )){
  197. //
  198. // No match, continue.
  199. //
  200. continue;
  201. }
  202. //
  203. // Found a match, read a value out of the
  204. // "parameters" key.
  205. //
  206. dwStatus = ClusterRegOpenKey( hKey,
  207. gszParameters,
  208. KEY_READ,
  209. &hKeyParameters );
  210. if( dwStatus != NO_ERROR ){
  211. DBGMSG( DBG_WARN,
  212. ( "bProcessResourceRegKey: ClusterRegOpenKey failed %d\n",
  213. dwStatus ));
  214. bStatus = FALSE;
  215. goto LoopDone;
  216. }
  217. rqv.hKey = hKeyParameters;
  218. rqv.pszValue = pClusInfoData[i].pszValue;
  219. pszNewSingleData = (LPCTSTR)pAllocRead( &rqv,
  220. bAllocClusterRegQueryValue,
  221. TYPE_NAME_LEN_HINT,
  222. NULL );
  223. if( !pszNewSingleData ){
  224. DBGMSG( DBG_WARN,
  225. ( "bProcessResource: Read "TSTR" failed %d\n",
  226. pClusInfoData[i].pszResource, GetLastError() ));
  227. bStatus = FALSE;
  228. goto LoopDone;
  229. }
  230. DBGMSG( DBG_TRACE,
  231. ( "bProcessResource: Read successful: "TSTR"\n",
  232. pszNewSingleData, GetLastError() ));
  233. cchLen = lstrlen( pszNewSingleData );
  234. //
  235. // We have new data in pszNewData, add it to the end.
  236. //
  237. cbNewSingleData = ( cchLen + 1 ) * sizeof( TCHAR );
  238. cbNewData = cbNewSingleData + pClusInfoDataOut[i].cbData;
  239. pszNewData = (LPTSTR)LocalAlloc( LMEM_FIXED, cbNewData );
  240. if( !pszNewData ){
  241. bStatus = FALSE;
  242. goto Done;
  243. }
  244. //
  245. // If we have something, copy it over then add a ',' character.
  246. //
  247. if( pClusInfoDataOut[i].cbData ){
  248. //
  249. // Copy it over.
  250. //
  251. CopyMemory( (PVOID)pszNewData,
  252. (PVOID)pClusInfoDataOut[i].pszData,
  253. pClusInfoDataOut[i].cbData );
  254. //
  255. // Convert the NULL to a comma in our new data.
  256. //
  257. pszNewData[pClusInfoDataOut[i].cbData /
  258. sizeof( pClusInfoDataOut[i].pszData[0] ) - 1] = TEXT( ',' );
  259. }
  260. //
  261. // Copy the new string.
  262. //
  263. CopyMemory( (PBYTE)pszNewData + pClusInfoDataOut[i].cbData,
  264. (PVOID)pszNewSingleData,
  265. cbNewSingleData );
  266. DBGMSG( DBG_TRACE,
  267. ( "bProcessResourceRegKey: Updated ("TSTR") + ("TSTR") = ("TSTR")\n",
  268. DBGSTR(pClusInfoDataOut[i].pszData), pszNewSingleData, pszNewData ));
  269. //
  270. // Now swap the newly created memory with the old one.
  271. // We'll free pszNewSingleData and store the old memory there.
  272. //
  273. pClusInfoDataOut[i].cbData = cbNewData;
  274. LocalFree( (HLOCAL)pszNewSingleData );
  275. pszNewSingleData = pClusInfoDataOut[i].pszData;
  276. pClusInfoDataOut[i].pszData = pszNewData;
  277. pszNewData = NULL;
  278. LoopDone:
  279. if( pszNewSingleData ){
  280. LocalFree( (HLOCAL)pszNewSingleData );
  281. }
  282. if( pszNewData ){
  283. LocalFree( (HLOCAL)pszNewData );
  284. }
  285. if( hKeyParameters && ClusterRegCloseKey( hKeyParameters )){
  286. DBGMSG( DBG_WARN,
  287. ( "bProcessResource: ClusterRegCloseKey1 failed %x\n",
  288. hKey ));
  289. }
  290. }
  291. Done:
  292. if( pszType ){
  293. LocalFree( (HLOCAL)pszType );
  294. }
  295. return bStatus;
  296. }
  297. BOOL
  298. bProcessResource(
  299. IN HCLUSTER hCluster,
  300. IN HRESOURCE hResource,
  301. IN PCLUSINFO_DATA pClusInfoData,
  302. OUT PCLUSINFO_DATAOUT pClusInfoDataOut
  303. )
  304. /*++
  305. Routine Description:
  306. Checks whether a resource in a cluster matches any of the ClusInfoData
  307. resources. If it does, fill one parameter into the ClusInfoDataOut
  308. parameter.
  309. Arguments:
  310. Return Value:
  311. TRUE - Success: this may or may not have filled in one of the OUT
  312. parameters, but we didn't encounter any errors trying to read
  313. the resource.
  314. FALSE - Failure (LastError set).
  315. --*/
  316. {
  317. HKEY hKey = NULL;
  318. LPCTSTR pszType = NULL;
  319. BOOL bStatus = FALSE;
  320. UNREFERENCED_PARAMETER( hCluster );
  321. hKey = GetClusterResourceKey( hResource, KEY_READ );
  322. if( !hKey ){
  323. DBGMSG( DBG_WARN,
  324. ( "bProcessResource: GetClusterResourceKey failed %d\n",
  325. GetLastError() ));
  326. goto Done;
  327. }
  328. bStatus = bProcessResourceRegKey( hKey,
  329. pClusInfoData,
  330. pClusInfoDataOut );
  331. Done:
  332. if( hKey && ClusterRegCloseKey( hKey )){
  333. DBGMSG( DBG_WARN,
  334. ( "bProcessResource: ClusterRegCloseKey2 failed %x\n",
  335. hKey ));
  336. }
  337. return bStatus;
  338. }
  339. /********************************************************************
  340. Enum dependency support. This is handled by calling a callback
  341. with the retieved handle.
  342. ********************************************************************/
  343. typedef BOOL (*ENUM_CALLBACK )(
  344. HCLUSTER hCluster,
  345. HRESOURCE hResource,
  346. HANDLE hData
  347. );
  348. BOOL
  349. bHandleEnumDependencies(
  350. IN HCLUSTER hCluster,
  351. IN HRESOURCE hResource,
  352. IN ENUM_CALLBACK pfnEnumCallback,
  353. IN HANDLE hData,
  354. OUT PUINT puSuccess OPTIONAL
  355. );
  356. /********************************************************************
  357. Callbacks for EnumDependencies.
  358. ********************************************************************/
  359. BOOL
  360. bEnumDependencyCallbackMain(
  361. IN HCLUSTER hCluster,
  362. IN HRESOURCE hResource,
  363. IN HANDLE hData
  364. );
  365. BOOL
  366. bEnumDependencyCallbackNetName(
  367. IN HCLUSTER hCluster,
  368. IN HRESOURCE hResource,
  369. IN HANDLE hData
  370. );
  371. /********************************************************************
  372. Functions.
  373. ********************************************************************/
  374. BOOL
  375. bHandleEnumDependencies(
  376. IN HCLUSTER hCluster,
  377. IN HRESOURCE hResource,
  378. IN ENUM_CALLBACK pfnEnumCallback,
  379. IN HANDLE hData,
  380. OUT PUINT puSuccess OPTIONAL
  381. )
  382. /*++
  383. Routine Description:
  384. Takes a resource and calls pfnEnumCallback for each of the dependent
  385. resources.
  386. Arguments:
  387. hResource - Resource that holds dependencies to check.
  388. pfnEnumCallback - Callback routine.
  389. hData - Private data.
  390. puSuccess - Number of successful hits.
  391. Return Value:
  392. TRUE - success, FALSE - failure.
  393. --*/
  394. {
  395. RESOURCE_ENUM ResourceEnum;
  396. LPCTSTR pszResource;
  397. HRESOURCE hResourceDependency;
  398. UINT uSuccess = 0;
  399. BOOL bStatus = TRUE;
  400. ResourceEnum.hResEnum = ClusterResourceOpenEnum(
  401. hResource,
  402. CLUSTER_RESOURCE_ENUM_DEPENDS );
  403. if( !ResourceEnum.hResEnum ){
  404. DBGMSG( DBG_WARN,
  405. ( "bHandleEnumDependencies: ClusterResourceOpenEnum failed %d\n",
  406. GetLastError() ));
  407. bStatus = FALSE;
  408. } else {
  409. //
  410. // Walk through all the dependent resources and call
  411. // the callback function to process them.
  412. //
  413. for( ResourceEnum.dwIndex = 0; ; ++ResourceEnum.dwIndex ){
  414. pszResource = (LPCTSTR)pAllocRead(
  415. (HANDLE)&ResourceEnum,
  416. bAllocClusterResourceEnum,
  417. RESOURCE_NAME_LEN_HINT,
  418. NULL );
  419. if( !pszResource ){
  420. SPLASSERT( GetLastError() == ERROR_NO_MORE_ITEMS );
  421. bStatus = FALSE;
  422. break;
  423. }
  424. hResourceDependency = OpenClusterResource( hCluster, pszResource );
  425. if( !hResourceDependency ){
  426. DBGMSG( DBG_WARN,
  427. ( "bHandleEnumDependencies: OpenClusterResource failed "TSTR" %d\n",
  428. pszResource, GetLastError() ));
  429. bStatus = FALSE;
  430. } else {
  431. if( pfnEnumCallback( hCluster, hResourceDependency, hData )){
  432. ++uSuccess;
  433. }
  434. if( !CloseClusterResource( hResourceDependency )){
  435. DBGMSG( DBG_WARN,
  436. ( "bProcessResource: CloseClusterResource failed "TSTR" %x %d\n",
  437. pszResource, hResourceDependency, GetLastError() ));
  438. }
  439. }
  440. LocalFree( (HLOCAL)pszResource );
  441. }
  442. if( ClusterResourceCloseEnum( ResourceEnum.hResEnum )){
  443. DBGMSG( DBG_WARN,
  444. ( "bProcessResource: ClusterResourceCloseEnum failed %x\n",
  445. ResourceEnum.hResEnum ));
  446. }
  447. }
  448. if( puSuccess ){
  449. *puSuccess = uSuccess;
  450. }
  451. return bStatus;
  452. }
  453. BOOL
  454. bEnumDependencyCallbackMain(
  455. IN HCLUSTER hCluster,
  456. IN HRESOURCE hResource,
  457. IN HANDLE hData
  458. )
  459. /*++
  460. Routine Description:
  461. This routine processes the dependent resources of the main resource.
  462. It is called once for each.
  463. When we encounter net name, we'll do the same procedure except
  464. look for tcpip addresses.
  465. Arguments:
  466. hResource - This resource is an enumerated dependency.
  467. hData - User supplied ata.
  468. Return Value:
  469. TRUE - Found
  470. FALSE - Not found.
  471. --*/
  472. {
  473. BOOL bStatus;
  474. BOOL bReturn = FALSE;
  475. UINT uSuccess;
  476. bStatus = bProcessResource( hCluster,
  477. hResource,
  478. gaClusInfoDataMain,
  479. (PCLUSINFO_DATAOUT)hData );
  480. //
  481. // If it's successful, it must have been "NetName," since that's
  482. // the only thing we're looking for. In that case, build
  483. // names off of its tcpip addresses.
  484. //
  485. if( bStatus ){
  486. PCLUSINFO_DATAOUT pClusInfoDataOut = (PCLUSINFO_DATAOUT)hData;
  487. bReturn = TRUE;
  488. //
  489. // Use the proper index for tcpip addresses.
  490. //
  491. bStatus = bHandleEnumDependencies(
  492. hCluster,
  493. hResource,
  494. bEnumDependencyCallbackNetName,
  495. (HANDLE)&pClusInfoDataOut[ClusInfoAddress],
  496. &uSuccess );
  497. if( !bStatus || !uSuccess ){
  498. DBGMSG( DBG_WARN,
  499. ( "bEnumDependencyCallbackMain: failed to get ip addr %d %d %d\n",
  500. bStatus, uSuccess, GetLastError() ));
  501. }
  502. } else {
  503. DBGMSG( DBG_WARN,
  504. ( "bEnumDependencyCallbackMain: failed to find net name %d\n",
  505. GetLastError() ));
  506. }
  507. return bReturn;
  508. }
  509. BOOL
  510. bEnumDependencyCallbackNetName(
  511. IN HCLUSTER hCluster,
  512. IN HRESOURCE hResource,
  513. IN HANDLE hData
  514. )
  515. /*++
  516. Routine Description:
  517. This routine processes the dependent resources of the net name
  518. resource.
  519. Arguments:
  520. hResource - This resource is an enumerated dependency.
  521. hData - User supplied ata.
  522. Return Value:
  523. TRUE - continue,
  524. FALSE - stop.
  525. --*/
  526. {
  527. BOOL bStatus;
  528. bStatus = bProcessResource( hCluster,
  529. hResource,
  530. gaClusInfoDataNetName,
  531. (PCLUSINFO_DATAOUT)hData );
  532. return bStatus;
  533. }
  534. /********************************************************************
  535. Main entry point.
  536. ********************************************************************/
  537. BOOL
  538. bGetClusterNameInfo(
  539. IN LPCTSTR pszResource,
  540. OUT LPCTSTR* ppszName,
  541. OUT LPCTSTR* ppszAddress
  542. )
  543. /*++
  544. Routine Description:
  545. Retrieves information about a given resource.
  546. Arguments:
  547. pszResource - Name of the resource. Must not be NULL.
  548. ppszName - Receives LocalAlloc'd string of cluster name.
  549. ppszAddress - Receives LocalAlloc'd TCPIP address name string.
  550. Return Value:
  551. TRUE - Success, *ppszName, *ppszAddress both valid and
  552. must be LocalFree'd when no longer needed.
  553. FALSE - Failed, *ppszName, *ppszAddress both NULL.
  554. LastError set.
  555. --*/
  556. {
  557. HCLUSTER hCluster = NULL;
  558. HRESOURCE hResource = NULL;
  559. HRESENUM hResEnum = NULL;
  560. LPCTSTR pszGroupName = NULL;
  561. UINT uSuccess = 0;
  562. UINT i;
  563. CLUSINFO_DATAOUT aClusInfoDataOut[ClusInfoMax];
  564. //
  565. // Free the strings if there were allocated earlier so we can
  566. // start clean.
  567. //
  568. if( *ppszName ){
  569. LocalFree( (HLOCAL)*ppszName );
  570. *ppszName = NULL;
  571. }
  572. if( *ppszAddress ){
  573. LocalFree( (HLOCAL)*ppszAddress );
  574. *ppszAddress = NULL;
  575. }
  576. ZeroMemory( aClusInfoDataOut, sizeof( aClusInfoDataOut ));
  577. //
  578. // Open the cluster and acquire the information.
  579. //
  580. hCluster = OpenCluster( NULL );
  581. if( !hCluster ){
  582. DBGMSG( DBG_WARN,
  583. ( "bGetClusterNameInfo: OpenCluster failed %d\n",
  584. GetLastError() ));
  585. goto Done;
  586. }
  587. hResource = OpenClusterResource(
  588. hCluster,
  589. pszResource );
  590. if( !hResource ){
  591. DBGMSG( DBG_WARN,
  592. ( "bGetClusterNameInfo: OpenClusterResource "TSTR" failed %d\n",
  593. pszResource, GetLastError() ));
  594. goto Done;
  595. }
  596. //
  597. // Enum through the dependent resources in the group looking for either
  598. // type "IP Address" or "Network Name." These shouldn't be
  599. // localized since they are registry keys (not values).
  600. //
  601. bHandleEnumDependencies( hCluster,
  602. hResource,
  603. bEnumDependencyCallbackMain,
  604. (HANDLE)&aClusInfoDataOut[ClusInfoName],
  605. &uSuccess );
  606. Done:
  607. if( hResource && !CloseClusterResource( hResource )){
  608. DBGMSG( DBG_WARN,
  609. ( "bGetCluseterNameInfo: CloseClusterResource failed %d\n",
  610. GetLastError() ));
  611. }
  612. if( hCluster && !CloseCluster( hCluster )){
  613. DBGMSG( DBG_WARN,
  614. ( "bGetClusterNameInfo: CloseCluster failed %d\n",
  615. GetLastError() ));
  616. }
  617. if( !uSuccess ){
  618. DBGMSG( DBG_WARN,
  619. ( "bGetCluseterNameInfo: No NetName enumerated back! %d\n",
  620. GetLastError() ));
  621. for( i=0; i<COUNTOF( aClusInfoDataOut ); ++i ){
  622. if( aClusInfoDataOut[i].pszData ){
  623. LocalFree( (HLOCAL)aClusInfoDataOut[i].pszData );
  624. }
  625. }
  626. } else {
  627. *ppszName = aClusInfoDataOut[ClusInfoName].pszData;
  628. *ppszAddress = aClusInfoDataOut[ClusInfoAddress].pszData;
  629. }
  630. DBGMSG( DBG_TRACE,
  631. ( "bGetClusterNameInfo: uSuccess %d "TSTR" "TSTR"\n",
  632. uSuccess, DBGSTR( *ppszName ), DBGSTR( *ppszAddress )));
  633. return uSuccess != 0;
  634. }
  635. /*++
  636. Routine Description:
  637. Gets the GUID for a resource.
  638. Arguments:
  639. hResource - handle obtained via OpenClusterResource
  640. Return Value:
  641. ERROR_SUCCESS - The function completed successfully.
  642. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  643. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  644. Win32 error code - The function failed.
  645. --*/
  646. DWORD
  647. GetIDFromName(
  648. IN HRESOURCE hResource,
  649. OUT LPWSTR *ppszID
  650. )
  651. {
  652. DWORD dwError = ERROR_INVALID_PARAMETER;
  653. if (hResource && ppszID)
  654. {
  655. //
  656. // Set the out parameter to something known
  657. //
  658. *ppszID = NULL;
  659. //
  660. // Should be able to hold the string representation of a guid
  661. //
  662. DWORD cbBuf = kGuidStringByteSize;
  663. if (*ppszID = (LPWSTR)LocalAlloc(LMEM_FIXED, cbBuf))
  664. {
  665. if ((dwError = ClusterResourceControl(hResource,
  666. NULL,
  667. CLUSCTL_RESOURCE_GET_ID,
  668. NULL,
  669. 0,
  670. *ppszID,
  671. cbBuf,
  672. &cbBuf)) == ERROR_MORE_DATA)
  673. {
  674. LocalFree(*ppszID);
  675. if (*ppszID = (LPWSTR)LocalAlloc(LMEM_FIXED, cbBuf))
  676. {
  677. dwError = ClusterResourceControl(hResource,
  678. NULL,
  679. CLUSCTL_RESOURCE_GET_ID,
  680. NULL,
  681. 0,
  682. *ppszID,
  683. cbBuf,
  684. &cbBuf);
  685. }
  686. else
  687. {
  688. dwError = GetLastError();
  689. }
  690. }
  691. //
  692. // Free the memory if getting the ID failed
  693. //
  694. if (dwError != ERROR_SUCCESS && *ppszID)
  695. {
  696. LocalFree(*ppszID);
  697. *ppszID = NULL;
  698. }
  699. }
  700. else
  701. {
  702. dwError = GetLastError();
  703. }
  704. }
  705. DBGMSG(DBG_TRACE, ("GetIDFromName returns %u\n", dwError));
  706. return dwError;
  707. }