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.

4111 lines
110 KiB

  1. /*++
  2. Copyright (c) 1997-2001 Microsoft Corporation
  3. Module Name:
  4. resutils.c
  5. Abstract:
  6. Common utility routines for clusters resources
  7. Author:
  8. John Vert (jvert) 12/15/1996
  9. Revision History:
  10. --*/
  11. #include "clusres.h"
  12. #include "clusrtl.h"
  13. #include "winbase.h"
  14. #include "userenv.h"
  15. //#define DBG_PRINT printf
  16. #define DBG_PRINT
  17. typedef struct _WORK_CONTEXT {
  18. PCLUS_WORKER Worker;
  19. PVOID lpParameter;
  20. PWORKER_START_ROUTINE lpStartRoutine;
  21. } WORK_CONTEXT, *PWORK_CONTEXT;
  22. //
  23. // Local Data
  24. //
  25. CRITICAL_SECTION ResUtilWorkerLock;
  26. BOOLEAN
  27. WINAPI
  28. ResUtilDllEntry(
  29. IN HINSTANCE DllHandle,
  30. IN DWORD Reason,
  31. IN LPVOID Reserved
  32. )
  33. /*++
  34. Routine Description:
  35. Main DLL entry for resource utility helper module.
  36. Arguments:
  37. DllHandle - Supplies the DLL Handle.
  38. Reason - Supplies the call reason.
  39. Return Value:
  40. TRUE if successful
  41. FALSE if unsuccessful
  42. --*/
  43. {
  44. if ( Reason == DLL_PROCESS_ATTACH ) {
  45. InitializeCriticalSection(&ResUtilWorkerLock);
  46. DisableThreadLibraryCalls(DllHandle);
  47. }
  48. if ( Reason == DLL_PROCESS_DETACH ) {
  49. DeleteCriticalSection(&ResUtilWorkerLock);
  50. }
  51. return(TRUE);
  52. } // ResUtilDllEntry
  53. DWORD
  54. WINAPI
  55. ResUtilStartResourceService(
  56. IN LPCWSTR pszServiceName,
  57. OUT LPSC_HANDLE phServiceHandle
  58. )
  59. /*++
  60. Routine Description:
  61. Start a service.
  62. Arguments:
  63. pszServiceName - The name of the service to start.
  64. phServiceHandle - Pointer to a handle to receive the service handle
  65. for this service.
  66. Return Value:
  67. ERROR_SUCCESS if successful.
  68. A Win32 error code on failure.
  69. --*/
  70. {
  71. SC_HANDLE serviceHandle;
  72. SC_HANDLE scManagerHandle;
  73. DWORD status = ERROR_SUCCESS;
  74. SERVICE_STATUS serviceStatus;
  75. scManagerHandle = OpenSCManager( NULL, // local machine
  76. NULL, // ServicesActive database
  77. SC_MANAGER_ALL_ACCESS ); // all access
  78. if ( scManagerHandle == NULL ) {
  79. status = GetLastError();
  80. DBG_PRINT( "ResUtilStartResourceService: Cannot access service controller! Error: %u.\n",
  81. status );
  82. return(status);
  83. }
  84. serviceHandle = OpenService( scManagerHandle,
  85. pszServiceName,
  86. SERVICE_ALL_ACCESS );
  87. if ( serviceHandle == NULL ) {
  88. status = GetLastError();
  89. DBG_PRINT( "ResUtilStartResourceService: Cannot open service %ws. Error: %u.\n",
  90. pszServiceName,
  91. status );
  92. CloseServiceHandle( scManagerHandle );
  93. return(status);
  94. }
  95. CloseServiceHandle( scManagerHandle );
  96. if ( !StartService( serviceHandle,
  97. 0,
  98. NULL) ) {
  99. status = GetLastError();
  100. if ( status == ERROR_SERVICE_ALREADY_RUNNING ) {
  101. status = ERROR_SUCCESS;
  102. } else {
  103. DBG_PRINT( "ResUtilStartResourceService: Failed to start %ws service. Error: %u.\n",
  104. pszServiceName,
  105. status );
  106. }
  107. } else {
  108. //
  109. // Wait for the service to start.
  110. //
  111. while ( TRUE ) {
  112. status = ERROR_SUCCESS;
  113. if ( !QueryServiceStatus(serviceHandle, &serviceStatus) ) {
  114. status = GetLastError();
  115. DBG_PRINT("ResUtilStartResourceService: Failed to query status of %ws service. Error: %u.\n",
  116. pszServiceName,
  117. status);
  118. break;
  119. }
  120. if ( serviceStatus.dwCurrentState == SERVICE_RUNNING ) {
  121. break;
  122. } else if ( serviceStatus.dwCurrentState != SERVICE_START_PENDING ) {
  123. status = ERROR_SERVICE_NEVER_STARTED;
  124. DBG_PRINT("ResUtilStartResourceService: Failed to start %ws service. CurrentState: %u.\n",
  125. pszServiceName,
  126. serviceStatus.dwCurrentState);
  127. break;
  128. }
  129. Sleep(200); // Try again in a little bit
  130. }
  131. }
  132. if ( (status == ERROR_SUCCESS) &&
  133. ARGUMENT_PRESENT(phServiceHandle) ) {
  134. *phServiceHandle = serviceHandle;
  135. } else {
  136. CloseServiceHandle( serviceHandle );
  137. }
  138. return(status);
  139. } // ResUtilStartResourceService
  140. DWORD
  141. WINAPI
  142. ResUtilStopResourceService(
  143. IN LPCWSTR pszServiceName
  144. )
  145. /*++
  146. Routine Description:
  147. Stop a service.
  148. Arguments:
  149. pszServiceName - The name of the service to stop.
  150. Return Value:
  151. ERROR_SUCCESS - Service stopped successfully.
  152. Win32 error code - Error stopping service.
  153. --*/
  154. {
  155. SC_HANDLE serviceHandle;
  156. SC_HANDLE scManagerHandle;
  157. DWORD status = ERROR_SUCCESS;
  158. DWORD retryTime = 30*1000; // wait 30 secs for shutdown
  159. DWORD retryTick = 300; // 300 msec at a time
  160. BOOL didStop = FALSE;
  161. SERVICE_STATUS serviceStatus;
  162. scManagerHandle = OpenSCManager( NULL,
  163. NULL,
  164. SC_MANAGER_ALL_ACCESS );
  165. if ( scManagerHandle == NULL ) {
  166. status = GetLastError();
  167. DBG_PRINT("ResUtilStartResourceService: Cannot access service controller! Error: %u.\n",
  168. status);
  169. return(status);
  170. }
  171. serviceHandle = OpenService( scManagerHandle,
  172. pszServiceName,
  173. SERVICE_ALL_ACCESS );
  174. if ( serviceHandle == NULL ) {
  175. status = GetLastError();
  176. DBG_PRINT("ResUtilStartResourceService: Cannot open service %ws. Error: %u.\n",
  177. pszServiceName,
  178. status);
  179. CloseServiceHandle(scManagerHandle);
  180. return(status);
  181. }
  182. CloseServiceHandle(scManagerHandle);
  183. while ( TRUE ) {
  184. status = ERROR_SUCCESS;
  185. if ( !ControlService(serviceHandle,
  186. (didStop ? SERVICE_CONTROL_INTERROGATE : SERVICE_CONTROL_STOP),
  187. &serviceStatus) ) {
  188. status = GetLastError();
  189. if ( status == ERROR_SUCCESS ) {
  190. didStop = TRUE;
  191. if ( serviceStatus.dwCurrentState == SERVICE_STOPPED ) {
  192. DBG_PRINT("ResUtilStartResourceService: service %ws successfully stopped.\n",
  193. pszServiceName);
  194. break;
  195. }
  196. }
  197. }
  198. if ( (status == ERROR_EXCEPTION_IN_SERVICE) ||
  199. (status == ERROR_PROCESS_ABORTED) ||
  200. (status == ERROR_SERVICE_NOT_ACTIVE) ) {
  201. DBG_PRINT("ResUtilStartResourceService: service %ws stopped or died; status = %u.\n",
  202. pszServiceName,
  203. status);
  204. status = ERROR_SUCCESS;
  205. break;
  206. }
  207. if ( (retryTime -= retryTick) <= 0 ) {
  208. DBG_PRINT("ResUtilStartResourceService: service %ws did not stop; giving up.\n",
  209. pszServiceName,
  210. status);
  211. status = ERROR_TIMEOUT;
  212. break;
  213. }
  214. DBG_PRINT("ResUtilStartResourceService: StopResourceService retrying...\n");
  215. Sleep(retryTick);
  216. }
  217. CloseServiceHandle(serviceHandle);
  218. return(status);
  219. } // ResUtilStopResourceService
  220. DWORD
  221. WINAPI
  222. ResUtilVerifyResourceService(
  223. IN LPCWSTR pszServiceName
  224. )
  225. /*++
  226. Routine Description:
  227. Verify that a service is alive.
  228. Arguments:
  229. pszServiceName - The name of the service to verify.
  230. Return Value:
  231. ERROR_SUCCESS - Service is alive.
  232. Win32 error code - Error verifying service, or service is not alive.
  233. --*/
  234. {
  235. BOOL success;
  236. SC_HANDLE serviceHandle;
  237. SC_HANDLE scManagerHandle;
  238. DWORD status = ERROR_SUCCESS;
  239. SERVICE_STATUS serviceStatus;
  240. scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  241. if ( scManagerHandle == NULL ) {
  242. status = GetLastError();
  243. DBG_PRINT("ResUtilStartResourceService: Cannot access service controller! Error: %u.\n",
  244. status);
  245. return(status);
  246. }
  247. serviceHandle = OpenService( scManagerHandle,
  248. pszServiceName,
  249. SERVICE_QUERY_STATUS );
  250. if ( serviceHandle == NULL ) {
  251. status = GetLastError();
  252. DBG_PRINT("ResUtilStartResourceService: Cannot open service %ws. Error: %u.\n",
  253. pszServiceName,
  254. status);
  255. CloseServiceHandle(scManagerHandle);
  256. return(status);
  257. }
  258. CloseServiceHandle(scManagerHandle);
  259. success = QueryServiceStatus( serviceHandle,
  260. &serviceStatus );
  261. status = GetLastError();
  262. CloseServiceHandle(serviceHandle);
  263. if ( !success ) {
  264. DBG_PRINT("ResUtilStartResourceService: Cannot query service %ws. Error: %u.\n",
  265. pszServiceName,
  266. status);
  267. return(status);
  268. }
  269. if ( (serviceStatus.dwCurrentState != SERVICE_RUNNING) &&
  270. (serviceStatus.dwCurrentState != SERVICE_START_PENDING) ) {
  271. DBG_PRINT("ResUtilStartResourceService: Service %ws is not alive: dwCurrentState: %u.\n",
  272. pszServiceName,
  273. serviceStatus.dwCurrentState);
  274. return(ERROR_SERVICE_NOT_ACTIVE);
  275. }
  276. return(ERROR_SUCCESS);
  277. } // ResUtilVerifyResourceService
  278. DWORD
  279. WINAPI
  280. ResUtilStopService(
  281. IN SC_HANDLE hServiceHandle
  282. )
  283. /*++
  284. Routine Description:
  285. Stop a service.
  286. Arguments:
  287. hServiceHandle - The handle of the service to stop.
  288. Return Value:
  289. ERROR_SUCCESS - Service stopped successfully.
  290. Win32 error code - Error stopping service.
  291. Notes:
  292. The hServiceHandle is closed as a side effect of this routine.
  293. --*/
  294. {
  295. DWORD status = ERROR_SUCCESS;
  296. DWORD retryTime = 30*1000; // wait 30 secs for shutdown
  297. DWORD retryTick = 300; // 300 msec at a time
  298. BOOL didStop = FALSE;
  299. SERVICE_STATUS serviceStatus;
  300. while ( TRUE ) {
  301. status = ERROR_SUCCESS;
  302. if ( !ControlService(hServiceHandle,
  303. (didStop ? SERVICE_CONTROL_INTERROGATE : SERVICE_CONTROL_STOP),
  304. &serviceStatus) ) {
  305. status = GetLastError();
  306. if ( status == ERROR_SUCCESS ) {
  307. didStop = TRUE;
  308. if ( serviceStatus.dwCurrentState == SERVICE_STOPPED ) {
  309. DBG_PRINT("ResUtilStartResourceService: service successfully stopped.\n" );
  310. break;
  311. }
  312. }
  313. }
  314. if ( (status == ERROR_EXCEPTION_IN_SERVICE) ||
  315. (status == ERROR_PROCESS_ABORTED) ||
  316. (status == ERROR_SERVICE_NOT_ACTIVE) ) {
  317. DBG_PRINT("ResUtilStartResourceService: service stopped or died; status = %u.\n",
  318. status);
  319. status = ERROR_SUCCESS;
  320. break;
  321. }
  322. if ( (retryTime -= retryTick) <= 0 ) {
  323. DBG_PRINT("ResUtilStartResourceService: service did not stop; giving up.\n",
  324. status);
  325. status = ERROR_TIMEOUT;
  326. break;
  327. }
  328. DBG_PRINT("ResUtilStartResourceService: StopResourceService retrying...\n");
  329. Sleep(retryTick);
  330. }
  331. CloseServiceHandle(hServiceHandle);
  332. return(status);
  333. } // ResUtilStopResourceService
  334. DWORD
  335. WINAPI
  336. ResUtilVerifyService(
  337. IN SC_HANDLE hServiceHandle
  338. )
  339. /*++
  340. Routine Description:
  341. Verify that a service is alive.
  342. Arguments:
  343. hServiceHandle - The handle of the service to verify.
  344. Return Value:
  345. ERROR_SUCCESS - Service is alive.
  346. Win32 error code - Error verifying service, or service is not alive.
  347. --*/
  348. {
  349. BOOL success;
  350. DWORD status = ERROR_SUCCESS;
  351. SERVICE_STATUS serviceStatus;
  352. success = QueryServiceStatus( hServiceHandle,
  353. &serviceStatus );
  354. if ( !success ) {
  355. status = GetLastError();
  356. DBG_PRINT("ResUtilStartResourceService: Cannot query service. Error: %u.\n",
  357. status);
  358. return(status);
  359. }
  360. if ( (serviceStatus.dwCurrentState != SERVICE_RUNNING) &&
  361. (serviceStatus.dwCurrentState != SERVICE_START_PENDING) ) {
  362. DBG_PRINT("ResUtilStartResourceService: Service is not alive: dwCurrentState: %u.\n",
  363. serviceStatus.dwCurrentState);
  364. return(ERROR_SERVICE_NOT_ACTIVE);
  365. }
  366. return(ERROR_SUCCESS);
  367. } // ResUtilVerifyService
  368. /////////////////////////////////////////////////////////////////////////////
  369. //++
  370. //
  371. // ResUtilTerminateServiceProcessFromResDll
  372. //
  373. // Description:
  374. // Attempt to terminate a service process from a resource DLL.
  375. //
  376. // Arguments:
  377. // dwServicePid [IN]
  378. // The process ID of the service process to terminate.
  379. //
  380. // bOffline [IN]
  381. // TRUE = called from the offline thread.
  382. //
  383. // pdwResourceState [OUT]
  384. // State of the resource. Optional.
  385. //
  386. // pfnLogEvent [IN]
  387. // Pointer to a routine that handles the reporting of events from
  388. // the resource DLL.
  389. //
  390. // hResourceHandle [IN]
  391. // Handle for logging.
  392. //
  393. // Return Value:
  394. // ERROR_SUCCESS
  395. // The function completed successfully.
  396. //
  397. // Win32 error code
  398. // The function failed.
  399. //
  400. //--
  401. /////////////////////////////////////////////////////////////////////////////
  402. DWORD
  403. WINAPI
  404. ResUtilTerminateServiceProcessFromResDll(
  405. IN DWORD dwServicePid,
  406. IN BOOL bOffline,
  407. OUT PDWORD pdwResourceState,
  408. IN PLOG_EVENT_ROUTINE pfnLogEvent,
  409. IN RESOURCE_HANDLE hResourceHandle
  410. )
  411. {
  412. DWORD nStatus = ERROR_SUCCESS;
  413. HANDLE hSvcProcess = NULL;
  414. BOOLEAN bWasEnabled;
  415. DWORD dwResourceState = ClusterResourceFailed;
  416. (pfnLogEvent)(
  417. hResourceHandle,
  418. LOG_INFORMATION,
  419. L"ResUtilTerminateServiceProcessFromResDll: Process with id=%1!u! might be terminated...\n",
  420. dwServicePid
  421. );
  422. //
  423. // Adjust the privilege to allow debug. This is to allow termination
  424. // of a service process which runs in a local system account from a
  425. // different service process which runs in a domain user account.
  426. //
  427. nStatus = ClRtlEnableThreadPrivilege(
  428. SE_DEBUG_PRIVILEGE,
  429. &bWasEnabled
  430. );
  431. if ( nStatus != ERROR_SUCCESS )
  432. {
  433. (pfnLogEvent)(
  434. hResourceHandle,
  435. LOG_ERROR,
  436. L"ResUtilTerminateServiceProcessFromResDll: Unable to set debug privilege for process with id=%1!u!, status=%2!u!...\n",
  437. dwServicePid,
  438. nStatus
  439. );
  440. goto Cleanup;
  441. } // if: error enabling thread privilege
  442. //
  443. // Open the process so we can terminate it.
  444. //
  445. hSvcProcess = OpenProcess(
  446. PROCESS_TERMINATE,
  447. FALSE,
  448. dwServicePid
  449. );
  450. if ( hSvcProcess == NULL )
  451. {
  452. //
  453. // Did this happen because the process terminated
  454. // too quickly after we sent out one control request ?
  455. //
  456. nStatus = GetLastError();
  457. (pfnLogEvent)(
  458. hResourceHandle,
  459. LOG_INFORMATION,
  460. L"ResUtilTerminateServiceProcessFromResDll: Unable to open pid=%1!u! for termination, status=%2!u!...\n",
  461. dwServicePid,
  462. nStatus
  463. );
  464. } // if: error opening the process
  465. else
  466. {
  467. if ( ! bOffline )
  468. {
  469. (pfnLogEvent)(
  470. hResourceHandle,
  471. LOG_INFORMATION,
  472. L"ResUtilTerminateServiceProcessFromResDll: Pid=%1!u! will be terminated by brute force...\n",
  473. dwServicePid
  474. );
  475. } // if: called from Terminate
  476. else
  477. {
  478. //
  479. // Wait 3 seconds for the process to shutdown gracefully.
  480. //
  481. if ( WaitForSingleObject( hSvcProcess, 3000 )
  482. == WAIT_OBJECT_0 )
  483. {
  484. (pfnLogEvent)(
  485. hResourceHandle,
  486. LOG_INFORMATION,
  487. L"ResUtilTerminateServiceProcessFromResDll: Process with id=%1!u! shutdown gracefully...\n",
  488. dwServicePid
  489. );
  490. dwResourceState = ClusterResourceOffline;
  491. nStatus = ERROR_SUCCESS;
  492. goto RestoreAndCleanup;
  493. } // if: process exited on its own
  494. } // else: called from Offline
  495. if ( ! TerminateProcess( hSvcProcess, 0 ) )
  496. {
  497. nStatus = GetLastError();
  498. (pfnLogEvent)(
  499. hResourceHandle,
  500. LOG_ERROR,
  501. L"ResUtilTerminateServiceProcessFromResDll: Unable to terminate process with id=%1!u!, status=%2!u!...\n",
  502. dwServicePid,
  503. nStatus
  504. );
  505. } // if: error terminating the process
  506. else
  507. {
  508. (pfnLogEvent)(
  509. hResourceHandle,
  510. LOG_INFORMATION,
  511. L"ResUtilTerminateServiceProcessFromResDll: Process with id=%1!u! was terminated...\n",
  512. dwServicePid
  513. );
  514. dwResourceState = ClusterResourceOffline;
  515. } // else: process terminated successfully
  516. } // else: process opened successfully
  517. RestoreAndCleanup:
  518. ClRtlRestoreThreadPrivilege(
  519. SE_DEBUG_PRIVILEGE,
  520. bWasEnabled
  521. );
  522. Cleanup:
  523. if ( hSvcProcess != NULL )
  524. {
  525. CloseHandle( hSvcProcess );
  526. } // if: process was opened successfully
  527. if ( pdwResourceState != NULL )
  528. {
  529. *pdwResourceState = dwResourceState;
  530. } // if: caller wants the resource state
  531. (pfnLogEvent)(
  532. hResourceHandle,
  533. LOG_INFORMATION,
  534. L"ResUtilTerminateServiceProcessFromResDll: Process id=%1!u!, status=%2!u!, state=%3!u!.\n",
  535. dwServicePid,
  536. nStatus,
  537. dwResourceState
  538. );
  539. return nStatus;
  540. } //*** ResUtilTerminateServiceProcessFromResDll()
  541. LPWSTR
  542. WINAPI
  543. ResUtilDupString(
  544. IN LPCWSTR pszInString
  545. )
  546. /*++
  547. Routine Description:
  548. Duplicates a string.
  549. Arguments:
  550. pszInString - Supplies the string to be duplicated.
  551. Return Value:
  552. A pointer to a buffer containing the duplicate if successful.
  553. NULL if unsuccessful. Call GetLastError() to get more details.
  554. --*/
  555. {
  556. PWSTR newValue;
  557. DWORD valueSize;
  558. //
  559. // Get the size of the parameter so we know how much to allocate.
  560. //
  561. valueSize = (lstrlenW( pszInString ) + 1) * sizeof(WCHAR);
  562. //
  563. // Allocate a buffer to copy the string into.
  564. //
  565. newValue = LocalAlloc( LMEM_FIXED, valueSize );
  566. if ( newValue == NULL ) {
  567. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  568. return(NULL);
  569. }
  570. //
  571. // Copy Value to the newValue buffer.
  572. //
  573. lstrcpyW( newValue, pszInString );
  574. return(newValue);
  575. } // ResUtilDupString
  576. DWORD
  577. WINAPI
  578. ResUtilGetBinaryValue(
  579. IN HKEY hkeyClusterKey,
  580. IN LPCWSTR pszValueName,
  581. OUT LPBYTE * ppbOutValue,
  582. OUT LPDWORD pcbOutValueSize
  583. )
  584. /*++
  585. Routine Description:
  586. Queries a REG_BINARY or REG_MULTI_SZ value out of the cluster
  587. database and allocates the necessary storage for it.
  588. Arguments:
  589. hkeyClusterKey - Supplies the cluster key where the value is stored
  590. pszValueName - Supplies the name of the value.
  591. ppbOutValue - Supplies the address of a pointer in which to return the value.
  592. pcbOutValueSize - Supplies the address of a DWORD in which to return the
  593. size of the value.
  594. Return Value:
  595. ERROR_SUCCESS - The value was read successfully.
  596. ERROR_NOT_ENOUGH_MEMORY - Error allocating memory for the value.
  597. Win32 error code - The operation failed.
  598. --*/
  599. {
  600. LPBYTE value;
  601. DWORD valueSize;
  602. DWORD valueType;
  603. DWORD status;
  604. //
  605. // Initialize the output parameters.
  606. //
  607. *ppbOutValue = NULL;
  608. *pcbOutValueSize = 0;
  609. //
  610. // Get the size of the value so we know how much to allocate.
  611. //
  612. valueSize = 0;
  613. status = ClusterRegQueryValue( hkeyClusterKey,
  614. pszValueName,
  615. &valueType,
  616. NULL,
  617. &valueSize );
  618. if ( (status != ERROR_SUCCESS) &&
  619. (status != ERROR_MORE_DATA) ) {
  620. return(status);
  621. }
  622. //
  623. // Allocate a buffer to read the value into.
  624. //
  625. value = LocalAlloc( LMEM_FIXED, valueSize );
  626. if ( value == NULL ) {
  627. return(ERROR_NOT_ENOUGH_MEMORY);
  628. }
  629. //
  630. // Read the value from the cluster database.
  631. //
  632. status = ClusterRegQueryValue( hkeyClusterKey,
  633. pszValueName,
  634. &valueType,
  635. (LPBYTE)value,
  636. &valueSize );
  637. if ( status != ERROR_SUCCESS ) {
  638. LocalFree( value );
  639. } else {
  640. *ppbOutValue = value;
  641. *pcbOutValueSize = valueSize;
  642. }
  643. return(status);
  644. } // ResUtilGetBinaryValue
  645. PWSTR
  646. WINAPI
  647. ResUtilGetSzValue(
  648. IN HKEY hkeyClusterKey,
  649. IN LPCWSTR pszValueName
  650. )
  651. /*++
  652. Routine Description:
  653. Queries a REG_SZ or REG_EXPAND_SZ value out of the cluster database
  654. and allocates the necessary storage for it.
  655. Arguments:
  656. hkeyClusterKey - Supplies the cluster key where the value is stored
  657. pszValueName - Supplies the name of the value.
  658. Return Value:
  659. A pointer to a buffer containing the value if successful.
  660. NULL if unsuccessful. Call GetLastError() to get more details.
  661. --*/
  662. {
  663. PWSTR value;
  664. DWORD valueSize;
  665. DWORD valueType;
  666. DWORD status;
  667. //
  668. // Get the size of the value so we know how much to allocate.
  669. //
  670. valueSize = 0;
  671. status = ClusterRegQueryValue( hkeyClusterKey,
  672. pszValueName,
  673. &valueType,
  674. NULL,
  675. &valueSize );
  676. if ( (status != ERROR_SUCCESS) &&
  677. (status != ERROR_MORE_DATA) ) {
  678. SetLastError( status );
  679. return(NULL);
  680. }
  681. //
  682. // Add on the size of the null terminator.
  683. //
  684. valueSize += sizeof(UNICODE_NULL);
  685. //
  686. // Allocate a buffer to read the string into.
  687. //
  688. value = LocalAlloc( LMEM_FIXED, valueSize );
  689. if ( value == NULL ) {
  690. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  691. return(NULL);
  692. }
  693. //
  694. // Read the value from the cluster database.
  695. //
  696. status = ClusterRegQueryValue( hkeyClusterKey,
  697. pszValueName,
  698. &valueType,
  699. (LPBYTE)value,
  700. &valueSize );
  701. if ( status != ERROR_SUCCESS ) {
  702. LocalFree( value );
  703. value = NULL;
  704. } else if ( (valueType != REG_SZ) &&
  705. (valueType != REG_EXPAND_SZ) &&
  706. (valueType != REG_MULTI_SZ) ) {
  707. status = ERROR_INVALID_PARAMETER;
  708. LocalFree( value );
  709. value = NULL;
  710. }
  711. return(value);
  712. } // ResUtilGetSzValue
  713. PWSTR
  714. WINAPI
  715. ResUtilGetExpandSzValue(
  716. IN HKEY hkeyClusterKey,
  717. IN LPCWSTR pszValueName,
  718. IN BOOL bExpand
  719. )
  720. /*++
  721. Routine Description:
  722. Queries a REG_EXPAND_SZ value out of the cluster database and allocates
  723. the necessary storage for it, optionally expanding it.
  724. Arguments:
  725. hkeyClusterKey - Supplies the cluster key where the value is stored
  726. pszValueName - Supplies the name of the value.
  727. bExpand - TRUE = return the expanded string.
  728. Return Value:
  729. A pointer to a buffer containing the value if successful.
  730. NULL if unsuccessful. Call GetLastError() to get more details.
  731. --*/
  732. {
  733. PWSTR value;
  734. PWSTR valueExpanded = NULL;
  735. DWORD valueSize;
  736. DWORD valueType;
  737. DWORD valueExpandedSize;
  738. DWORD valueExpandedSizeReturned;
  739. DWORD status;
  740. //
  741. // Get the size of the value so we know how much to allocate.
  742. //
  743. valueSize = 0;
  744. status = ClusterRegQueryValue( hkeyClusterKey,
  745. pszValueName,
  746. &valueType,
  747. NULL,
  748. &valueSize );
  749. if ( (status != ERROR_SUCCESS) &&
  750. (status != ERROR_MORE_DATA) ) {
  751. SetLastError( status );
  752. return(NULL);
  753. }
  754. //
  755. // Add on the size of the null terminator.
  756. //
  757. valueSize += sizeof(UNICODE_NULL);
  758. //
  759. // Allocate a buffer to read the string into.
  760. //
  761. value = LocalAlloc( LMEM_FIXED, valueSize );
  762. if ( value == NULL ) {
  763. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  764. return(NULL);
  765. }
  766. //
  767. // Read the value from the cluster database.
  768. //
  769. status = ClusterRegQueryValue( hkeyClusterKey,
  770. pszValueName,
  771. &valueType,
  772. (LPBYTE)value,
  773. &valueSize );
  774. if ( status != ERROR_SUCCESS ) {
  775. LocalFree( value );
  776. value = NULL;
  777. } else if ( ( valueType != REG_EXPAND_SZ ) &&
  778. ( valueType != REG_SZ ) ) {
  779. status = ERROR_INVALID_PARAMETER;
  780. LocalFree( value );
  781. value = NULL;
  782. } else if ( bExpand ) {
  783. //
  784. // Expand the environment variable strings in the
  785. // value that was just read.
  786. //
  787. valueExpandedSize = valueSize;
  788. do
  789. {
  790. //
  791. // Allocate the buffer for the expansion string. This will
  792. // get double each time we are told it is too small.
  793. //
  794. valueExpanded = LocalAlloc( LMEM_FIXED, valueExpandedSize );
  795. if ( valueExpanded == NULL ) {
  796. status = ERROR_NOT_ENOUGH_MEMORY;
  797. break;
  798. } else {
  799. //
  800. // Expand the environment variables in the value.
  801. // If the buffer isn't big enough, we will loop up to
  802. // the top of the loop and allocate a bigger buffer.
  803. //
  804. valueExpandedSizeReturned = ExpandEnvironmentStrings(
  805. value,
  806. valueExpanded,
  807. valueExpandedSize );
  808. if ( valueExpandedSizeReturned == 0 ) {
  809. status = GetLastError();
  810. break;
  811. } else if ( valueExpandedSizeReturned > valueExpandedSize ) {
  812. valueExpandedSize = valueExpandedSize * 2;
  813. } else {
  814. status = ERROR_SUCCESS;
  815. break;
  816. }
  817. }
  818. } while ( TRUE );
  819. //
  820. // If any errors occurred, cleanup.
  821. // Otherwise, return expanded string.
  822. //
  823. if ( status != ERROR_SUCCESS ) {
  824. LocalFree( valueExpanded );
  825. LocalFree( value );
  826. value = NULL;
  827. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  828. } else {
  829. LocalFree( value );
  830. value = valueExpanded;
  831. }
  832. }
  833. return(value);
  834. } // ResUtilGetExpandSzValue
  835. DWORD
  836. WINAPI
  837. ResUtilGetDwordValue(
  838. IN HKEY hkeyClusterKey,
  839. IN LPCWSTR pszValueName,
  840. OUT LPDWORD pdwOutValue,
  841. IN DWORD dwDefaultValue
  842. )
  843. /*++
  844. Routine Description:
  845. Queries a REG_DWORD value out of the cluster database.
  846. Arguments:
  847. hkeyClusterKey - Supplies the cluster key where the value is stored
  848. pszValueName - Supplies the name of the value.
  849. pdwOutValue - Supplies the address of a DWORD in which to return the value.
  850. dwDefaultValue - Value to return if the parameter is not found.
  851. Return Value:
  852. ERROR_SUCCESS - The value was read successfully.
  853. Win32 error code - The operation failed.
  854. --*/
  855. {
  856. DWORD value;
  857. DWORD valueSize;
  858. DWORD valueType;
  859. DWORD status;
  860. //
  861. // Initialize the output value.
  862. //
  863. *pdwOutValue = 0;
  864. //
  865. // Read the value from the cluster database.
  866. //
  867. valueSize = sizeof(DWORD);
  868. status = ClusterRegQueryValue( hkeyClusterKey,
  869. pszValueName,
  870. &valueType,
  871. (LPBYTE)&value,
  872. &valueSize );
  873. if ( status == ERROR_SUCCESS ) {
  874. if ( valueType != REG_DWORD ) {
  875. status = ERROR_INVALID_PARAMETER;
  876. } else {
  877. *pdwOutValue = value;
  878. }
  879. } else if ( status == ERROR_FILE_NOT_FOUND ) {
  880. *pdwOutValue = dwDefaultValue;
  881. status = ERROR_SUCCESS;
  882. }
  883. return(status);
  884. } // ResUtilGetDwordValue
  885. DWORD
  886. WINAPI
  887. ResUtilSetBinaryValue(
  888. IN HKEY hkeyClusterKey,
  889. IN LPCWSTR pszValueName,
  890. IN const LPBYTE pbNewValue,
  891. IN DWORD cbNewValueSize,
  892. IN OUT LPBYTE * ppbOutValue,
  893. IN OUT LPDWORD pcbOutValueSize
  894. )
  895. /*++
  896. Routine Description:
  897. Sets a REG_BINARY value in a pointer, deallocating a previous value
  898. if necessary, and sets the value in the cluster database.
  899. Arguments:
  900. hkeyClusterKey - Supplies the cluster key where the value is stored.
  901. pszValueName - Supplies the name of the value.
  902. pbNewValue - Supplies the new binary value.
  903. cbNewValueSize - Supplies the size of the new value.
  904. ppbOutValue - Supplies pointer to the binary pointer in which to set
  905. the value.
  906. pcbOutValueSize - Supplies a pointer to a size DWORD in which to set
  907. the size of the value.
  908. Return Value:
  909. ERROR_SUCCESS - The operation completed successfully.
  910. ERROR_NOT_ENOUGH_MEMORY - An error occurred attempting to allocate memory.
  911. Win32 error code - The operation failed.
  912. --*/
  913. {
  914. DWORD status;
  915. LPBYTE allocedValue = NULL;
  916. if ( ppbOutValue != NULL )
  917. {
  918. //
  919. // Allocate memory for the new value.
  920. //
  921. allocedValue = LocalAlloc( LMEM_FIXED, cbNewValueSize );
  922. if ( allocedValue == NULL ) {
  923. return(ERROR_NOT_ENOUGH_MEMORY);
  924. }
  925. }
  926. //
  927. // Set the value in the cluster database.
  928. //
  929. // _ASSERTE( hkeyClusterKey != NULL );
  930. // _ASSERTE( pszValueName != NULL );
  931. status = ClusterRegSetValue( hkeyClusterKey,
  932. pszValueName,
  933. REG_BINARY,
  934. pbNewValue,
  935. cbNewValueSize );
  936. if ( status != ERROR_SUCCESS ) {
  937. LocalFree( allocedValue );
  938. return(status);
  939. }
  940. if ( ppbOutValue != NULL )
  941. {
  942. //
  943. // Copy the new value to the output buffer.
  944. //
  945. CopyMemory( allocedValue, pbNewValue, cbNewValueSize );
  946. // Set the new value in the output pointer.
  947. if ( *ppbOutValue != NULL ) {
  948. LocalFree( *ppbOutValue );
  949. }
  950. *ppbOutValue = allocedValue;
  951. *pcbOutValueSize = cbNewValueSize;
  952. }
  953. return(ERROR_SUCCESS);
  954. } // ResUtilSetBinaryValue
  955. DWORD
  956. WINAPI
  957. ResUtilSetSzValue(
  958. IN HKEY hkeyClusterKey,
  959. IN LPCWSTR pszValueName,
  960. IN LPCWSTR pszNewValue,
  961. IN OUT LPWSTR * ppszOutValue
  962. )
  963. /*++
  964. Routine Description:
  965. Sets a REG_SZ value in a pointer, deallocating a previous value
  966. if necessary, and sets the value in the cluster database.
  967. Arguments:
  968. hkeyClusterKey - Supplies the cluster key where the value is stored.
  969. pszValueName - Supplies the name of the value.
  970. pszNewValue - Supplies the new string value.
  971. ppszOutValue - Supplies pointer to the string pointer in which to set
  972. the value.
  973. Return Value:
  974. ERROR_SUCCESS - The operation completed successfully.
  975. ERROR_NOT_ENOUGH_MEMORY - An error occurred attempting to allocate memory.
  976. Win32 error code - The operation failed.
  977. --*/
  978. {
  979. DWORD status;
  980. DWORD dataSize;
  981. PWSTR allocedValue = NULL;
  982. dataSize = (lstrlenW( pszNewValue ) + 1) * sizeof(WCHAR);
  983. if ( ppszOutValue != NULL )
  984. {
  985. //
  986. // Allocate memory for the new value string.
  987. //
  988. allocedValue = LocalAlloc( LMEM_FIXED, dataSize );
  989. if ( allocedValue == NULL ) {
  990. return(ERROR_NOT_ENOUGH_MEMORY);
  991. }
  992. }
  993. //
  994. // Set the value in the cluster database.
  995. //
  996. // _ASSERTE( hkeyClusterKey != NULL );
  997. // _ASSERTE( pszValueName != NULL );
  998. status = ClusterRegSetValue( hkeyClusterKey,
  999. pszValueName,
  1000. REG_SZ,
  1001. (CONST BYTE*)pszNewValue,
  1002. dataSize );
  1003. if ( status != ERROR_SUCCESS ) {
  1004. LocalFree( allocedValue );
  1005. return(status);
  1006. }
  1007. if ( ppszOutValue != NULL )
  1008. {
  1009. //
  1010. // Copy the new value to the output buffer.
  1011. //
  1012. lstrcpyW( allocedValue, pszNewValue );
  1013. // Set the new value in the output string pointer.
  1014. if ( *ppszOutValue != NULL ) {
  1015. LocalFree( *ppszOutValue );
  1016. }
  1017. *ppszOutValue = allocedValue;
  1018. }
  1019. return(ERROR_SUCCESS);
  1020. } // ResUtilSetSzValue
  1021. DWORD
  1022. WINAPI
  1023. ResUtilSetExpandSzValue(
  1024. IN HKEY hkeyClusterKey,
  1025. IN LPCWSTR pszValueName,
  1026. IN LPCWSTR pszNewValue,
  1027. IN OUT LPWSTR * ppszOutValue
  1028. )
  1029. /*++
  1030. Routine Description:
  1031. Sets a REG_EXPAND_SZ value in a pointer, deallocating a previous value
  1032. if necessary, and sets the value in the cluster database.
  1033. Arguments:
  1034. hkeyClusterKey - Supplies the cluster key where the value is stored.
  1035. pszValueName - Supplies the name of the value.
  1036. pszNewValue - Supplies the new string value.
  1037. ppszOutValue - Supplies pointer to the string pointer in which to set
  1038. the value.
  1039. Return Value:
  1040. ERROR_SUCCESS - The operation completed successfully.
  1041. ERROR_NOT_ENOUGH_MEMORY - An error occurred attempting to allocate memory.
  1042. Win32 error code - The operation failed.
  1043. --*/
  1044. {
  1045. DWORD status;
  1046. DWORD dataSize;
  1047. PWSTR allocedValue = NULL;
  1048. dataSize = (lstrlenW( pszNewValue ) + 1) * sizeof(WCHAR);
  1049. if ( ppszOutValue != NULL ) {
  1050. //
  1051. // Allocate memory for the new value string.
  1052. //
  1053. allocedValue = LocalAlloc( LMEM_FIXED, dataSize );
  1054. if ( allocedValue == NULL ) {
  1055. return(ERROR_NOT_ENOUGH_MEMORY);
  1056. }
  1057. }
  1058. //
  1059. // Set the value in the cluster database.
  1060. //
  1061. // _ASSERTE( hkeyClusterKey != NULL );
  1062. // _ASSERTE( pszValueName != NULL );
  1063. status = ClusterRegSetValue( hkeyClusterKey,
  1064. pszValueName,
  1065. REG_EXPAND_SZ,
  1066. (CONST BYTE*)pszNewValue,
  1067. dataSize );
  1068. if ( status != ERROR_SUCCESS ) {
  1069. LocalFree( allocedValue );
  1070. return(status);
  1071. }
  1072. if ( ppszOutValue != NULL ) {
  1073. //
  1074. // Copy the new value to the output buffer.
  1075. //
  1076. lstrcpyW( allocedValue, pszNewValue );
  1077. // Set the new value in the output string pointer.
  1078. if ( *ppszOutValue != NULL ) {
  1079. LocalFree( *ppszOutValue );
  1080. }
  1081. *ppszOutValue = allocedValue;
  1082. }
  1083. return(ERROR_SUCCESS);
  1084. } // ResUtilSetSzValue
  1085. DWORD
  1086. WINAPI
  1087. ResUtilSetMultiSzValue(
  1088. IN HKEY hkeyClusterKey,
  1089. IN LPCWSTR pszValueName,
  1090. IN LPCWSTR pszNewValue,
  1091. IN DWORD cbNewValueSize,
  1092. IN OUT LPWSTR * ppszOutValue,
  1093. IN OUT LPDWORD pcbOutValueSize
  1094. )
  1095. /*++
  1096. Routine Description:
  1097. Sets a REG_MULTI_SZ value in a pointer, deallocating a previous value
  1098. if necessary, and sets the value in the cluster database.
  1099. Arguments:
  1100. hkeyClusterKey - Supplies the cluster key where the ValueName is stored.
  1101. pszValueName - Supplies the name of the value.
  1102. pszNewValue - Supplies the new MULTI_SZ value.
  1103. cbNewValueSize - Supplies the size of the new value.
  1104. ppszOutValue - Supplies a pointer to the string pointer in which to set
  1105. the value.
  1106. pcbOutValueSize - Supplies a pointer to a size DWORD in which to set
  1107. the size of the value.
  1108. Return Value:
  1109. ERROR_SUCCESS - The operation completed successfully.
  1110. ERROR_NOT_ENOUGH_MEMORY - An error occurred attempting to allocate memory.
  1111. Win32 error code - The operation failed.
  1112. --*/
  1113. {
  1114. DWORD status;
  1115. LPWSTR allocedValue = NULL;
  1116. if ( ppszOutValue != NULL )
  1117. {
  1118. //
  1119. // Allocate memory for the new value.
  1120. //
  1121. allocedValue = LocalAlloc( LMEM_FIXED, cbNewValueSize );
  1122. if ( allocedValue == NULL ) {
  1123. return(ERROR_NOT_ENOUGH_MEMORY);
  1124. }
  1125. }
  1126. //
  1127. // Set the value in the cluster database.
  1128. //
  1129. // _ASSERTE( hkeyClusterKey != NULL );
  1130. // _ASSERTE( pszValueName != NULL );
  1131. status = ClusterRegSetValue( hkeyClusterKey,
  1132. pszValueName,
  1133. REG_MULTI_SZ,
  1134. (CONST BYTE*)pszNewValue,
  1135. cbNewValueSize );
  1136. if ( status != ERROR_SUCCESS ) {
  1137. LocalFree(allocedValue);
  1138. return(status);
  1139. }
  1140. if ( ppszOutValue != NULL )
  1141. {
  1142. //
  1143. // Copy the new value to the output buffer.
  1144. //
  1145. CopyMemory( allocedValue, pszNewValue, cbNewValueSize );
  1146. // Set the new value in the output pointer.
  1147. if ( *ppszOutValue != NULL ) {
  1148. LocalFree( *ppszOutValue );
  1149. }
  1150. *ppszOutValue = allocedValue;
  1151. *pcbOutValueSize = cbNewValueSize;
  1152. }
  1153. return(ERROR_SUCCESS);
  1154. } // ResUtilSetMultiSzValue
  1155. DWORD
  1156. WINAPI
  1157. ResUtilSetDwordValue(
  1158. IN HKEY hkeyClusterKey,
  1159. IN LPCWSTR pszValueName,
  1160. IN DWORD dwNewValue,
  1161. IN OUT LPDWORD pdwOutValue
  1162. )
  1163. /*++
  1164. Routine Description:
  1165. Sets a REG_DWORD value in a pointer and sets the value in the
  1166. cluster database.
  1167. Arguments:
  1168. hkeyClusterKey - Supplies the cluster key where the property is stored.
  1169. pszValueName - Supplies the name of the value.
  1170. dwNewValue - Supplies the new DWORD value.
  1171. pdwOutValue - Supplies pointer to the DWORD pointer in which to set
  1172. the value.
  1173. Return Value:
  1174. ERROR_SUCCESS - The operation completed successfully.
  1175. Win32 error code - The operation failed.
  1176. --*/
  1177. {
  1178. DWORD status;
  1179. //
  1180. // Set the value in the cluster database.
  1181. //
  1182. // _ASSERTE( hkeyClusterKey != NULL );
  1183. // _ASSERTE( pszValueName != NULL );
  1184. status = ClusterRegSetValue( hkeyClusterKey,
  1185. pszValueName,
  1186. REG_DWORD,
  1187. (CONST BYTE*)&dwNewValue,
  1188. sizeof(DWORD) );
  1189. if ( status != ERROR_SUCCESS ) {
  1190. return(status);
  1191. }
  1192. if ( pdwOutValue != NULL )
  1193. {
  1194. //
  1195. // Copy the new value to the output buffer.
  1196. //
  1197. *pdwOutValue = dwNewValue;
  1198. }
  1199. return(ERROR_SUCCESS);
  1200. } // ResUtilSetDwordValue
  1201. DWORD
  1202. WINAPI
  1203. ResUtilGetBinaryProperty(
  1204. OUT LPBYTE * ppbOutValue,
  1205. OUT LPDWORD pcbOutValueSize,
  1206. IN const PCLUSPROP_BINARY pValueStruct,
  1207. IN const LPBYTE pbOldValue,
  1208. IN DWORD cbOldValueSize,
  1209. OUT LPBYTE * ppPropertyList,
  1210. OUT LPDWORD pcbPropertyListSize
  1211. )
  1212. /*++
  1213. Routine Description:
  1214. Gets a binary property from a property list and advances the pointers.
  1215. Arguments:
  1216. ppbOutValue - Supplies the address of a pointer in which to return a
  1217. pointer to the binary value in the property list.
  1218. pcbOutValueSize - Supplies the address of the output value size.
  1219. pValueStruct - Supplies the binary value from the property list.
  1220. pbOldValue - Supplies the previous value for this property.
  1221. cbOldValueSize - Supplies the previous value's size.
  1222. ppPropertyList - Supplies the address of the pointer to the property list
  1223. buffer which will be advanced to the beginning of the next property.
  1224. pcbPropertyListSize - Supplies a pointer to the buffer size which will be
  1225. decremented to account for this property.
  1226. Return Value:
  1227. ERROR_SUCCESS - The operation completed successfully.
  1228. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1229. Win32 error code - The operation failed.
  1230. --*/
  1231. {
  1232. BOOL propChanged = FALSE;
  1233. DWORD arrayIndex;
  1234. DWORD dataSize;
  1235. //
  1236. // Make sure the buffer is big enough and
  1237. // the value is formatted correctly.
  1238. //
  1239. dataSize = sizeof(*pValueStruct) + ALIGN_CLUSPROP( pValueStruct->cbLength );
  1240. if ( (*pcbPropertyListSize < dataSize) ||
  1241. (pValueStruct->Syntax.wFormat != CLUSPROP_FORMAT_BINARY) ) {
  1242. return(ERROR_INVALID_PARAMETER);
  1243. }
  1244. //
  1245. // If the value changed, point to the new value.
  1246. //
  1247. if ( (pbOldValue == NULL) ||
  1248. (cbOldValueSize != pValueStruct->cbLength) ) {
  1249. propChanged = TRUE;
  1250. } else {
  1251. for ( arrayIndex = 0 ; arrayIndex < cbOldValueSize ; arrayIndex++ ) {
  1252. if ( pValueStruct->rgb[arrayIndex] != pbOldValue[arrayIndex] ) {
  1253. propChanged = TRUE;
  1254. break;
  1255. }
  1256. }
  1257. }
  1258. if ( propChanged ) {
  1259. *ppbOutValue = pValueStruct->rgb;
  1260. *pcbOutValueSize = pValueStruct->cbLength;
  1261. }
  1262. //
  1263. // Decrement remaining buffer size and move to the next property.
  1264. //
  1265. *pcbPropertyListSize -= dataSize;
  1266. *ppPropertyList += dataSize;
  1267. return(ERROR_SUCCESS);
  1268. } // ResUtilGetBinaryProperty
  1269. DWORD
  1270. WINAPI
  1271. ResUtilGetSzProperty(
  1272. OUT LPWSTR * ppszOutValue,
  1273. IN const PCLUSPROP_SZ pValueStruct,
  1274. IN LPCWSTR pszOldValue,
  1275. OUT LPBYTE * ppPropertyList,
  1276. OUT LPDWORD pcbPropertyListSize
  1277. )
  1278. /*++
  1279. Routine Description:
  1280. Gets a string property from a property list and advances the pointers.
  1281. Arguments:
  1282. ppszOutValue - Supplies the address of a pointer in which to return a
  1283. pointer to the string in the property list.
  1284. pValueStruct - Supplies the string value from the property list.
  1285. pszOldValue - Supplies the previous value for this property.
  1286. ppPropertyList - Supplies the address of the pointer to the property list
  1287. buffer which will be advanced to the beginning of the next property.
  1288. pcbPropertyListSize - Supplies a pointer to the buffer size which will be
  1289. decremented to account for this property.
  1290. Return Value:
  1291. ERROR_SUCCESS - The operation completed successfully.
  1292. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1293. Win32 error code - The operation failed.
  1294. --*/
  1295. {
  1296. DWORD dataSize;
  1297. //
  1298. // Make sure the buffer is big enough and
  1299. // the value is formatted correctly.
  1300. //
  1301. dataSize = sizeof(*pValueStruct) + ALIGN_CLUSPROP( pValueStruct->cbLength );
  1302. if ( (*pcbPropertyListSize < dataSize) ||
  1303. (pValueStruct->Syntax.wFormat != CLUSPROP_FORMAT_SZ) ||
  1304. (pValueStruct->Syntax.wFormat != CLUSPROP_FORMAT_EXPAND_SZ) ) {
  1305. return(ERROR_INVALID_PARAMETER);
  1306. }
  1307. //
  1308. // If the value changed, point to the new value.
  1309. // Do this even if only the case of the value changed.
  1310. //
  1311. if ( (pszOldValue == NULL) ||
  1312. (lstrcmpW( pValueStruct->sz, pszOldValue ) != 0) ) {
  1313. *ppszOutValue = pValueStruct->sz;
  1314. }
  1315. //
  1316. // Decrement remaining buffer size and move to the next property.
  1317. //
  1318. *pcbPropertyListSize -= dataSize;
  1319. *ppPropertyList += dataSize;
  1320. return(ERROR_SUCCESS);
  1321. } // ResUtilGetSzProperty
  1322. DWORD
  1323. WINAPI
  1324. ResUtilGetMultiSzProperty(
  1325. OUT LPWSTR * ppszOutValue,
  1326. OUT LPDWORD pcbOutValueSize,
  1327. IN const PCLUSPROP_SZ pValueStruct,
  1328. IN LPCWSTR pszOldValue,
  1329. IN DWORD cbOldValueSize,
  1330. OUT LPBYTE * ppPropertyList,
  1331. OUT LPDWORD pcbPropertyListSize
  1332. )
  1333. /*++
  1334. Routine Description:
  1335. Gets a binary property from a property list and advances the pointers.
  1336. Arguments:
  1337. ppszOutValue - Supplies the address of a pointer in which to return a
  1338. pointer to the binary value in the property list.
  1339. pcbOutValueSize - Supplies the address of the output value size.
  1340. pValueStruct - Supplies the string value from the property list.
  1341. pszOldValue - Supplies the previous value for this property.
  1342. cbOldValueSize - Supplies the previous value's size.
  1343. ppPropertyList - Supplies the address of the pointer to the property list
  1344. buffer which will be advanced to the beginning of the next property.
  1345. pcbPropertyListSize - Supplies a pointer to the buffer size which will be
  1346. decremented to account for this property.
  1347. Return Value:
  1348. ERROR_SUCCESS - The operation completed successfully.
  1349. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1350. Win32 error code - The operation failed.
  1351. --*/
  1352. {
  1353. BOOL propChanged = FALSE;
  1354. DWORD dataSize;
  1355. //
  1356. // Make sure the buffer is big enough and
  1357. // the value is formatted correctly.
  1358. //
  1359. dataSize = sizeof(*pValueStruct) + ALIGN_CLUSPROP( pValueStruct->cbLength );
  1360. if ( (*pcbPropertyListSize < dataSize) ||
  1361. (pValueStruct->Syntax.wFormat != CLUSPROP_FORMAT_MULTI_SZ) ) {
  1362. return(ERROR_INVALID_PARAMETER);
  1363. }
  1364. //
  1365. // If the value changed, point to the new value.
  1366. //
  1367. if ( (pszOldValue == NULL) ||
  1368. (cbOldValueSize != pValueStruct->cbLength) ) {
  1369. propChanged = TRUE;
  1370. } else if ( memcmp( pValueStruct->sz, pszOldValue, cbOldValueSize ) != 0 ) {
  1371. propChanged = TRUE;
  1372. }
  1373. if ( propChanged ) {
  1374. *ppszOutValue = pValueStruct->sz;
  1375. *pcbOutValueSize = pValueStruct->cbLength;
  1376. }
  1377. //
  1378. // Decrement remaining buffer size and move to the next property.
  1379. //
  1380. *pcbPropertyListSize -= dataSize;
  1381. *ppPropertyList += dataSize;
  1382. return(ERROR_SUCCESS);
  1383. } // ResUtilGetMultiSzProperty
  1384. DWORD
  1385. WINAPI
  1386. ResUtilGetDwordProperty(
  1387. OUT LPDWORD pdwOutValue,
  1388. IN const PCLUSPROP_DWORD pValueStruct,
  1389. IN DWORD dwOldValue,
  1390. IN DWORD dwMinimum,
  1391. IN DWORD dwMaximum,
  1392. OUT LPBYTE * ppPropertyList,
  1393. OUT LPDWORD pcbPropertyListSize
  1394. )
  1395. /*++
  1396. Routine Description:
  1397. Gets a DWORD property from a property list and advances the pointers.
  1398. Arguments:
  1399. pdwOutValue - Supplies the address of a pointer in which to return a
  1400. pointer to the string in the property list.
  1401. pValueStruct - Supplies the DWORD value from the property list.
  1402. dwOldValue - Supplies the previous value for thie property.
  1403. dwMinimum - Minimum value the value can have. If both Minimum and Maximum
  1404. are 0, no range check will be done.
  1405. dwMaximum - Maximum value the value can have.
  1406. ppPropertyList - Supplies the address of the pointer to the property list
  1407. buffer which will be advanced to the beginning of the next property.
  1408. pcbPropertyListSize - Supplies a pointer to the buffer size which will be
  1409. decremented to account for this property.
  1410. Return Value:
  1411. ERROR_SUCCESS - The operation completed successfully.
  1412. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1413. Win32 error code - The operation failed.
  1414. --*/
  1415. {
  1416. DWORD dataSize;
  1417. //
  1418. // Make sure the buffer is big enough and
  1419. // the value is formatted correctly.
  1420. //
  1421. dataSize = sizeof(*pValueStruct);
  1422. if ( (*pcbPropertyListSize < dataSize) ||
  1423. (pValueStruct->Syntax.wFormat != CLUSPROP_FORMAT_DWORD) ||
  1424. (pValueStruct->cbLength != sizeof(DWORD)) ) {
  1425. return(ERROR_INVALID_PARAMETER);
  1426. }
  1427. //
  1428. // Make sure the value is in range.
  1429. //
  1430. if ( (dwMinimum != 0) && (dwMaximum != 0) ) {
  1431. if ( (pValueStruct->dw < dwMinimum) ||
  1432. (pValueStruct->dw > dwMaximum) ) {
  1433. return(ERROR_INVALID_PARAMETER);
  1434. }
  1435. }
  1436. //
  1437. // Set to the new value.
  1438. //
  1439. *pdwOutValue = pValueStruct->dw;
  1440. //
  1441. // Decrement remaining buffer size and move to the next property.
  1442. //
  1443. *pcbPropertyListSize -= dataSize;
  1444. *ppPropertyList += dataSize;
  1445. return(ERROR_SUCCESS);
  1446. } // ResUtilGetDwordProperty
  1447. LPVOID
  1448. WINAPI
  1449. ResUtilGetEnvironmentWithNetName(
  1450. IN HRESOURCE hResource
  1451. )
  1452. /*++
  1453. Routine Description:
  1454. Creates an environment block based on the current environment
  1455. block, but with the addition of a _CLUSTER_NETWORK_NAME=xxx
  1456. environment value. xxx in this case represents the network
  1457. name of the supplied resource. This environment block is suitable
  1458. for passing to CreateProcess to create an environment that will
  1459. cause GetComputerName to lie to the application.
  1460. _CLUSTER_NETWORK_FQDN_ will return a fully qualified DNS name.
  1461. Arguments:
  1462. hResource - Supplies the resource
  1463. Return Value:
  1464. pointer to the environment block if successful.
  1465. NULL otherwise
  1466. --*/
  1467. {
  1468. PVOID pvEnvironment = NULL;
  1469. DWORD dwStatus;
  1470. NTSTATUS ntStatus;
  1471. BOOL fSuccess;
  1472. LPWSTR pszNetworkName = NULL;
  1473. DWORD cchNetworkName;
  1474. DWORD cchAllocSize;
  1475. DWORD cchDomain;
  1476. UNICODE_STRING usValueName;
  1477. UNICODE_STRING usValue;
  1478. HANDLE hProcessToken = NULL;
  1479. //
  1480. // First find out the network name
  1481. //
  1482. cchNetworkName = 256;
  1483. cchAllocSize = cchNetworkName;
  1484. pszNetworkName = LocalAlloc( LMEM_FIXED, cchAllocSize * sizeof( pszNetworkName[ 0 ] ) );
  1485. if ( pszNetworkName == NULL )
  1486. {
  1487. dwStatus = E_OUTOFMEMORY;
  1488. goto Cleanup;
  1489. }
  1490. fSuccess = GetClusterResourceNetworkName(
  1491. hResource,
  1492. pszNetworkName,
  1493. &cchNetworkName
  1494. );
  1495. if ( ! fSuccess )
  1496. {
  1497. dwStatus = GetLastError();
  1498. if ( dwStatus == ERROR_MORE_DATA )
  1499. {
  1500. LocalFree( pszNetworkName );
  1501. cchNetworkName++;
  1502. cchNetworkName *= 2;
  1503. cchAllocSize = cchNetworkName;
  1504. pszNetworkName = LocalAlloc( LMEM_FIXED, cchAllocSize * sizeof( pszNetworkName[ 0 ] ) );
  1505. if ( pszNetworkName == NULL )
  1506. {
  1507. dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  1508. goto Cleanup;
  1509. }
  1510. fSuccess = GetClusterResourceNetworkName(
  1511. hResource,
  1512. pszNetworkName,
  1513. &cchNetworkName
  1514. );
  1515. }
  1516. if ( ! fSuccess )
  1517. {
  1518. dwStatus = GetLastError();
  1519. goto Cleanup;
  1520. }
  1521. }
  1522. RtlInitUnicodeString( &usValueName, L"_CLUSTER_NETWORK_NAME_" );
  1523. RtlInitUnicodeString( &usValue, pszNetworkName );
  1524. //
  1525. // get the current process token. If it fails, we revert to using just the
  1526. // system environment area
  1527. //
  1528. OpenProcessToken( GetCurrentProcess(), MAXIMUM_ALLOWED, &hProcessToken );
  1529. //
  1530. // Clone the current environment, picking up any changes that might have
  1531. // been made after resmon started
  1532. //
  1533. fSuccess = CreateEnvironmentBlock( &pvEnvironment, hProcessToken, FALSE );
  1534. if ( ! fSuccess )
  1535. {
  1536. dwStatus = GetLastError();
  1537. goto Cleanup;
  1538. }
  1539. //
  1540. // Add the new value to the cloned environment
  1541. //
  1542. ntStatus = RtlSetEnvironmentVariable(
  1543. &pvEnvironment,
  1544. &usValueName,
  1545. &usValue
  1546. );
  1547. if ( ! NT_SUCCESS( ntStatus ) )
  1548. {
  1549. dwStatus = RtlNtStatusToDosError( ntStatus );
  1550. goto Error;
  1551. }
  1552. //
  1553. // add in the DNS hostname
  1554. //
  1555. RtlInitUnicodeString( &usValueName, L"_CLUSTER_NETWORK_HOSTNAME_" );
  1556. RtlInitUnicodeString( &usValue, pszNetworkName );
  1557. ntStatus = RtlSetEnvironmentVariable(
  1558. &pvEnvironment,
  1559. &usValueName,
  1560. &usValue
  1561. );
  1562. if ( ! NT_SUCCESS( ntStatus ) )
  1563. {
  1564. dwStatus = RtlNtStatusToDosError( ntStatus );
  1565. goto Error;
  1566. }
  1567. //
  1568. // Change the COMPUTERNAME environment variable to match.
  1569. //
  1570. RtlInitUnicodeString( &usValueName, L"COMPUTERNAME" );
  1571. ntStatus = RtlSetEnvironmentVariable(
  1572. &pvEnvironment,
  1573. &usValueName,
  1574. &usValue
  1575. );
  1576. if ( ! NT_SUCCESS( ntStatus ) )
  1577. {
  1578. dwStatus = RtlNtStatusToDosError( ntStatus );
  1579. goto Error;
  1580. }
  1581. //
  1582. // Now generate the string for the FQDN
  1583. //
  1584. RtlInitUnicodeString( &usValueName, L"_CLUSTER_NETWORK_FQDN_" );
  1585. pszNetworkName[ cchNetworkName ] = L'.';
  1586. cchDomain = cchAllocSize - cchNetworkName - 1;
  1587. if ( GetComputerNameExW(
  1588. ComputerNameDnsDomain,
  1589. &pszNetworkName[ cchNetworkName + 1 ],
  1590. &cchDomain )
  1591. )
  1592. {
  1593. if ( cchDomain == 0 )
  1594. {
  1595. pszNetworkName[ cchNetworkName ] = L'\0';
  1596. }
  1597. }
  1598. else
  1599. {
  1600. //
  1601. // Error from trying to get the DNS Domain name.
  1602. // Just don't set the DnsDomain name!
  1603. //
  1604. goto Cleanup;
  1605. }
  1606. RtlInitUnicodeString( &usValue, pszNetworkName );
  1607. //
  1608. // Add in the FQDN name
  1609. //
  1610. ntStatus = RtlSetEnvironmentVariable(
  1611. &pvEnvironment,
  1612. &usValueName,
  1613. &usValue
  1614. );
  1615. if ( ! NT_SUCCESS( ntStatus ) )
  1616. {
  1617. dwStatus = RtlNtStatusToDosError( ntStatus );
  1618. goto Error;
  1619. }
  1620. Cleanup:
  1621. if ( hProcessToken != NULL )
  1622. {
  1623. CloseHandle( hProcessToken );
  1624. }
  1625. if ( pszNetworkName != NULL )
  1626. {
  1627. LocalFree( pszNetworkName );
  1628. }
  1629. SetLastError( dwStatus );
  1630. return pvEnvironment;
  1631. Error:
  1632. if ( pvEnvironment != NULL )
  1633. {
  1634. RtlDestroyEnvironment( pvEnvironment );
  1635. pvEnvironment = NULL;
  1636. }
  1637. goto Cleanup;
  1638. } // ResUtilGetEnvironmentWithNetName
  1639. //***************************************************************************
  1640. //
  1641. // Worker thread routines
  1642. //
  1643. //***************************************************************************
  1644. DWORD
  1645. WINAPI
  1646. ClusWorkerStart(
  1647. IN PWORK_CONTEXT pContext
  1648. )
  1649. /*++
  1650. Routine Description:
  1651. Wrapper routine for cluster resource worker startup
  1652. Arguments:
  1653. Context - Supplies the context block. This will be freed.
  1654. Return Value:
  1655. ERROR_SUCCESS
  1656. --*/
  1657. {
  1658. DWORD Status;
  1659. WORK_CONTEXT Context;
  1660. //
  1661. // Capture our parameters and free the work context.
  1662. //
  1663. Context = *pContext;
  1664. LocalFree(pContext);
  1665. //
  1666. // Call the worker routine
  1667. //
  1668. Status = (Context.lpStartRoutine)(Context.Worker, Context.lpParameter);
  1669. //
  1670. // Synchronize and clean up properly.
  1671. //
  1672. EnterCriticalSection(&ResUtilWorkerLock);
  1673. if (!Context.Worker->Terminate) {
  1674. CloseHandle(Context.Worker->hThread);
  1675. Context.Worker->hThread = NULL;
  1676. }
  1677. Context.Worker->Terminate = TRUE;
  1678. LeaveCriticalSection(&ResUtilWorkerLock);
  1679. return(Status);
  1680. } // ClusWorkerStart
  1681. DWORD
  1682. WINAPI
  1683. ClusWorkerCreate(
  1684. OUT PCLUS_WORKER lpWorker,
  1685. IN PWORKER_START_ROUTINE lpStartAddress,
  1686. IN PVOID lpParameter
  1687. )
  1688. /*++
  1689. Routine Description:
  1690. Common wrapper for resource DLL worker threads. Provides
  1691. "clean" terminate semantics
  1692. Arguments:
  1693. lpWorker - Returns an initialized worker structure
  1694. lpStartAddress - Supplies the worker thread routine
  1695. lpParameter - Supplies the parameter to be passed to the
  1696. worker thread routine
  1697. Return Value:
  1698. ERROR_SUCCESS if successful
  1699. Win32 error code otherwise
  1700. --*/
  1701. {
  1702. PWORK_CONTEXT Context;
  1703. DWORD ThreadId;
  1704. DWORD Status;
  1705. Context = LocalAlloc(LMEM_FIXED, sizeof(WORK_CONTEXT));
  1706. if (Context == NULL) {
  1707. return(ERROR_NOT_ENOUGH_MEMORY);
  1708. }
  1709. Context->Worker = lpWorker;
  1710. Context->lpParameter = lpParameter;
  1711. Context->lpStartRoutine = lpStartAddress;
  1712. lpWorker->Terminate = FALSE;
  1713. lpWorker->hThread = CreateThread(NULL,
  1714. 0,
  1715. ClusWorkerStart,
  1716. Context,
  1717. 0,
  1718. &ThreadId);
  1719. if (lpWorker->hThread == NULL) {
  1720. Status = GetLastError();
  1721. LocalFree(Context);
  1722. return(Status);
  1723. }
  1724. return(ERROR_SUCCESS);
  1725. } // ClusWorkerCreate
  1726. BOOL
  1727. WINAPI
  1728. ClusWorkerCheckTerminate(
  1729. IN PCLUS_WORKER lpWorker
  1730. )
  1731. /*++
  1732. Routine Description:
  1733. Checks to see if the specified Worker thread should exit ASAP.
  1734. Arguments:
  1735. lpWorker - Supplies the worker
  1736. Return Value:
  1737. TRUE if the thread should exit.
  1738. FALSE otherwise
  1739. --*/
  1740. {
  1741. return(lpWorker->Terminate);
  1742. } // ClusWorkerCheckTerminate
  1743. VOID
  1744. WINAPI
  1745. ClusWorkerTerminate(
  1746. IN PCLUS_WORKER lpWorker
  1747. )
  1748. /*++
  1749. Routine Description:
  1750. Checks to see if the specified Worker thread should exit ASAP.
  1751. Arguments:
  1752. lpWorker - Supplies the worker
  1753. Return Value:
  1754. None.
  1755. --*/
  1756. {
  1757. //
  1758. // N.B. There is a race condition here if multiple threads
  1759. // call this routine on the same worker. The first one
  1760. // through will set Terminate. The second one will see
  1761. // that Terminate is set and return immediately without
  1762. // waiting for the Worker to exit. Not really any nice
  1763. // way to fix this without adding another synchronization
  1764. // object.
  1765. //
  1766. if ((lpWorker->hThread == NULL) ||
  1767. (lpWorker->Terminate)) {
  1768. return;
  1769. }
  1770. EnterCriticalSection(&ResUtilWorkerLock);
  1771. if (!lpWorker->Terminate) {
  1772. lpWorker->Terminate = TRUE;
  1773. LeaveCriticalSection(&ResUtilWorkerLock);
  1774. WaitForSingleObject(lpWorker->hThread, INFINITE);
  1775. CloseHandle(lpWorker->hThread);
  1776. lpWorker->hThread = NULL;
  1777. } else {
  1778. LeaveCriticalSection(&ResUtilWorkerLock);
  1779. }
  1780. return;
  1781. } // ClusWorkerTerminate
  1782. DWORD
  1783. WINAPI
  1784. ResUtilCreateDirectoryTree(
  1785. IN LPCWSTR pszPath
  1786. )
  1787. /*++
  1788. Routine Description:
  1789. Creates all the directories in the specified path.
  1790. ERROR_ALREADY_EXISTS will never be returned by this routine.
  1791. Arguments:
  1792. pszPath - String containing a path.
  1793. Return Value:
  1794. ERROR_SUCCESS - The operation completed successfully
  1795. Win32 error code - The operation failed.
  1796. --*/
  1797. {
  1798. return( ClRtlCreateDirectory( pszPath ) );
  1799. } // ResUtilCreateDirectoryTree
  1800. BOOL
  1801. WINAPI
  1802. ResUtilIsPathValid(
  1803. IN LPCWSTR pszPath
  1804. )
  1805. /*++
  1806. Routine Description:
  1807. Returns true if the given path looks syntactically valid.
  1808. This call is NOT network-aware.
  1809. Arguments:
  1810. pszPath - String containing a path.
  1811. Return Value:
  1812. TRUE if the path looks valid, otherwise FALSE.
  1813. --*/
  1814. {
  1815. return( ClRtlIsPathValid( pszPath ) );
  1816. } // ResUtilIsPathValid
  1817. DWORD
  1818. WINAPI
  1819. ResUtilFreeEnvironment(
  1820. IN LPVOID lpEnvironment
  1821. )
  1822. /*++
  1823. Routine Description:
  1824. Destroys an environment variable block.
  1825. Arguments:
  1826. Environment - the environment variable block to destroy.
  1827. Return Value:
  1828. A Win32 error code.
  1829. --*/
  1830. {
  1831. NTSTATUS ntStatus;
  1832. ntStatus = RtlDestroyEnvironment( lpEnvironment );
  1833. return( RtlNtStatusToDosError(ntStatus) );
  1834. } // ResUtilFreeEnvironment
  1835. LPWSTR
  1836. WINAPI
  1837. ResUtilExpandEnvironmentStrings(
  1838. IN LPCWSTR pszSrc
  1839. )
  1840. /*++
  1841. Routine Description:
  1842. Expands environment strings and returns an allocated buffer containing
  1843. the result.
  1844. Arguments:
  1845. pszSrc - Source string to expand.
  1846. Return Value:
  1847. A pointer to a buffer containing the value if successful.
  1848. NULL if unsuccessful. Call GetLastError() to get more details.
  1849. --*/
  1850. {
  1851. return( ClRtlExpandEnvironmentStrings( pszSrc ) );
  1852. } // ResUtilExpandEnvironmentStrings
  1853. /////////////////////////////////////////////////////////////////////////////
  1854. //++
  1855. //
  1856. // ResUtilSetResourceServiceEnvironment
  1857. //
  1858. // Description:
  1859. // Set the environment for the specified service.
  1860. //
  1861. // Arguments:
  1862. // pszServiceName [IN]
  1863. // Name of service whose environment is to be set.
  1864. //
  1865. // hResource [IN]
  1866. // Handle to resource.
  1867. //
  1868. // pfnLogEvent [IN]
  1869. // Pointer to a routine that handles the reporting of events from
  1870. // the resource DLL.
  1871. //
  1872. // hResourceHandle [IN]
  1873. // Handle for logging.
  1874. //
  1875. // Return Value:
  1876. // ERROR_SUCCESS
  1877. // The function completed successfully.
  1878. //
  1879. // Win32 error code
  1880. // The function failed.
  1881. //
  1882. //--
  1883. /////////////////////////////////////////////////////////////////////////////
  1884. DWORD WINAPI ResUtilSetResourceServiceEnvironment(
  1885. IN LPCWSTR pszServiceName,
  1886. IN HRESOURCE hResource,
  1887. IN PLOG_EVENT_ROUTINE pfnLogEvent,
  1888. IN RESOURCE_HANDLE hResourceHandle
  1889. )
  1890. {
  1891. DWORD nStatus;
  1892. DWORD cbEnvironment;
  1893. PVOID pvEnvironment = NULL;
  1894. LPWSTR pszEnvString;
  1895. HKEY hkeyServicesKey;
  1896. HKEY hkeyServiceName;
  1897. do
  1898. {
  1899. //
  1900. // Create the new environment with the simulated net name when the
  1901. // service queries GetComputerName.
  1902. //
  1903. pvEnvironment = ResUtilGetEnvironmentWithNetName( hResource );
  1904. if ( pvEnvironment == NULL )
  1905. {
  1906. nStatus = GetLastError();
  1907. break;
  1908. } // if: error getting environment
  1909. //
  1910. // Compute the size of the environment. We are looking for
  1911. // the double NULL terminator that ends the environment block.
  1912. //
  1913. pszEnvString = (LPWSTR) pvEnvironment;
  1914. while ( *pszEnvString != L'\0' )
  1915. {
  1916. while ( *pszEnvString++ != L'\0')
  1917. {
  1918. } // while: more characters in this environment string
  1919. } // while: more environment strings
  1920. cbEnvironment = (DWORD)((PUCHAR)pszEnvString - (PUCHAR)pvEnvironment) + sizeof( WCHAR );
  1921. //
  1922. // Open the Services key in the registry.
  1923. //
  1924. nStatus = RegOpenKeyExW(
  1925. HKEY_LOCAL_MACHINE,
  1926. L"System\\CurrentControlSet\\Services",
  1927. 0,
  1928. KEY_READ,
  1929. &hkeyServicesKey
  1930. );
  1931. if ( nStatus != ERROR_SUCCESS )
  1932. {
  1933. (pfnLogEvent)(
  1934. hResourceHandle,
  1935. LOG_ERROR,
  1936. L"ResUtilSetResourceServiceEnvironment: Failed to open services key, error = %1!u!.\n",
  1937. nStatus
  1938. );
  1939. break;
  1940. } // if: error opening the Services key in the registry
  1941. //
  1942. // Open the service name key in the registry
  1943. //
  1944. nStatus = RegOpenKeyExW(
  1945. hkeyServicesKey,
  1946. pszServiceName,
  1947. 0,
  1948. KEY_READ | KEY_WRITE,
  1949. &hkeyServiceName
  1950. );
  1951. RegCloseKey( hkeyServicesKey );
  1952. if ( nStatus != ERROR_SUCCESS )
  1953. {
  1954. (pfnLogEvent)(
  1955. hResourceHandle,
  1956. LOG_ERROR,
  1957. L"ResUtilSetResourceServiceEnvironment: Failed to open service key, error = %1!u!.\n",
  1958. nStatus
  1959. );
  1960. break;
  1961. } // if: error opening the service name key in the registry
  1962. //
  1963. // Set the environment value in the service's registry key.
  1964. //
  1965. nStatus = RegSetValueExW(
  1966. hkeyServiceName,
  1967. L"Environment",
  1968. 0,
  1969. REG_MULTI_SZ,
  1970. (const UCHAR *) pvEnvironment,
  1971. cbEnvironment
  1972. );
  1973. RegCloseKey( hkeyServiceName );
  1974. if ( nStatus != ERROR_SUCCESS )
  1975. {
  1976. (pfnLogEvent)(
  1977. hResourceHandle,
  1978. LOG_ERROR,
  1979. L"ResUtilSetResourceServiceEnvironment: Failed to set service environment value, error = %1!u!.\n",
  1980. nStatus
  1981. );
  1982. break;
  1983. } // if: error setting the Environment value in the registry
  1984. } while ( 0 );
  1985. if ( pvEnvironment != NULL )
  1986. {
  1987. ResUtilFreeEnvironment( pvEnvironment );
  1988. } // if: environment block allocated
  1989. return nStatus;
  1990. } //*** ResUtilSetResourceServiceEnvironment()
  1991. /////////////////////////////////////////////////////////////////////////////
  1992. //++
  1993. //
  1994. // ResUtilSetResourceServiceStartParameters
  1995. //
  1996. // Description:
  1997. // Set the start parameters for the specified service.
  1998. //
  1999. // Arguments:
  2000. // pszServiceName [IN]
  2001. // Name of service whose start parameters are to be set.
  2002. //
  2003. // schSCMHandle [IN]
  2004. // Handle to the Service Control Manager. Can be specified as NULL.
  2005. //
  2006. // phService [OUT]
  2007. // Service handle.
  2008. //
  2009. // pfnLogEvent [IN]
  2010. // Pointer to a routine that handles the reporting of events from
  2011. // the resource DLL.
  2012. //
  2013. // hResourceHandle [IN]
  2014. // Handle for logging.
  2015. //
  2016. // Return Value:
  2017. // ERROR_SUCCESS
  2018. // The function completed successfully.
  2019. //
  2020. // Win32 error code
  2021. // The function failed.
  2022. //
  2023. //--
  2024. /////////////////////////////////////////////////////////////////////////////
  2025. DWORD WINAPI ResUtilSetResourceServiceStartParameters(
  2026. IN LPCWSTR pszServiceName,
  2027. IN SC_HANDLE schSCMHandle,
  2028. IN OUT LPSC_HANDLE phService,
  2029. IN PLOG_EVENT_ROUTINE pfnLogEvent,
  2030. IN RESOURCE_HANDLE hResourceHandle
  2031. )
  2032. {
  2033. DWORD nStatus;
  2034. DWORD cbBytesNeeded;
  2035. DWORD cbQueryServiceConfig;
  2036. DWORD idx;
  2037. BOOL bWeOpenedSCM = FALSE;
  2038. LPQUERY_SERVICE_CONFIG pQueryServiceConfig = NULL;
  2039. LPSERVICE_FAILURE_ACTIONS pSvcFailureActions = NULL;
  2040. do
  2041. {
  2042. //
  2043. // Open the Service Control Manager if necessary.
  2044. //
  2045. if ( schSCMHandle == NULL )
  2046. {
  2047. schSCMHandle = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
  2048. if ( schSCMHandle == NULL )
  2049. {
  2050. nStatus = GetLastError();
  2051. (pfnLogEvent)(
  2052. hResourceHandle,
  2053. LOG_ERROR,
  2054. L"ResUtilSetResourceServiceStartParameters: Failed to open Service Control Manager. Error: %1!u!.\n",
  2055. nStatus
  2056. );
  2057. break;
  2058. } // if: error opening the Service Control Manager
  2059. bWeOpenedSCM = TRUE;
  2060. } // if: Service Control Manager not open yet
  2061. //
  2062. // Open the service.
  2063. //
  2064. *phService = OpenService(
  2065. schSCMHandle,
  2066. pszServiceName,
  2067. SERVICE_ALL_ACCESS
  2068. );
  2069. if ( *phService == NULL )
  2070. {
  2071. nStatus = GetLastError();
  2072. // TODO: Log event to the event log.
  2073. (pfnLogEvent)(
  2074. hResourceHandle,
  2075. LOG_ERROR,
  2076. L"ResUtilSetResourceServiceStartParameters: Failed to open the '%1' service. Error: %2!u!.\n",
  2077. pszServiceName,
  2078. nStatus
  2079. );
  2080. break;
  2081. } // if: error opening the service
  2082. //
  2083. // Query the service to make sure it is not disabled.
  2084. //
  2085. cbQueryServiceConfig = sizeof( QUERY_SERVICE_CONFIG );
  2086. do
  2087. {
  2088. //
  2089. // Allocate memory for the config info structure.
  2090. //
  2091. pQueryServiceConfig = (LPQUERY_SERVICE_CONFIG) LocalAlloc( LMEM_FIXED, cbQueryServiceConfig );
  2092. if ( pQueryServiceConfig == NULL )
  2093. {
  2094. nStatus = GetLastError();
  2095. (pfnLogEvent)(
  2096. hResourceHandle,
  2097. LOG_ERROR,
  2098. L"ResUtilSetResourceServiceStartParameters: Failed to allocate memory for query_service_config. Error: %1!u!.\n",
  2099. nStatus
  2100. );
  2101. break;
  2102. } // if: error allocating memory
  2103. //
  2104. // Query for the config info. If it fails because the buffer
  2105. // is too small, reallocate and try again.
  2106. //
  2107. if ( ! QueryServiceConfig(
  2108. *phService,
  2109. pQueryServiceConfig,
  2110. cbQueryServiceConfig,
  2111. &cbBytesNeeded
  2112. ) )
  2113. {
  2114. nStatus = GetLastError();
  2115. if ( nStatus != ERROR_INSUFFICIENT_BUFFER )
  2116. {
  2117. (pfnLogEvent)(
  2118. hResourceHandle,
  2119. LOG_ERROR,
  2120. L"ResUtilSetResourceServiceStartParameters: Failed to query service configuration for the '%1' service. Error: %2!u!.\n",
  2121. pszServiceName,
  2122. nStatus
  2123. );
  2124. break;
  2125. }
  2126. nStatus = ERROR_SUCCESS;
  2127. LocalFree( pQueryServiceConfig );
  2128. pQueryServiceConfig = NULL;
  2129. cbQueryServiceConfig = cbBytesNeeded;
  2130. continue;
  2131. } // if: error querying for service config info
  2132. else
  2133. {
  2134. nStatus = ERROR_SUCCESS;
  2135. cbBytesNeeded = 0;
  2136. } // else: query was successful
  2137. //
  2138. // Check to see if the service is disabled or not.
  2139. //
  2140. if ( pQueryServiceConfig->dwStartType == SERVICE_DISABLED )
  2141. {
  2142. (pfnLogEvent)(
  2143. hResourceHandle,
  2144. LOG_ERROR,
  2145. L"ResUtilSetResourceServiceStartParameters: The service '%1' is DISABLED.\n",
  2146. pszServiceName
  2147. );
  2148. nStatus = ERROR_SERVICE_DISABLED;
  2149. break;
  2150. } // if: service is disabled
  2151. } while ( cbBytesNeeded != 0 );
  2152. if ( nStatus != ERROR_SUCCESS )
  2153. {
  2154. break;
  2155. } // if: error occurred checking to see if service is disabled
  2156. //
  2157. // Set the service to manual start.
  2158. //
  2159. if ( ! ChangeServiceConfig(
  2160. *phService,
  2161. SERVICE_NO_CHANGE,
  2162. SERVICE_DEMAND_START, // Manual start
  2163. SERVICE_NO_CHANGE,
  2164. NULL,
  2165. NULL,
  2166. NULL,
  2167. NULL,
  2168. NULL,
  2169. NULL,
  2170. NULL
  2171. ) )
  2172. {
  2173. nStatus = GetLastError();
  2174. (pfnLogEvent)(
  2175. hResourceHandle,
  2176. LOG_ERROR,
  2177. L"ResUtilSetResourceServiceStartParameters: Failed to set service '%1' to manual start. Error: %2!u!.\n",
  2178. pszServiceName,
  2179. nStatus
  2180. );
  2181. break;
  2182. } // if: error setting service to manual start
  2183. //
  2184. // Query for the size of the service failure actions array.
  2185. // Use nStatus as the dummy buffer since the QueryServiceConfig2 API
  2186. // is not that friendly.
  2187. //
  2188. if ( ! QueryServiceConfig2(
  2189. *phService,
  2190. SERVICE_CONFIG_FAILURE_ACTIONS,
  2191. (LPBYTE) &nStatus,
  2192. sizeof( DWORD ),
  2193. &cbBytesNeeded
  2194. ) )
  2195. {
  2196. nStatus = GetLastError();
  2197. if ( nStatus == ERROR_INSUFFICIENT_BUFFER )
  2198. {
  2199. nStatus = ERROR_SUCCESS;
  2200. } // if: expected "buffer too small" error occurred
  2201. else
  2202. {
  2203. (pfnLogEvent)(
  2204. hResourceHandle,
  2205. LOG_ERROR,
  2206. L"ResUtilSetResourceServiceStartParameters: Failed to query service configuration for size for the '%1' service. Error: %2!u!.\n",
  2207. pszServiceName,
  2208. nStatus
  2209. );
  2210. break;
  2211. } // else: an unexpected error occurred
  2212. } // if: error querying for service failure actions buffer size
  2213. //
  2214. // Allocate memory for the service failure actions array.
  2215. //
  2216. pSvcFailureActions = (LPSERVICE_FAILURE_ACTIONS) LocalAlloc( LMEM_FIXED, cbBytesNeeded );
  2217. if ( pSvcFailureActions == NULL )
  2218. {
  2219. nStatus = GetLastError();
  2220. (pfnLogEvent)(
  2221. hResourceHandle,
  2222. LOG_ERROR,
  2223. L"ResUtilSetResourceServiceStartParameters: Failed to allocate memory of size %1!u!. Error: %2!u!.\n",
  2224. cbBytesNeeded,
  2225. nStatus
  2226. );
  2227. break;
  2228. } // if: error allocating memory for the service failure actions array
  2229. //
  2230. // Query for the service failure actions array.
  2231. //
  2232. if ( ! QueryServiceConfig2(
  2233. *phService,
  2234. SERVICE_CONFIG_FAILURE_ACTIONS,
  2235. (LPBYTE) pSvcFailureActions,
  2236. cbBytesNeeded,
  2237. &cbBytesNeeded
  2238. ) )
  2239. {
  2240. nStatus = GetLastError();
  2241. (pfnLogEvent)(
  2242. hResourceHandle,
  2243. LOG_ERROR,
  2244. L"ResUtilSetResourceServiceStartParameters: Failed to query service configuration for the '%1' service. Error: %2!u!.\n",
  2245. pszServiceName,
  2246. nStatus
  2247. );
  2248. break;
  2249. } // if: error querying for service failure actions
  2250. //
  2251. // If any of the service action is set to service restart,
  2252. // set it to none.
  2253. //
  2254. for ( idx = 0 ; idx < pSvcFailureActions->cActions ; idx++ )
  2255. {
  2256. if ( pSvcFailureActions->lpsaActions[ idx ].Type == SC_ACTION_RESTART )
  2257. {
  2258. pSvcFailureActions->lpsaActions[ idx ].Type = SC_ACTION_NONE;
  2259. } // if: action set to restart
  2260. } // for: each service failure action array entry
  2261. //
  2262. // Set the changes to the service failure actions array.
  2263. //
  2264. if ( ! ChangeServiceConfig2(
  2265. *phService,
  2266. SERVICE_CONFIG_FAILURE_ACTIONS,
  2267. pSvcFailureActions
  2268. ) )
  2269. {
  2270. nStatus = GetLastError();
  2271. (pfnLogEvent)(
  2272. hResourceHandle,
  2273. LOG_ERROR,
  2274. L"ResUtilSetResourceServiceStartParameters: Failed to set service failure actions for the '%1' service. Error: %2!u!.\n",
  2275. pszServiceName,
  2276. nStatus
  2277. );
  2278. break;
  2279. } // if: error saving service failure actions
  2280. } while ( 0 );
  2281. //
  2282. // Cleanup.
  2283. //
  2284. LocalFree( pQueryServiceConfig );
  2285. LocalFree( pSvcFailureActions );
  2286. if ( bWeOpenedSCM )
  2287. {
  2288. CloseServiceHandle( schSCMHandle );
  2289. } // if: we opened the Server Control Manager
  2290. if ( ( nStatus != ERROR_SUCCESS ) && ( *phService != NULL ) )
  2291. {
  2292. CloseServiceHandle( *phService );
  2293. *phService = NULL;
  2294. } // if: error occurred after opening service
  2295. return nStatus;
  2296. } //*** ResUtilSetResourceServiceStartParameters()
  2297. /////////////////////////////////////////////////////////////////////////////
  2298. //++
  2299. //
  2300. // ResUtilGetResourceDependentIPAddressProps
  2301. //
  2302. // Description:
  2303. // Get the properties from the first IP Address resource on which the
  2304. // specified resource is dependent.
  2305. //
  2306. // Arguments:
  2307. // hResource [IN]
  2308. // Handle to the resource to query.
  2309. //
  2310. // pszAddress [OUT]
  2311. // Output buffer for returning the address.
  2312. //
  2313. // pcchAddress [IN OUT]
  2314. // On input contains the size in characters of the pszAddress buffer.
  2315. // On output contains the size in characters, including the terminating
  2316. // NULL, of the string for the Address property. If pszAddress is
  2317. // specified as NULL and this is not specified as NULL, ERROR_SUCCESS
  2318. // be returned. Otherwise, ERROR_MORE_DATA will be returned.
  2319. //
  2320. // pszSubnetMask [OUT]
  2321. // Output buffer for returning the subnet mask.
  2322. //
  2323. // pcchSubnetMask [IN OUT]
  2324. // On input contains the size in characters of the pszSubnetMask buffer.
  2325. // On output contains the size in characters, including the terminating
  2326. // NULL, of the string for the SubnetMask property. If pszSubnetMask is
  2327. // specified as NULL and this is not specified as NULL, ERROR_SUCCESS
  2328. // be returned. Otherwise, ERROR_MORE_DATA will be returned.
  2329. //
  2330. // pszNetwork [OUT]
  2331. // Output buffer for returning the network.
  2332. //
  2333. // pcchNetwork [IN OUT]
  2334. // On input contains the size in characters of the pszNetwork buffer.
  2335. // On output contains the size in characters, including the terminating
  2336. // NULL, of the string for the Network property. If pszNetwork is
  2337. // specified as NULL and this is not specified as NULL, ERROR_SUCCESS
  2338. // be returned. Otherwise, ERROR_MORE_DATA will be returned.
  2339. //
  2340. // Return Value:
  2341. // ERROR_SUCCESS
  2342. // The function completed successfully.
  2343. //
  2344. // ERROR_MORE_DATA
  2345. // The size of one of the buffers was too small.
  2346. //
  2347. // Win32 error code
  2348. // The function failed.
  2349. //
  2350. //--
  2351. /////////////////////////////////////////////////////////////////////////////
  2352. DWORD WINAPI ResUtilGetResourceDependentIPAddressProps(
  2353. IN HRESOURCE hResource,
  2354. OUT LPWSTR pszAddress,
  2355. IN OUT DWORD * pcchAddress,
  2356. OUT LPWSTR pszSubnetMask,
  2357. IN OUT DWORD * pcchSubnetMask,
  2358. OUT LPWSTR pszNetwork,
  2359. IN OUT DWORD * pcchNetwork
  2360. )
  2361. {
  2362. DWORD nStatus = ERROR_SUCCESS;
  2363. HRESENUM hresenum = NULL;
  2364. HRESOURCE hresDep = NULL;
  2365. DWORD idx;
  2366. DWORD nType;
  2367. DWORD cchmacName;
  2368. DWORD cchName;
  2369. LPWSTR pszName = NULL;
  2370. DWORD cbProps;
  2371. PBYTE pbProps = NULL;
  2372. LPWSTR pszProp;
  2373. DWORD cchProp;
  2374. HCLUSTER hCluster;
  2375. do
  2376. {
  2377. //
  2378. // Enumerate dependent resources.
  2379. //
  2380. hresenum = ClusterResourceOpenEnum( hResource, CLUSTER_RESOURCE_ENUM_DEPENDS );
  2381. if ( hresenum == NULL )
  2382. {
  2383. nStatus = GetLastError();
  2384. break;
  2385. } // if: error opening the enumeration
  2386. //
  2387. // Allocate the initial name buffer.
  2388. //
  2389. cchmacName = 256;
  2390. cchName = cchmacName;
  2391. pszName = (LPWSTR) LocalAlloc( LMEM_FIXED, cchName * sizeof( pszName[ 0 ] ) );
  2392. if ( pszName == NULL )
  2393. {
  2394. nStatus = GetLastError();
  2395. break;
  2396. } // if: error allocating resource name buffer
  2397. for ( idx = 0 ; ; idx++ )
  2398. {
  2399. //
  2400. // Get the first entry in the enumeration.
  2401. //
  2402. nStatus = ClusterResourceEnum(
  2403. hresenum,
  2404. idx,
  2405. &nType,
  2406. pszName,
  2407. &cchName
  2408. );
  2409. if ( nStatus == ERROR_MORE_DATA )
  2410. {
  2411. LocalFree( pszName );
  2412. cchName++;
  2413. cchmacName = cchName;
  2414. pszName = (LPWSTR) LocalAlloc( LMEM_FIXED, cchName * sizeof( pszName[ 0 ] ) );
  2415. if ( pszName == NULL )
  2416. {
  2417. nStatus = GetLastError();
  2418. break;
  2419. } // if: error allocating resource name buffer
  2420. nStatus = ClusterResourceEnum(
  2421. hresenum,
  2422. idx,
  2423. &nType,
  2424. pszName,
  2425. &cchName
  2426. );
  2427. } // if: buffer is too small
  2428. if ( nStatus != ERROR_SUCCESS )
  2429. {
  2430. break;
  2431. } // if: error getting the dependent resource name
  2432. //
  2433. // Open the resource.
  2434. //
  2435. hCluster = GetClusterFromResource( hResource );
  2436. if ( hCluster == NULL ) {
  2437. nStatus = GetLastError();
  2438. break;
  2439. }
  2440. hresDep = OpenClusterResource( hCluster, pszName );
  2441. if ( hresDep == NULL )
  2442. {
  2443. nStatus = GetLastError();
  2444. break;
  2445. } // if: error opening the dependent resource
  2446. //
  2447. // Get the resource type name.
  2448. //
  2449. cchName = cchmacName;
  2450. nStatus = ClusterResourceControl(
  2451. hresDep,
  2452. NULL,
  2453. CLUSCTL_RESOURCE_GET_RESOURCE_TYPE,
  2454. NULL,
  2455. 0,
  2456. pszName,
  2457. cchmacName,
  2458. &cchName
  2459. );
  2460. if ( nStatus == ERROR_MORE_DATA )
  2461. {
  2462. LocalFree( pszName );
  2463. cchName++;
  2464. cchmacName = cchName;
  2465. pszName = (LPWSTR) LocalAlloc( LMEM_FIXED, cchName * sizeof( pszName[ 0 ] ) );
  2466. if ( pszName == NULL )
  2467. {
  2468. nStatus = GetLastError();
  2469. break;
  2470. } // if: error allocating resource type name buffer
  2471. nStatus = ClusterResourceControl(
  2472. hresDep,
  2473. NULL,
  2474. CLUSCTL_RESOURCE_GET_RESOURCE_TYPE,
  2475. NULL,
  2476. 0,
  2477. pszName,
  2478. cchmacName,
  2479. &cchName
  2480. );
  2481. } // if: buffer was too small
  2482. if ( nStatus != ERROR_SUCCESS )
  2483. {
  2484. break;
  2485. } // if: error getting resource type name
  2486. if ( lstrcmpiW( pszName, L"IP Address" ) == 0 )
  2487. {
  2488. //
  2489. // Get the private properties of the dependent resource.
  2490. //
  2491. cbProps = 1024;
  2492. pbProps = (PBYTE) LocalAlloc( LMEM_FIXED, cbProps );
  2493. if ( pbProps == NULL )
  2494. {
  2495. nStatus = GetLastError();
  2496. break;
  2497. } // if: error allocating buffer for properties
  2498. nStatus = ClusterResourceControl(
  2499. hresDep,
  2500. NULL,
  2501. CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES,
  2502. NULL,
  2503. 0,
  2504. pbProps,
  2505. cbProps,
  2506. &cbProps
  2507. );
  2508. if ( nStatus == ERROR_MORE_DATA )
  2509. {
  2510. LocalFree( pbProps );
  2511. pbProps = (PBYTE) LocalAlloc( LMEM_FIXED, cbProps );
  2512. if ( pbProps == NULL )
  2513. {
  2514. nStatus = GetLastError();
  2515. break;
  2516. } // if: error allocating buffer for properties
  2517. nStatus = ClusterResourceControl(
  2518. hresDep,
  2519. NULL,
  2520. CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES,
  2521. NULL,
  2522. 0,
  2523. pbProps,
  2524. cbProps,
  2525. &cbProps
  2526. );
  2527. } // if: properties buffer too small
  2528. if ( nStatus != ERROR_SUCCESS )
  2529. {
  2530. break;
  2531. } // if: error getting private properties
  2532. //
  2533. // Return the address.
  2534. //
  2535. if ( ( pszAddress != NULL )
  2536. || ( pcchAddress != NULL )
  2537. )
  2538. {
  2539. nStatus = ResUtilFindSzProperty(
  2540. pbProps,
  2541. cbProps,
  2542. L"Address",
  2543. &pszProp
  2544. );
  2545. if ( nStatus != ERROR_SUCCESS )
  2546. {
  2547. break;
  2548. } // if: error finding the property
  2549. cchProp = lstrlenW( pszProp ) + 1;
  2550. if ( cchProp > *pcchAddress )
  2551. {
  2552. if ( pszAddress == NULL )
  2553. {
  2554. nStatus = ERROR_SUCCESS;
  2555. } // if: no buffer was specified
  2556. else
  2557. {
  2558. nStatus = ERROR_MORE_DATA;
  2559. } // else: buffer was specified but was too small
  2560. *pcchAddress = cchProp;
  2561. break;
  2562. } // if: buffer is too small
  2563. lstrcpyW( pszAddress, pszProp );
  2564. *pcchAddress = cchProp;
  2565. } // if: address requested by caller
  2566. //
  2567. // Return the subnet mask.
  2568. //
  2569. if ( ( pszSubnetMask != NULL )
  2570. || ( pcchSubnetMask != NULL )
  2571. )
  2572. {
  2573. nStatus = ResUtilFindSzProperty(
  2574. pbProps,
  2575. cbProps,
  2576. L"SubnetMask",
  2577. &pszProp
  2578. );
  2579. if ( nStatus != ERROR_SUCCESS )
  2580. {
  2581. break;
  2582. } // if: error finding the property
  2583. cchProp = lstrlenW( pszProp ) + 1;
  2584. if ( cchProp > *pcchSubnetMask )
  2585. {
  2586. if ( pszSubnetMask == NULL )
  2587. {
  2588. nStatus = ERROR_SUCCESS;
  2589. } // if: no buffer was specified
  2590. else
  2591. {
  2592. nStatus = ERROR_MORE_DATA;
  2593. } // else: buffer was specified but was too small
  2594. *pcchSubnetMask = cchProp;
  2595. break;
  2596. } // if: buffer is too small
  2597. lstrcpyW( pszSubnetMask, pszProp );
  2598. *pcchSubnetMask = cchProp;
  2599. } // if: subnet mask requested by caller
  2600. //
  2601. // Return the network.
  2602. //
  2603. if ( ( pszNetwork != NULL )
  2604. || ( pcchNetwork != NULL )
  2605. )
  2606. {
  2607. nStatus = ResUtilFindSzProperty(
  2608. pbProps,
  2609. cbProps,
  2610. L"Network",
  2611. &pszProp
  2612. );
  2613. if ( nStatus != ERROR_SUCCESS )
  2614. {
  2615. break;
  2616. } // if: error finding the property
  2617. cchProp = lstrlenW( pszProp ) + 1;
  2618. if ( cchProp > *pcchNetwork )
  2619. {
  2620. if ( pszNetwork == NULL )
  2621. {
  2622. nStatus = ERROR_SUCCESS;
  2623. } // if: no buffer was specified
  2624. else
  2625. {
  2626. nStatus = ERROR_MORE_DATA;
  2627. } // else: buffer was specified but was too small
  2628. *pcchNetwork = cchProp;
  2629. break;
  2630. } // if: buffer is too small
  2631. lstrcpyW( pszNetwork, pszProp );
  2632. *pcchNetwork = cchProp;
  2633. } // if: network requested by caller
  2634. //
  2635. // Exit the loop since we found a match.
  2636. //
  2637. break;
  2638. } // if: IP Address resource found
  2639. //
  2640. // Close the dependent resource.
  2641. //
  2642. CloseClusterResource( hresDep );
  2643. hresDep = NULL;
  2644. } // for: each dependency
  2645. } while ( 0 );
  2646. //
  2647. // Cleanup.
  2648. //
  2649. LocalFree( pszName );
  2650. LocalFree( pbProps );
  2651. if ( hresenum != NULL )
  2652. {
  2653. ClusterResourceCloseEnum( hresenum );
  2654. } // if: we opened the enumerator
  2655. if ( hresDep != NULL )
  2656. {
  2657. CloseClusterResource( hresDep );
  2658. } // if: opened dependent resource
  2659. return nStatus;
  2660. } //*** ResUtilGetResourceDependentIPAddressProps()
  2661. /////////////////////////////////////////////////////////////////////////////
  2662. //++
  2663. //
  2664. // ResUtilFindDependentDiskResourceDriveLetter
  2665. //
  2666. // Description:
  2667. // Finds a disk resource in the dependent resources and retrieves the
  2668. // the drive letter associated with it.
  2669. //
  2670. // Arguments:
  2671. // hCluster [IN]
  2672. // Handle to the cluster.
  2673. //
  2674. // hResource [IN]
  2675. // Handle to the resource to query for dependencies.
  2676. //
  2677. // pszDriveLetter [IN/RETVAL]
  2678. // The drive letter of a dependent disk resource that was found.
  2679. // If a resource is not found, this value is untouched.
  2680. //
  2681. // pcchDriverLetter [IN/OUT]
  2682. // [IN] The number of characters that pszDriverLetter points to.
  2683. // [OUT] The number of characters written to the buffer
  2684. // (including NULL). If ERROR_MORE_DATA is returned, this value
  2685. // is the size of the buffer required to store the value.
  2686. //
  2687. // Return Value:
  2688. // ERROR_SUCCESS
  2689. // The function completed successfully and the drive letter was
  2690. // set.
  2691. //
  2692. // ERROR_NO_MORE_ITEMS
  2693. // ERROR_RESOURCE_NOT_PRESENT
  2694. // A dependent disk resource was not found or the resource is
  2695. // not dependent on a disk resource.
  2696. //
  2697. // ERROR_MORE_DATA
  2698. // The buffer passed in is too small. pcchDriveLetter will
  2699. // contain the size of the buffer (WCHARs) needed to fulfill
  2700. // the request.
  2701. //
  2702. // Win32 error code
  2703. // Other possible failures.
  2704. //
  2705. // SPECIAL NOTE:
  2706. // Do _NOT_ call this from a Resource DLL. It will cause a deadlock.
  2707. // You should have your Resource Extension call this function and
  2708. // write the results out as a private property that your Resource
  2709. // DLL can then read.
  2710. //
  2711. //--
  2712. /////////////////////////////////////////////////////////////////////////////
  2713. DWORD WINAPI ResUtilFindDependentDiskResourceDriveLetter(
  2714. IN HCLUSTER hCluster, // handle to cluster
  2715. IN HRESOURCE hResource, // handle to resource to query for dependencies
  2716. IN LPWSTR pszDriveLetter, // buffer to store drive letter (ex. "X:")
  2717. IN OUT DWORD * pcchDriveLetter // IN size of the pszDriveLetter buffer, OUT size of buffer required
  2718. )
  2719. {
  2720. BOOL fFoundDriveLetter = FALSE;
  2721. DWORD status = ERROR_SUCCESS;
  2722. HRESENUM hresenum;
  2723. DWORD cchName;
  2724. DWORD dwRetType;
  2725. WCHAR szName[ MAX_PATH ];
  2726. INT iCount;
  2727. // validate arguments
  2728. if ( !pszDriveLetter
  2729. || !pcchDriveLetter )
  2730. {
  2731. return ERROR_INVALID_PARAMETER;
  2732. }
  2733. hresenum = ClusterResourceOpenEnum( hResource, CLUSTER_RESOURCE_ENUM_DEPENDS );
  2734. if ( hresenum != NULL )
  2735. {
  2736. // Scan the dependencies until we find a disk resource or we hit
  2737. // the end of the dependency list.
  2738. for( iCount = 0 ; ! fFoundDriveLetter && ( status == ERROR_SUCCESS ) ; iCount++ )
  2739. {
  2740. cchName = sizeof(szName) / sizeof(szName[0]);
  2741. status = ClusterResourceEnum( hresenum, iCount, &dwRetType, szName, &cchName );
  2742. if ( status == ERROR_SUCCESS )
  2743. {
  2744. HRESOURCE hRes;
  2745. // Interrogate the resource to see if it is a disk resource.
  2746. hRes = OpenClusterResource( hCluster, szName );
  2747. if ( hRes != NULL )
  2748. {
  2749. DWORD cbDiskInfo = sizeof(CLUSPROP_DWORD)
  2750. + sizeof(CLUSPROP_SCSI_ADDRESS)
  2751. + sizeof(CLUSPROP_DISK_NUMBER)
  2752. + sizeof(CLUSPROP_PARTITION_INFO)
  2753. + sizeof(CLUSPROP_SYNTAX);
  2754. PBYTE pDiskInfo = (PBYTE) LocalAlloc( LMEM_FIXED, cbDiskInfo );
  2755. if ( !pDiskInfo )
  2756. {
  2757. status = ERROR_OUTOFMEMORY;
  2758. break;
  2759. } // if: !pDiskInfo
  2760. status = ClusterResourceControl( hRes,
  2761. NULL,
  2762. CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO,
  2763. NULL,
  2764. 0,
  2765. pDiskInfo,
  2766. cbDiskInfo,
  2767. &cbDiskInfo
  2768. );
  2769. if ( status == ERROR_MORE_DATA )
  2770. {
  2771. LocalFree( pDiskInfo );
  2772. // get a bigger block
  2773. pDiskInfo = (PBYTE) LocalAlloc( LMEM_FIXED, cbDiskInfo );
  2774. if ( !pDiskInfo )
  2775. {
  2776. status = ERROR_OUTOFMEMORY;
  2777. break;
  2778. } // if: !pDiskInfo
  2779. status = ClusterResourceControl( hRes,
  2780. NULL,
  2781. CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO,
  2782. NULL,
  2783. 0,
  2784. pDiskInfo,
  2785. cbDiskInfo,
  2786. &cbDiskInfo
  2787. );
  2788. } // if: more data
  2789. if ( status == ERROR_SUCCESS )
  2790. {
  2791. DWORD dwValueSize;
  2792. CLUSPROP_BUFFER_HELPER props;
  2793. PCLUSPROP_PARTITION_INFO pPartitionInfo;
  2794. props.pb = pDiskInfo;
  2795. // Loop through each property.
  2796. while ( ! fFoundDriveLetter
  2797. && ( status == ERROR_SUCCESS )
  2798. && ( cbDiskInfo > sizeof(CLUSPROP_SYNTAX ) )
  2799. && ( props.pSyntax->dw != CLUSPROP_SYNTAX_ENDMARK) )
  2800. {
  2801. // Get the size of this value and verify there is enough buffer left.
  2802. dwValueSize = sizeof(*props.pValue) + ALIGN_CLUSPROP( props.pValue->cbLength );
  2803. if ( dwValueSize > cbDiskInfo )
  2804. {
  2805. break;
  2806. } // if: data is not valid
  2807. if ( props.pSyntax->dw == CLUSPROP_SYNTAX_PARTITION_INFO )
  2808. {
  2809. // Validate the data. There must be a device name.
  2810. pPartitionInfo = props.pPartitionInfoValue;
  2811. if ( ( dwValueSize != sizeof(*pPartitionInfo) )
  2812. || ( pPartitionInfo->szDeviceName[0] == L'\0' ) )
  2813. {
  2814. break;
  2815. } // if: data is not valid
  2816. // Make sure it fits
  2817. if ( wcslen( pPartitionInfo->szDeviceName ) < *pcchDriveLetter )
  2818. {
  2819. wcscpy( pszDriveLetter, pPartitionInfo->szDeviceName );
  2820. fFoundDriveLetter = TRUE;
  2821. } // if: drive letter fits into buffer
  2822. else
  2823. {
  2824. status = ERROR_MORE_DATA;
  2825. } // else: does not fit into buffer
  2826. // set the size written and/or size needed
  2827. *pcchDriveLetter = wcslen( pPartitionInfo->szDeviceName ) + 1;
  2828. } // if props.pSyntax->dw
  2829. cbDiskInfo -= dwValueSize;
  2830. props.pb += dwValueSize;
  2831. } // while
  2832. } // if status
  2833. else if ( status == ERROR_INVALID_FUNCTION )
  2834. {
  2835. // Ignore resources that don't support the control
  2836. // code. Only storage-class resources will support
  2837. // the control code.
  2838. status = ERROR_SUCCESS;
  2839. } // else if: resource doesn't support the control code
  2840. LocalFree( pDiskInfo );
  2841. CloseClusterResource( hRes );
  2842. } // if hRes
  2843. } // if status
  2844. else if ( status == ERROR_NO_MORE_ITEMS )
  2845. {
  2846. break;
  2847. } // if status
  2848. } // for ( i )
  2849. ClusterResourceCloseEnum( hresenum );
  2850. } // if: opened hresenum
  2851. else
  2852. {
  2853. status = GetLastError( );
  2854. } // else: failed to open hresenum
  2855. // Make sure if we did not find a disk resource that we don't
  2856. // return ERROR_SUCCESS or ERROR_NO_MORE_ITEMS.
  2857. if ( ! fFoundDriveLetter
  2858. && ( ( status == ERROR_SUCCESS )
  2859. || ( status == ERROR_NO_MORE_ITEMS ) ) )
  2860. {
  2861. status = ERROR_RESOURCE_NOT_PRESENT;
  2862. } // if: sanity check
  2863. return status;
  2864. } //*** ResUtilFindDependentDiskResourceDriveLetter()
  2865. //////////////////////////////////////////////////////////////////////////////
  2866. //++
  2867. //
  2868. // ScIsResourceOfType()
  2869. //
  2870. // Description:
  2871. // Is the resource of the type passed in?
  2872. //
  2873. // Arguments:
  2874. //
  2875. //
  2876. // Return Value:
  2877. // S_OK
  2878. // The resource is of the type requested.
  2879. //
  2880. // S_FALSE
  2881. // The resource is not of the type requested.
  2882. //
  2883. // Other HRESULT
  2884. // Win32 error as HRESULT.
  2885. //
  2886. // Remarks:
  2887. // None.
  2888. //
  2889. //--
  2890. //////////////////////////////////////////////////////////////////////////////
  2891. static DWORD
  2892. ScIsResourceOfType(
  2893. HRESOURCE hResIn
  2894. , const WCHAR * pszResourceTypeIn
  2895. , BOOL * pbIsResourceOfTypeOut
  2896. )
  2897. {
  2898. DWORD sc;
  2899. WCHAR * psz = NULL;
  2900. DWORD cbpsz = 33 * sizeof( WCHAR );
  2901. DWORD cb;
  2902. int idx;
  2903. BOOL bIsResourceOfTypeOut = FALSE;
  2904. psz = (WCHAR *) LocalAlloc( LPTR, cbpsz );
  2905. if ( psz == NULL )
  2906. {
  2907. goto OutOfMemory;
  2908. } // if:
  2909. for ( idx = 0; idx < 2; idx++ )
  2910. {
  2911. sc = ClusterResourceControl( hResIn, NULL, CLUSCTL_RESOURCE_GET_RESOURCE_TYPE, NULL, 0, psz, cbpsz, &cb );
  2912. if ( sc == ERROR_MORE_DATA )
  2913. {
  2914. LocalFree( psz );
  2915. psz = NULL;
  2916. cbpsz = cb + 1;
  2917. psz = (WCHAR *) LocalAlloc( LPTR, cbpsz );
  2918. if ( psz == NULL )
  2919. {
  2920. goto OutOfMemory;
  2921. } // if:
  2922. continue;
  2923. } // if:
  2924. if ( sc != ERROR_SUCCESS )
  2925. {
  2926. goto Cleanup;
  2927. } // if:
  2928. break;
  2929. } // for:
  2930. bIsResourceOfTypeOut = ( wcscmp( psz, pszResourceTypeIn ) == 0 );
  2931. if ( pbIsResourceOfTypeOut != NULL )
  2932. {
  2933. *pbIsResourceOfTypeOut = bIsResourceOfTypeOut;
  2934. } // if:
  2935. else
  2936. {
  2937. sc = ERROR_INVALID_PARAMETER;
  2938. } // else
  2939. goto Cleanup;
  2940. OutOfMemory:
  2941. sc = ERROR_NOT_ENOUGH_MEMORY;
  2942. Cleanup:
  2943. LocalFree( psz );
  2944. return sc;
  2945. } //*** ScIsResourceOfType()
  2946. //////////////////////////////////////////////////////////////////////////////
  2947. //++
  2948. //
  2949. // ScIsCoreResource()
  2950. //
  2951. // Description:
  2952. // Is the passed in resource a core resource?
  2953. //
  2954. // Arguments:
  2955. //
  2956. //
  2957. // Return Value:
  2958. // ERROR_SUCCESS
  2959. // The operation succeeded.
  2960. //
  2961. // Other Win32 error
  2962. //
  2963. // Remarks:
  2964. // None.
  2965. //
  2966. //--
  2967. //////////////////////////////////////////////////////////////////////////////
  2968. static DWORD
  2969. ScIsCoreResource(
  2970. HRESOURCE hResIn
  2971. , BOOL * pfIsCoreResourceOut
  2972. )
  2973. {
  2974. DWORD sc;
  2975. DWORD dwFlags = 0;
  2976. DWORD cb;
  2977. BOOL fIsCoreResource = FALSE;
  2978. sc = ClusterResourceControl( hResIn, NULL, CLUSCTL_RESOURCE_GET_FLAGS, NULL, 0, &dwFlags, sizeof( dwFlags ), &cb );
  2979. if ( sc != ERROR_SUCCESS )
  2980. {
  2981. goto Cleanup;
  2982. } // if:
  2983. fIsCoreResource = ( dwFlags & CLUS_FLAG_CORE );
  2984. if ( pfIsCoreResourceOut != NULL )
  2985. {
  2986. *pfIsCoreResourceOut = fIsCoreResource;
  2987. } // if:
  2988. else
  2989. {
  2990. sc = ERROR_INVALID_PARAMETER;
  2991. } // else
  2992. Cleanup:
  2993. return sc;
  2994. } //*** ScIsCoreResource()
  2995. //////////////////////////////////////////////////////////////////////////////
  2996. //++
  2997. //
  2998. // ScIsQuorumCapableResource()
  2999. //
  3000. // Description:
  3001. // Is the passed in resource quorum capable?
  3002. //
  3003. // Arguments:
  3004. // hResIn
  3005. // The resource to check for quorum capability.
  3006. //
  3007. // pfIsQuorumCapableResource
  3008. // True if the resource is quorum capable, false if it is not.
  3009. //
  3010. // Return Value:
  3011. // ERROR_SUCCESS
  3012. // The operation succeeded.
  3013. //
  3014. // Other Win32 error
  3015. //
  3016. // Remarks:
  3017. // None.
  3018. //
  3019. //--
  3020. //////////////////////////////////////////////////////////////////////////////
  3021. static DWORD
  3022. ScIsQuorumCapableResource(
  3023. HRESOURCE hResIn
  3024. , BOOL * pfIsQuorumCapableResource
  3025. )
  3026. {
  3027. DWORD sc;
  3028. DWORD cb;
  3029. DWORD dwFlags = 0;
  3030. if ( hResIn == NULL )
  3031. {
  3032. sc = ERROR_INVALID_PARAMETER;
  3033. goto Cleanup;
  3034. } // if:
  3035. if ( pfIsQuorumCapableResource == NULL )
  3036. {
  3037. sc = ERROR_INVALID_PARAMETER;
  3038. goto Cleanup;
  3039. } // if:
  3040. sc = ClusterResourceControl( hResIn, NULL, CLUSCTL_RESOURCE_GET_CHARACTERISTICS, NULL, 0, &dwFlags, sizeof( dwFlags ), &cb );
  3041. if ( sc != ERROR_SUCCESS )
  3042. {
  3043. goto Cleanup;
  3044. } // if:
  3045. *pfIsQuorumCapableResource = ( dwFlags & CLUS_CHAR_QUORUM );
  3046. Cleanup:
  3047. return sc;
  3048. } //*** ScIsQuorumCapableResource()
  3049. static WCHAR * g_pszCoreResourceTypes[] =
  3050. {
  3051. L"Network Name",
  3052. L"IP Address",
  3053. L"\0"
  3054. };
  3055. #define CLUSTER_NAME 0
  3056. #define CLUSTER_IP_ADDRESS 1
  3057. //////////////////////////////////////////////////////////////////////////////
  3058. //++
  3059. //
  3060. // ResUtilGetCoreClusterResources()
  3061. //
  3062. // Description:
  3063. // Find the core cluster resources.
  3064. //
  3065. // Arguments:
  3066. // hClusterIn
  3067. // The cluster whose core resource are sought.
  3068. //
  3069. // phClusterNameResourceOut
  3070. // The resource handle of the cluster name resource.
  3071. //
  3072. // phClusterIPAddressResourceOut
  3073. // The resource handle of the cluster IP address resource.
  3074. //
  3075. // phClusterQuorumResourceOut
  3076. // The resource handle of the cluster quorum resource.
  3077. //
  3078. // Return Value:
  3079. // ERROR_SUCCESS or other Win32 error.
  3080. //
  3081. // Remarks:
  3082. // None.
  3083. //
  3084. //--
  3085. //////////////////////////////////////////////////////////////////////////////
  3086. DWORD
  3087. WINAPI
  3088. ResUtilGetCoreClusterResources(
  3089. HCLUSTER hClusterIn
  3090. , HRESOURCE * phClusterNameResourceOut
  3091. , HRESOURCE * phClusterIPAddressResourceOut
  3092. , HRESOURCE * phClusterQuorumResourceOut
  3093. )
  3094. {
  3095. DWORD sc;
  3096. HCLUSENUM hEnum = NULL;
  3097. DWORD idxResource;
  3098. DWORD idx;
  3099. DWORD dwType;
  3100. WCHAR * psz = NULL;
  3101. DWORD cchpsz = 33;
  3102. DWORD cch;
  3103. HRESOURCE hRes = NULL;
  3104. BOOL fIsCoreResource = FALSE;
  3105. BOOL fIsResourceOfType = FALSE;
  3106. BOOL fCloseResource = FALSE;
  3107. BOOL fIsQuorumCapableResource = FALSE;
  3108. if ( hClusterIn == NULL )
  3109. {
  3110. sc = ERROR_INVALID_PARAMETER;
  3111. goto Cleanup;
  3112. } // if:
  3113. hEnum = ClusterOpenEnum( hClusterIn, CLUSTER_ENUM_RESOURCE );
  3114. if ( hEnum == NULL )
  3115. {
  3116. sc = GetLastError();
  3117. goto Cleanup;
  3118. } // if:
  3119. psz = (WCHAR *) LocalAlloc( LPTR, cchpsz * sizeof( WCHAR ) );
  3120. if ( psz == NULL )
  3121. {
  3122. sc = ERROR_NOT_ENOUGH_MEMORY;
  3123. goto Cleanup;
  3124. } // if:
  3125. //
  3126. // KB: 10-JUL-2002 GalenB
  3127. //
  3128. // Using cch in the ClusterEnum() call below because using cchpsz causes extra allocations.
  3129. // ClusterEnum() changes cch when the buffer is big enough to hold the data and returns
  3130. // ERROR_SUCCESS to be the size of the data that was just copied into the buffer. Now
  3131. // cch no longer reflects the amount of memory allocated to psz...
  3132. //
  3133. for ( idxResource = 0; ; )
  3134. {
  3135. //
  3136. // Reset cch to the real size of the buffer to avoid extra allocations...
  3137. //
  3138. cch = cchpsz;
  3139. sc = ClusterEnum( hEnum, idxResource, &dwType, psz, &cch );
  3140. if ( sc == ERROR_MORE_DATA )
  3141. {
  3142. LocalFree( psz );
  3143. psz = NULL;
  3144. cch++; // need space for the NULL...
  3145. cchpsz = cch;
  3146. psz = (WCHAR *) LocalAlloc( LPTR, cchpsz * sizeof( WCHAR ) );
  3147. if ( psz == NULL )
  3148. {
  3149. sc = ERROR_NOT_ENOUGH_MEMORY;
  3150. goto Cleanup;
  3151. } // if:
  3152. sc = ClusterEnum( hEnum, idxResource, &dwType, psz, &cch );
  3153. } // if: sc == ERROR_MORE_DATA
  3154. if ( sc == ERROR_SUCCESS )
  3155. {
  3156. hRes = OpenClusterResource( hClusterIn, psz );
  3157. if ( hRes == NULL )
  3158. {
  3159. sc = GetLastError();
  3160. goto Cleanup;
  3161. } // if:
  3162. fCloseResource = TRUE;
  3163. sc = ScIsCoreResource( hRes, &fIsCoreResource );
  3164. if ( sc != ERROR_SUCCESS )
  3165. {
  3166. goto Cleanup;
  3167. } // if:
  3168. //
  3169. // If the resource is not a core resource then close it and go around again.
  3170. //
  3171. if ( !fIsCoreResource )
  3172. {
  3173. CloseClusterResource( hRes );
  3174. hRes = NULL;
  3175. idxResource++;
  3176. continue;
  3177. } // if:
  3178. sc = ScIsQuorumCapableResource( hRes, &fIsQuorumCapableResource );
  3179. if ( sc != ERROR_SUCCESS )
  3180. {
  3181. goto Cleanup;
  3182. } // if:
  3183. //
  3184. // If this core resource is a quorum capable resource then it must be the quorom. If the caller
  3185. // has asked for the quorom resource then pass it back and leave the resource open, other wise
  3186. // close the resource and go around again.
  3187. //
  3188. if ( fIsQuorumCapableResource )
  3189. {
  3190. if ( phClusterQuorumResourceOut != NULL)
  3191. {
  3192. *phClusterQuorumResourceOut = hRes;
  3193. } // if:
  3194. else
  3195. {
  3196. CloseClusterResource( hRes );
  3197. } // else:
  3198. hRes = NULL;
  3199. idxResource++;
  3200. continue;
  3201. } // if:
  3202. //
  3203. // Since this core resource is not a quorum capable resource it is either the cluster
  3204. // name or the cluster IP address resource.
  3205. //
  3206. for ( idx = 0; *( g_pszCoreResourceTypes[ idx ] ) != '\0'; idx++ )
  3207. {
  3208. sc = ScIsResourceOfType( hRes, g_pszCoreResourceTypes[ idx ], &fIsResourceOfType );
  3209. if ( sc != ERROR_SUCCESS )
  3210. {
  3211. goto Cleanup;
  3212. } // if:
  3213. if ( !fIsResourceOfType )
  3214. {
  3215. continue;
  3216. } // if:
  3217. switch ( idx )
  3218. {
  3219. case CLUSTER_NAME :
  3220. if ( phClusterNameResourceOut != NULL )
  3221. {
  3222. *phClusterNameResourceOut = hRes;
  3223. fCloseResource = FALSE;
  3224. } // if:
  3225. break;
  3226. case CLUSTER_IP_ADDRESS :
  3227. if ( phClusterIPAddressResourceOut != NULL )
  3228. {
  3229. *phClusterIPAddressResourceOut = hRes;
  3230. fCloseResource = FALSE;
  3231. } // if:
  3232. break;
  3233. default:
  3234. goto Cleanup;
  3235. } // switch:
  3236. //
  3237. // If we get here then we broke from the switch above and we want out of
  3238. // this loop.
  3239. //
  3240. break;
  3241. } // for:
  3242. if ( fCloseResource )
  3243. {
  3244. CloseClusterResource( hRes );
  3245. } // if:
  3246. hRes = NULL;
  3247. idxResource++;
  3248. continue;
  3249. } // if: sc == ERROR_SUCCESS
  3250. else if ( sc == ERROR_NO_MORE_ITEMS )
  3251. {
  3252. sc = ERROR_SUCCESS;
  3253. break;
  3254. } // else if: sc == ERROR_NO_MORE_ITEMS
  3255. else
  3256. {
  3257. goto Cleanup;
  3258. } // else: sc has some other error...
  3259. break;
  3260. } // for:
  3261. Cleanup:
  3262. LocalFree( psz );
  3263. if ( hRes != NULL )
  3264. {
  3265. CloseClusterResource( hRes );
  3266. } // if:
  3267. if ( hEnum != NULL )
  3268. {
  3269. ClusterCloseEnum( hEnum );
  3270. } // if:
  3271. return sc;
  3272. } //*** ResUtilGetCoreClusterResources
  3273. //////////////////////////////////////////////////////////////////////////////
  3274. //++
  3275. //
  3276. // ResUtilGetResourceName()
  3277. //
  3278. // Description:
  3279. // Get the name of the resource that is passed in.
  3280. //
  3281. // Arguments:
  3282. // hResourceIn
  3283. // The resource whose name is sought.
  3284. //
  3285. // pszResourceNameOut
  3286. // Buffer to hold the resource's name.
  3287. //
  3288. // pcchResourceNameInOut
  3289. // The size of the buffer on input and the size required on output.
  3290. //
  3291. //
  3292. // Return Value:
  3293. // ERROR_SUCCESS
  3294. // ERROR_MORE_DATA
  3295. //
  3296. // Remarks:
  3297. // None.
  3298. //
  3299. //--
  3300. //////////////////////////////////////////////////////////////////////////////
  3301. DWORD
  3302. WINAPI
  3303. ResUtilGetResourceName(
  3304. HRESOURCE hResourceIn
  3305. , WCHAR * pszResourceNameOut
  3306. , DWORD * pcchResourceNameInOut
  3307. )
  3308. {
  3309. DWORD sc = ERROR_INVALID_PARAMETER;
  3310. WCHAR * psz = NULL;
  3311. DWORD cb;
  3312. if ( hResourceIn == NULL )
  3313. {
  3314. goto Bail;
  3315. } // if:
  3316. if ( ( pszResourceNameOut == NULL ) || ( pcchResourceNameInOut == NULL ) )
  3317. {
  3318. goto Bail;
  3319. } // if:
  3320. psz = (WCHAR *) LocalAlloc( LPTR, (*pcchResourceNameInOut) * sizeof( WCHAR ) );
  3321. if ( psz == NULL )
  3322. {
  3323. goto OutOfMemory;
  3324. } // if:
  3325. sc = ClusterResourceControl(
  3326. hResourceIn
  3327. , NULL
  3328. , CLUSCTL_RESOURCE_GET_NAME
  3329. , NULL
  3330. , 0
  3331. , psz
  3332. , (*pcchResourceNameInOut) * sizeof( WCHAR )
  3333. , &cb
  3334. );
  3335. if ( sc == ERROR_MORE_DATA )
  3336. {
  3337. *pcchResourceNameInOut = ( cb / sizeof( WCHAR ) ) + 1;
  3338. goto Cleanup;
  3339. } // if:
  3340. if ( sc != ERROR_SUCCESS )
  3341. {
  3342. goto Cleanup;
  3343. } // if:
  3344. wcsncpy( pszResourceNameOut, psz, *pcchResourceNameInOut );
  3345. goto Cleanup;
  3346. OutOfMemory:
  3347. sc = ERROR_NOT_ENOUGH_MEMORY;
  3348. Cleanup:
  3349. LocalFree( psz );
  3350. Bail:
  3351. return sc;
  3352. } //*** ResUtilGetResourceName