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.

1019 lines
29 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. services.c
  5. Abstract:
  6. Routines to deal with the Windows NT service controller
  7. and service entries in the registry,
  8. Externally exposed routines:
  9. MyCreateService
  10. MyChangeServiceStart
  11. MyChangeServiceConfig
  12. Author:
  13. Ted Miller (tedm) 5-Apr-1995
  14. adapted from legacy\dll\sc.c
  15. Revision History:
  16. Dan Elliott (dane) 14-Aug-2000 Added WaitForScmInitialization().
  17. --*/
  18. #include "setupp.h"
  19. #pragma hdrstop
  20. //
  21. // Constants used in logging specific to this module.
  22. //
  23. PCWSTR szOpenSCManager = L"OpenSCManager";
  24. PCWSTR szCreateService = L"CreateService";
  25. PCWSTR szChangeServiceConfig = L"ChangeServiceConfig";
  26. PCWSTR szOpenService = L"OpenService";
  27. PCWSTR szStartService = L"StartService";
  28. PCWSTR szEnumDependentService= L"EnumDependentService";
  29. PCWSTR szServicesKeyPath = L"SYSTEM\\CurrentControlSet\\Services";
  30. PCWSTR szDependOnService = L"DependOnService";
  31. PCWSTR szServicesToRename = L"ServicesToRename";
  32. BOOL
  33. pSetupWaitForScmInitialization()
  34. /*++
  35. Routine Description:
  36. Wait for services.exe to signal that the Services Control Manager is
  37. running and autostart services have been started.
  38. Arguments:
  39. None.
  40. Return value:
  41. Boolean indicating whether the the SCM was started successfully.
  42. --*/
  43. {
  44. HANDLE hEventHandle;
  45. DWORD WaitStatus;
  46. hEventHandle = OpenEvent( SYNCHRONIZE, FALSE, SC_AUTOSTART_EVENT_NAME );
  47. if( hEventHandle != NULL ) {
  48. SetupDebugPrint1(L"SETUP: Waiting on event %ls \n", SC_AUTOSTART_EVENT_NAME );
  49. WaitStatus = WaitForSingleObject( hEventHandle, INFINITE );
  50. if( WaitStatus != WAIT_FAILED ) {
  51. if( WaitStatus == WAIT_OBJECT_0 ) {
  52. SetupDebugPrint1(L"SETUP: Wait on event %ls completed successfully \n", SC_AUTOSTART_EVENT_NAME );
  53. } else {
  54. SetupDebugPrint2(L"SETUP: Wait on event %ls failed. WaitStatus = %d \n", SC_AUTOSTART_EVENT_NAME, WaitStatus );
  55. }
  56. } else {
  57. DWORD Error;
  58. Error = GetLastError();
  59. SetupDebugPrint2(L"SETUP: Wait on event %ls failed. Error = %d \n", SC_AUTOSTART_EVENT_NAME, Error );
  60. }
  61. CloseHandle( hEventHandle );
  62. }
  63. else {
  64. return FALSE;
  65. }
  66. return (WAIT_OBJECT_0 == WaitStatus);
  67. }
  68. BOOL
  69. MyCreateService(
  70. IN PCWSTR ServiceName,
  71. IN PCWSTR DisplayName, OPTIONAL
  72. IN DWORD ServiceType,
  73. IN DWORD StartType,
  74. IN DWORD ErrorControl,
  75. IN PCWSTR BinaryPathName,
  76. IN PCWSTR LoadOrderGroup, OPTIONAL
  77. IN PWCHAR DependencyList,
  78. IN PCWSTR ServiceStartName, OPTIONAL
  79. IN PCWSTR Password OPTIONAL
  80. )
  81. /*++
  82. Routine Description:
  83. Stub for calling CreateService. If CreateService fails with
  84. the error code indicating that the service already exists, this routine
  85. calls the routine for ChangeServiceConfig to ensure that the
  86. parameters passed in are reflected in the services database.
  87. Arguments:
  88. ServiceName - Name of service
  89. DisplayName - Localizable name of Service or ""
  90. ServiceType - Service type, e.g. SERVICE_KERNEL_DRIVER
  91. StartType - Service Start value, e.g. SERVICE_BOOT_START
  92. ErrorControl - Error control value, e.g. SERVICE_ERROR_NORMAL
  93. BinaryPathName - Full Path of the binary image containing service
  94. LoadOrderGroup - Group name for load ordering or ""
  95. Dependencies - MultiSz list of dependencies for this service. Any dependency
  96. component having + as the first character is a group dependency.
  97. The others are service dependencies.
  98. ServiceStartName - Service Start name (account name in which this service is run).
  99. Password - Password used for starting the service.
  100. Return value:
  101. Boolean value indicating outcome.
  102. --*/
  103. {
  104. SC_HANDLE hSC;
  105. SC_HANDLE hSCService;
  106. DWORD dwTag,dw;
  107. BOOL b;
  108. //
  109. // Open a handle to the service controller manager
  110. //
  111. hSC = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
  112. if(hSC == NULL) {
  113. SetuplogError(
  114. LogSevWarning,
  115. SETUPLOG_USE_MESSAGEID,
  116. MSG_LOG_CREATESVC_FAIL,
  117. ServiceName, NULL,
  118. SETUPLOG_USE_MESSAGEID,
  119. MSG_LOG_X_RETURNED_WINERR,
  120. szOpenSCManager,
  121. GetLastError(),
  122. NULL,NULL);
  123. return(FALSE);
  124. }
  125. //
  126. // Process the optional "" parameters passed in and make them NULL.
  127. //
  128. if(DisplayName && !DisplayName[0]) {
  129. DisplayName = NULL;
  130. }
  131. if(LoadOrderGroup && !LoadOrderGroup[0]) {
  132. LoadOrderGroup = NULL;
  133. }
  134. if(ServiceStartName && !ServiceStartName[0]) {
  135. ServiceStartName = NULL;
  136. }
  137. if(Password && !Password[0]) {
  138. Password = NULL;
  139. }
  140. //
  141. // Create the service.
  142. //
  143. hSCService = CreateService(
  144. hSC,
  145. ServiceName,
  146. DisplayName,
  147. 0,
  148. ServiceType,
  149. StartType,
  150. ErrorControl,
  151. BinaryPathName,
  152. LoadOrderGroup,
  153. LoadOrderGroup ? &dwTag : NULL,
  154. DependencyList,
  155. ServiceStartName,
  156. Password
  157. );
  158. //
  159. // If we were unable to create the service, check if the service already
  160. // exists in which case all we need to do is change the configuration
  161. // parameters in the service.
  162. //
  163. if(hSCService) {
  164. //
  165. // Note that we won't do anything with the tag.
  166. //
  167. CloseServiceHandle(hSCService);
  168. b = TRUE;
  169. } else {
  170. if((dw = GetLastError()) == ERROR_SERVICE_EXISTS) {
  171. b = MyChangeServiceConfig(
  172. ServiceName,
  173. ServiceType,
  174. StartType,
  175. ErrorControl,
  176. BinaryPathName,
  177. LoadOrderGroup,
  178. DependencyList,
  179. ServiceStartName,
  180. Password,
  181. DisplayName
  182. );
  183. } else {
  184. SetuplogError(
  185. LogSevWarning,
  186. SETUPLOG_USE_MESSAGEID,
  187. MSG_LOG_CREATESVC_FAIL,
  188. ServiceName, NULL,
  189. SETUPLOG_USE_MESSAGEID,
  190. MSG_LOG_X_RETURNED_WINERR,
  191. szCreateService,
  192. dw,
  193. NULL,NULL);
  194. b = FALSE;
  195. }
  196. }
  197. CloseServiceHandle(hSC);
  198. return(b);
  199. }
  200. BOOL
  201. MyChangeServiceConfig(
  202. IN PCWSTR ServiceName,
  203. IN DWORD ServiceType,
  204. IN DWORD StartType,
  205. IN DWORD ErrorControl,
  206. IN PCWSTR BinaryPathName, OPTIONAL
  207. IN PCWSTR LoadOrderGroup, OPTIONAL
  208. IN PWCHAR DependencyList,
  209. IN PCWSTR ServiceStartName, OPTIONAL
  210. IN PCWSTR Password, OPTIONAL
  211. IN PCWSTR DisplayName OPTIONAL
  212. )
  213. /*++
  214. Routine Description:
  215. Wrapper for ChangeServiceConfig.
  216. Arguments:
  217. ServiceName - Name of service
  218. ServiceType - Service type, e.g. SERVICE_KERNEL_DRIVER
  219. StartType - Service Start value, e.g. SERVICE_BOOT_START
  220. ErrorControl - Error control value, e.g. SERVICE_ERROR_NORMAL
  221. BinaryPathName - Full Path of the binary image containing service
  222. LoadOrderGroup - Group name for load ordering
  223. DependencyList - Multisz string having dependencies. Any dependency
  224. component having + as the first character is a
  225. group dependency. The others are service dependencies.
  226. ServiceStartName - Service Start name (account name in which this
  227. service is run).
  228. Password - Password used for starting the service.
  229. DisplayName - Localizable name of Service.
  230. Return value:
  231. Boolean value indicating outcome.
  232. --*/
  233. {
  234. SC_LOCK sclLock;
  235. SC_HANDLE hSC;
  236. SC_HANDLE hSCService;
  237. DWORD dw;
  238. BOOL b;
  239. //
  240. // Open a handle to the service controller manager
  241. //
  242. hSC = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
  243. if(hSC == NULL) {
  244. SetuplogError(
  245. LogSevWarning,
  246. SETUPLOG_USE_MESSAGEID,
  247. MSG_LOG_CHANGESVC_FAIL,
  248. ServiceName, NULL,
  249. SETUPLOG_USE_MESSAGEID,
  250. MSG_LOG_X_RETURNED_WINERR,
  251. szOpenSCManager,
  252. GetLastError(),
  253. NULL,NULL);
  254. return(FALSE);
  255. }
  256. //
  257. // Try to lock the database, if possible. If we are not able to lock
  258. // the database we will still modify the services entry. This is because
  259. // we are just modifying a single service and chances are very low that
  260. // anybody else is manipulating the same entry at the same time.
  261. //
  262. SetupDebugPrint1(L"MyChangeServiceConfig: LockingServiceDatabase for service %s", ServiceName);
  263. sclLock = LockServiceDatabase(hSC);
  264. //
  265. // Process optional parameters
  266. //
  267. if(BinaryPathName && !BinaryPathName[0]) {
  268. BinaryPathName = NULL;
  269. }
  270. if(LoadOrderGroup && !LoadOrderGroup[0]) {
  271. LoadOrderGroup = NULL;
  272. }
  273. if(ServiceStartName && !ServiceStartName[0]) {
  274. ServiceStartName = NULL;
  275. }
  276. if(Password && !Password[0]) {
  277. Password = NULL;
  278. }
  279. if(DisplayName && !DisplayName[0]) {
  280. DisplayName = NULL;
  281. }
  282. //
  283. // Open the service with SERVICE_CHANGE_CONFIG access
  284. //
  285. if(hSCService = OpenService(hSC,ServiceName,SERVICE_CHANGE_CONFIG)) {
  286. b = ChangeServiceConfig(
  287. hSCService,
  288. ServiceType,
  289. StartType,
  290. ErrorControl,
  291. BinaryPathName,
  292. LoadOrderGroup,
  293. NULL,
  294. DependencyList,
  295. ServiceStartName,
  296. Password,
  297. DisplayName
  298. );
  299. if(!b) {
  300. SetuplogError(
  301. LogSevWarning,
  302. SETUPLOG_USE_MESSAGEID,
  303. MSG_LOG_CHANGESVC_FAIL,
  304. ServiceName, NULL,
  305. SETUPLOG_USE_MESSAGEID,
  306. MSG_LOG_X_RETURNED_WINERR,
  307. szChangeServiceConfig,
  308. GetLastError(),
  309. NULL,NULL);
  310. }
  311. CloseServiceHandle(hSCService);
  312. } else {
  313. b = FALSE;
  314. SetuplogError(
  315. LogSevWarning,
  316. SETUPLOG_USE_MESSAGEID,
  317. MSG_LOG_CHANGESVC_FAIL,
  318. ServiceName, NULL,
  319. SETUPLOG_USE_MESSAGEID,
  320. MSG_LOG_X_RETURNED_WINERR,
  321. szOpenService,
  322. GetLastError(),
  323. NULL,NULL);
  324. }
  325. //
  326. // Unlock the database if locked and then close the service controller
  327. // handle
  328. //
  329. if(sclLock) {
  330. UnlockServiceDatabase(sclLock);
  331. SetupDebugPrint1(L"MyChangeServiceConfig: Unlocked ServiceDatabase for service %s", ServiceName);
  332. }
  333. CloseServiceHandle(hSC);
  334. return(b);
  335. }
  336. BOOL
  337. MyChangeServiceStart(
  338. IN PCWSTR ServiceName,
  339. IN DWORD StartType
  340. )
  341. /*++
  342. Routine Description:
  343. Routine to change the start value of a service. This turns
  344. around and calls the stub to ChangeServiceConfig.
  345. Arguments:
  346. ServiceName - Name of service
  347. StartType - Service Start value, e.g. SERVICE_BOOT_START
  348. Return value:
  349. Boolean value indicating outcome.
  350. --*/
  351. {
  352. BOOL b;
  353. b = MyChangeServiceConfig(
  354. ServiceName,
  355. SERVICE_NO_CHANGE,
  356. StartType,
  357. SERVICE_NO_CHANGE,
  358. NULL,
  359. NULL,
  360. NULL,
  361. NULL,
  362. NULL,
  363. NULL
  364. );
  365. return(b);
  366. }
  367. BOOL
  368. SetupStartService(
  369. IN PCWSTR ServiceName,
  370. IN BOOLEAN Wait // if TRUE, try to wait until it is started.
  371. )
  372. {
  373. SC_HANDLE hSC,hSCService;
  374. BOOL b;
  375. DWORD d;
  376. DWORD dwDesiredAccess;
  377. b = FALSE;
  378. //
  379. // Open a handle to the service controller manager
  380. //
  381. hSC = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
  382. if(hSC == NULL) {
  383. SetuplogError(
  384. LogSevWarning,
  385. SETUPLOG_USE_MESSAGEID,
  386. MSG_LOG_STARTSVC_FAIL,
  387. ServiceName, NULL,
  388. SETUPLOG_USE_MESSAGEID,
  389. MSG_LOG_X_RETURNED_WINERR,
  390. szOpenSCManager,
  391. GetLastError(),
  392. NULL,NULL);
  393. return(FALSE);
  394. }
  395. if (Wait) {
  396. dwDesiredAccess = SERVICE_START | SERVICE_QUERY_STATUS;
  397. } else {
  398. dwDesiredAccess = SERVICE_START;
  399. }
  400. if(hSCService = OpenService(hSC,ServiceName,dwDesiredAccess)) {
  401. SetupDebugPrint1(L"SetupStartService: Sending StartService to <%ws>\n", ServiceName);
  402. b = StartService(hSCService,0,NULL);
  403. SetupDebugPrint1(L"SetupStartService: Sent StartService to <%ws>\n", ServiceName);
  404. if(!b && ((d = GetLastError()) == ERROR_SERVICE_ALREADY_RUNNING)) {
  405. //
  406. // Service is already running.
  407. //
  408. b = TRUE;
  409. }
  410. if(!b) {
  411. SetuplogError(
  412. LogSevWarning,
  413. SETUPLOG_USE_MESSAGEID,
  414. MSG_LOG_STARTSVC_FAIL,
  415. ServiceName, NULL,
  416. SETUPLOG_USE_MESSAGEID,
  417. MSG_LOG_X_PARAM_RETURNED_WINERR,
  418. szStartService,
  419. d,
  420. ServiceName,
  421. NULL,NULL);
  422. }
  423. if (b && Wait) {
  424. #define SLEEP_TIME 4000
  425. #define LOOP_COUNT 30
  426. SERVICE_STATUS ssStatus;
  427. DWORD loopCount = 0;
  428. //SetupDebugPrint(L" )) Looping waiting for start\n");
  429. do {
  430. b = QueryServiceStatus( hSCService, &ssStatus);
  431. if ( !b ) {
  432. //SetupDebugPrint(L"FAILED %d\n", GetLastError());
  433. break;
  434. }
  435. if (ssStatus.dwCurrentState == SERVICE_START_PENDING) {
  436. //SetupDebugPrint(L"PENDING\n");
  437. if ( loopCount++ == LOOP_COUNT ) {
  438. //SetupDebugPrint2(L"SYSSETUP: STILL PENDING after %d times: <%ws> service\n", loopCount, ServiceName);
  439. break;
  440. }
  441. Sleep( SLEEP_TIME );
  442. } else {
  443. //SetupDebugPrint3(L"SYSSETUP: WAITED %d times: <%ws> service, status %d\n", loopCount, ServiceName, ssStatus.dwCurrentState);
  444. break;
  445. }
  446. } while ( TRUE );
  447. }
  448. CloseServiceHandle(hSCService);
  449. } else {
  450. b = FALSE;
  451. SetuplogError(
  452. LogSevWarning,
  453. SETUPLOG_USE_MESSAGEID,
  454. MSG_LOG_STARTSVC_FAIL,
  455. ServiceName, NULL,
  456. SETUPLOG_USE_MESSAGEID,
  457. MSG_LOG_X_PARAM_RETURNED_WINERR,
  458. szOpenService,
  459. GetLastError(),
  460. ServiceName,
  461. NULL,NULL);
  462. }
  463. CloseServiceHandle(hSC);
  464. return(b);
  465. }
  466. BOOL
  467. FixServiceDependency(
  468. IN PCWSTR ServiceName,
  469. IN PCWSTR OldDependencyName,
  470. IN PCWSTR NewDependencyName
  471. )
  472. {
  473. ULONG Error;
  474. HKEY hKey;
  475. WCHAR ServicePath[ MAX_PATH + 1 ];
  476. PBYTE OldValueData;
  477. PBYTE NewValueData;
  478. ULONG OldValueSize;
  479. ULONG NewValueSize;
  480. DWORD Type;
  481. PBYTE p,q;
  482. BOOL ChangeDependencyList;
  483. //
  484. // Open the key that describes the service
  485. //
  486. lstrcpy( ServicePath, szServicesKeyPath );
  487. pSetupConcatenatePaths(ServicePath,ServiceName,sizeof( ServicePath )/sizeof( WCHAR ),NULL);
  488. Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  489. ServicePath,
  490. 0,
  491. KEY_READ | KEY_WRITE,
  492. &hKey );
  493. if( Error != ERROR_SUCCESS ) {
  494. SetuplogError(
  495. LogSevWarning,
  496. SETUPLOG_USE_MESSAGEID,
  497. MSG_LOG_FIX_SERVICE_FAILED,
  498. ServiceName, NULL,
  499. SETUPLOG_USE_MESSAGEID,
  500. MSG_LOG_X_PARAM_RETURNED_WINERR,
  501. szRegOpenKeyEx,
  502. Error,
  503. ServicePath,
  504. NULL,NULL);
  505. return( FALSE );
  506. }
  507. //
  508. // Allocate a buffer for the old value data
  509. //
  510. OldValueSize = 0;
  511. Error = RegQueryValueEx(hKey,
  512. szDependOnService,
  513. NULL,
  514. &Type,
  515. NULL,
  516. &OldValueSize);
  517. if( ( Error != ERROR_SUCCESS ) && ( Error != ERROR_MORE_DATA ) ) {
  518. SetuplogError(
  519. LogSevWarning,
  520. SETUPLOG_USE_MESSAGEID,
  521. MSG_LOG_FIX_SERVICE_FAILED,
  522. ServiceName, NULL,
  523. SETUPLOG_USE_MESSAGEID,
  524. MSG_LOG_X_PARAM_RETURNED_WINERR,
  525. szRegQueryValueEx,
  526. Error,
  527. szDependOnService,
  528. NULL,NULL);
  529. RegCloseKey( hKey );
  530. return( FALSE );
  531. }
  532. OldValueData = MyMalloc( OldValueSize );
  533. if( OldValueData == NULL ) {
  534. SetuplogError(
  535. LogSevWarning,
  536. SETUPLOG_USE_MESSAGEID,
  537. MSG_LOG_FIX_SERVICE_FAILED,
  538. ServiceName, NULL,
  539. SETUPLOG_USE_MESSAGEID,
  540. MSG_LOG_OUTOFMEMORY,
  541. NULL,NULL);
  542. RegCloseKey( hKey );
  543. return( FALSE );
  544. }
  545. //
  546. // Read the value entry that lists the dependencies
  547. //
  548. Error = RegQueryValueEx(hKey,
  549. szDependOnService,
  550. NULL,
  551. &Type,
  552. OldValueData,
  553. &OldValueSize);
  554. if( Error != ERROR_SUCCESS ) {
  555. SetuplogError(
  556. LogSevWarning,
  557. SETUPLOG_USE_MESSAGEID,
  558. MSG_LOG_FIX_SERVICE_FAILED,
  559. ServiceName, NULL,
  560. SETUPLOG_USE_MESSAGEID,
  561. MSG_LOG_X_PARAM_RETURNED_WINERR,
  562. szRegQueryValueEx,
  563. Error,
  564. szDependOnService,
  565. NULL,NULL);
  566. MyFree( OldValueData );
  567. RegCloseKey( hKey );
  568. return( FALSE );
  569. }
  570. //
  571. // Find out if the OldValueData, explicitly list OldDependencyName.
  572. // If not, then the service depends on another service that depends
  573. // on OlDependencyName, and in this case there is no need to change
  574. // the dependency list.
  575. //
  576. p = OldValueData;
  577. ChangeDependencyList = FALSE;
  578. while( (ULONG)(p - OldValueData) < OldValueSize ) {
  579. if( ( lstrcmpi( (PWSTR)p, OldDependencyName ) == 0 ) ) {
  580. ChangeDependencyList = TRUE;
  581. break;
  582. }
  583. p += (lstrlen( (PWSTR)p ) + 1)*sizeof(WCHAR);
  584. }
  585. if( !ChangeDependencyList ) {
  586. MyFree( OldValueData );
  587. RegCloseKey( hKey );
  588. //
  589. // Let the caller think that the dependency list was fixed
  590. //
  591. return( TRUE );
  592. }
  593. //
  594. // Allocate a buffer for the new value data
  595. //
  596. NewValueSize = OldValueSize -
  597. ( lstrlen( OldDependencyName ) - lstrlen( NewDependencyName ) )*sizeof(WCHAR);
  598. NewValueData = MyMalloc( NewValueSize );
  599. if( NewValueData == NULL ) {
  600. SetuplogError(
  601. LogSevWarning,
  602. SETUPLOG_USE_MESSAGEID,
  603. MSG_LOG_FIX_SERVICE_FAILED,
  604. ServiceName, NULL,
  605. SETUPLOG_USE_MESSAGEID,
  606. MSG_LOG_OUTOFMEMORY,
  607. NULL,NULL);
  608. MyFree( OldValueData );
  609. RegCloseKey( hKey );
  610. return( FALSE );
  611. }
  612. //
  613. // Replace the old dependency name with the new one
  614. //
  615. p = OldValueData;
  616. q = NewValueData;
  617. lstrcpy( (PWSTR)q, NewDependencyName );
  618. q += (lstrlen( (PWSTR)q ) + 1)*sizeof(WCHAR);
  619. while( (ULONG)(p - OldValueData) < OldValueSize ) {
  620. if( ( lstrcmpi( (PWSTR)p, OldDependencyName ) != 0 ) &&
  621. ( lstrcmpi( (PWSTR)p, NewDependencyName ) != 0 )
  622. ) {
  623. lstrcpy( (PWSTR)q, (PWSTR)p );
  624. q += (lstrlen( (PWSTR)q ) + 1)*sizeof(WCHAR);
  625. }
  626. p += (lstrlen( (PWSTR)p ) + 1)*sizeof(WCHAR);
  627. }
  628. //
  629. // Save the value entry with the new dependency name
  630. //
  631. Error = RegSetValueEx( hKey,
  632. szDependOnService,
  633. 0,
  634. REG_MULTI_SZ,
  635. NewValueData,
  636. (DWORD)(q-NewValueData) // NewValueSize
  637. );
  638. if( Error != ERROR_SUCCESS ) {
  639. SetuplogError(
  640. LogSevWarning,
  641. SETUPLOG_USE_MESSAGEID,
  642. MSG_LOG_FIX_SERVICE_FAILED,
  643. ServiceName, NULL,
  644. SETUPLOG_USE_MESSAGEID,
  645. MSG_LOG_X_PARAM_RETURNED_WINERR,
  646. szRegSetValueEx,
  647. Error,
  648. szDependOnService,
  649. NULL,NULL);
  650. MyFree( OldValueData );
  651. MyFree( NewValueData );
  652. RegCloseKey( hKey );
  653. return( FALSE );
  654. }
  655. //
  656. // Free the allocated buffers
  657. //
  658. MyFree( OldValueData );
  659. MyFree( NewValueData );
  660. //
  661. // Close the key
  662. //
  663. RegCloseKey( hKey );
  664. return( TRUE );
  665. }
  666. BOOL
  667. UpdateServicesDependencies(
  668. IN HINF InfHandle
  669. )
  670. {
  671. INFCONTEXT InfContext;
  672. PCWSTR OldServiceName,NewServiceName;
  673. BOOL b;
  674. SC_HANDLE hSC, hSCService;
  675. LPENUM_SERVICE_STATUS DependentsList;
  676. DWORD BytesNeeded;
  677. DWORD ServicesReturned;
  678. HKEY hKey;
  679. ULONG Error;
  680. ULONG i;
  681. //
  682. // Iterate the [ServicesToRename] section in the inf.
  683. // Each line is the name of a dependecy service that needs to be renamed.
  684. //
  685. if(SetupFindFirstLine(InfHandle,szServicesToRename,NULL,&InfContext)) {
  686. b = TRUE;
  687. } else {
  688. SetuplogError( LogSevWarning,
  689. SETUPLOG_USE_MESSAGEID,
  690. MSG_LOG_UPDATE_SERVICES_FAILED, NULL,
  691. SETUPLOG_USE_MESSAGEID,
  692. MSG_LOG_NO_SECTION,
  693. szServicesToRename,NULL,NULL);
  694. return(FALSE);
  695. }
  696. //
  697. // Open a handle to the service controller manager
  698. //
  699. hSC = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
  700. if(hSC == NULL) {
  701. SetuplogError(
  702. LogSevWarning,
  703. SETUPLOG_USE_MESSAGEID,
  704. MSG_LOG_UPDATE_SERVICES_FAILED, NULL,
  705. SETUPLOG_USE_MESSAGEID,
  706. MSG_LOG_X_RETURNED_WINERR,
  707. szOpenSCManager,
  708. GetLastError(),
  709. NULL,NULL);
  710. return(FALSE);
  711. }
  712. do {
  713. //
  714. // Fetch the name of a service that got renamed
  715. //
  716. if((OldServiceName = pSetupGetField(&InfContext,0))
  717. && (NewServiceName = pSetupGetField(&InfContext,1))) {
  718. //
  719. // Create a dummy service that has the same name as the old service
  720. // This is necessarey so that we can get a handle to this service,
  721. // and pass it to EnumDependentServices to find out the services that
  722. // depend on this one.
  723. //
  724. if( !MyCreateService( OldServiceName,
  725. NULL,
  726. SERVICE_WIN32_OWN_PROCESS,
  727. SERVICE_DISABLED,
  728. SERVICE_ERROR_NORMAL,
  729. L"%SystemRoot%\\System32\\dummy.exe",
  730. NULL,
  731. L"",
  732. NULL,
  733. NULL ) ) {
  734. SetuplogError(
  735. LogSevWarning,
  736. SETUPLOG_USE_MESSAGEID,
  737. MSG_LOG_UPDATE_SERVICES_FAILED, NULL,
  738. SETUPLOG_USE_MESSAGEID,
  739. MSG_LOG_CANT_CREATE_DUMMY_SERVICE,
  740. OldServiceName,
  741. NULL,NULL);
  742. b = FALSE;
  743. continue;
  744. }
  745. //
  746. // Open the service that was just created
  747. //
  748. hSCService = OpenService(hSC,OldServiceName,SERVICE_ENUMERATE_DEPENDENTS | DELETE);
  749. if( hSCService == NULL) {
  750. Error = GetLastError();
  751. SetupDebugPrint2( L"SYSSETUP: Unable to open service = %ls. Error = %d \n", OldServiceName, Error );
  752. SetuplogError( LogSevWarning,
  753. SETUPLOG_USE_MESSAGEID,
  754. MSG_LOG_UPDATE_SERVICES_FAILED, NULL,
  755. SETUPLOG_USE_MESSAGEID,
  756. MSG_LOG_X_PARAM_RETURNED_WINERR,
  757. szOpenService,
  758. Error,
  759. OldServiceName,
  760. NULL,NULL);
  761. //
  762. // Force deletion of the service cretated
  763. //
  764. b = FALSE;
  765. Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  766. szServicesKeyPath,
  767. 0,
  768. MAXIMUM_ALLOWED,
  769. &hKey );
  770. if( Error == ERROR_SUCCESS ) {
  771. pSetupRegistryDelnode( hKey, OldServiceName );
  772. RegCloseKey( hKey );
  773. }
  774. continue;
  775. }
  776. //
  777. // Determine all services that depend on the service that was renamed
  778. //
  779. BytesNeeded = 0;
  780. ServicesReturned = 0;
  781. DependentsList = NULL;
  782. if( !EnumDependentServices( hSCService,
  783. SERVICE_ACTIVE | SERVICE_INACTIVE,
  784. DependentsList,
  785. 0,
  786. &BytesNeeded,
  787. &ServicesReturned ) &&
  788. ( Error = GetLastError()) != ERROR_MORE_DATA ) {
  789. SetuplogError( LogSevWarning,
  790. SETUPLOG_USE_MESSAGEID,
  791. MSG_LOG_UPDATE_SERVICES_PARAM_FAILED,
  792. OldServiceName, NULL,
  793. SETUPLOG_USE_MESSAGEID,
  794. MSG_LOG_X_RETURNED_WINERR,
  795. szEnumDependentService,
  796. Error,
  797. NULL,NULL);
  798. b = FALSE;
  799. goto delete_dummy_service;
  800. }
  801. DependentsList = MyMalloc( BytesNeeded );
  802. if( DependentsList == NULL ) {
  803. SetuplogError(
  804. LogSevWarning,
  805. SETUPLOG_USE_MESSAGEID,
  806. MSG_LOG_UPDATE_SERVICES_PARAM_FAILED,
  807. OldServiceName, NULL,
  808. SETUPLOG_USE_MESSAGEID,
  809. MSG_LOG_OUTOFMEMORY,
  810. NULL,NULL);
  811. b = FALSE;
  812. goto delete_dummy_service;
  813. }
  814. if( !EnumDependentServices( hSCService,
  815. SERVICE_ACTIVE | SERVICE_INACTIVE,
  816. DependentsList,
  817. BytesNeeded,
  818. &BytesNeeded,
  819. &ServicesReturned ) ) {
  820. SetuplogError( LogSevWarning,
  821. SETUPLOG_USE_MESSAGEID,
  822. MSG_LOG_UPDATE_SERVICES_PARAM_FAILED,
  823. OldServiceName, NULL,
  824. SETUPLOG_USE_MESSAGEID,
  825. MSG_LOG_X_RETURNED_WINERR,
  826. szEnumDependentService,
  827. GetLastError(),
  828. NULL,NULL);
  829. MyFree( DependentsList );
  830. b = FALSE;
  831. goto delete_dummy_service;
  832. }
  833. for( i = 0; i < ServicesReturned; i++ ) {
  834. //
  835. // Fix the dependency for this service
  836. //
  837. b = b && FixServiceDependency( DependentsList[i].lpServiceName,
  838. OldServiceName,
  839. NewServiceName );
  840. }
  841. MyFree( DependentsList );
  842. delete_dummy_service:
  843. if( !DeleteService(hSCService) &&
  844. ((Error = GetLastError()) != ERROR_SERVICE_MARKED_FOR_DELETE)
  845. ) {
  846. SetupDebugPrint2( L"SYSSETUP: Unable to delete service %ls. Error = %d \n", OldServiceName, Error );
  847. #if 0
  848. //
  849. // Force deletion of the dummy service
  850. //
  851. Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  852. szServicesKeyPath,
  853. 0,
  854. MAXIMUM_ALLOWED,
  855. &hKey );
  856. if( Error == ERROR_SUCCESS ) {
  857. pSetupRegistryDelnode( hKey, OldServiceName );
  858. RegCloseKey( hKey );
  859. }
  860. #endif
  861. }
  862. CloseServiceHandle(hSCService);
  863. } else {
  864. SetuplogError( LogSevWarning,
  865. SETUPLOG_USE_MESSAGEID,
  866. MSG_LOG_UPDATE_SERVICES_FAILED, NULL,
  867. SETUPLOG_USE_MESSAGEID,
  868. MSG_LOG_NO_SECTION,
  869. szServicesToRename,NULL,NULL);
  870. }
  871. } while(SetupFindNextLine(&InfContext,&InfContext));
  872. CloseServiceHandle(hSC);
  873. return(b);
  874. }