Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

938 lines
34 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: Service.cpp
  3. //
  4. // Copyright (c) 2000, Microsoft Corporation
  5. //
  6. // This file contains a class that implements generic portions of a Win32
  7. // serivce.
  8. //
  9. // History: 2000-11-29 vtan created
  10. // --------------------------------------------------------------------------
  11. #include "StandardHeader.h"
  12. #define STRSAFE_LIB
  13. #include <strsafe.h>
  14. #include "Service.h"
  15. #include "RegistryResources.h"
  16. #include "StatusCode.h"
  17. // --------------------------------------------------------------------------
  18. // CService::CService
  19. //
  20. // Arguments: pAPIConnection = CAPIConnection used to implement service.
  21. // pServerAPI = CServerAPI used to stop service.
  22. // pszServiceName = Name of service.
  23. //
  24. // Returns: <none>
  25. //
  26. // Purpose: Constructor for CService.
  27. //
  28. // History: 2000-11-29 vtan created
  29. // --------------------------------------------------------------------------
  30. CService::CService (CAPIConnection *pAPIConnection, CServerAPI *pServerAPI, const TCHAR *pszServiceName) :
  31. _hService(NULL),
  32. _pszServiceName(pszServiceName),
  33. _pAPIConnection(pAPIConnection),
  34. _pServerAPI(pServerAPI),
  35. _pAPIDispatchSync(NULL)
  36. {
  37. CopyMemory(_szTag, CSVC_TAG, CB_CSVC_TAG);
  38. ZeroMemory(&_serviceStatus, sizeof(_serviceStatus));
  39. pAPIConnection->AddRef();
  40. pServerAPI->AddRef();
  41. }
  42. // --------------------------------------------------------------------------
  43. // CService::~CService
  44. //
  45. // Arguments: <none>
  46. //
  47. // Returns: <none>
  48. //
  49. // Purpose: Destructor for CService. Release used resources.
  50. //
  51. // History: 2000-11-29 vtan created
  52. // --------------------------------------------------------------------------
  53. CService::~CService (void)
  54. {
  55. CopyMemory(_szTag, DEAD_CSVC_TAG, CB_CSVC_TAG);
  56. _pServerAPI->Release();
  57. _pServerAPI = NULL;
  58. _pAPIConnection->Release();
  59. _pAPIConnection = NULL;
  60. delete _pAPIDispatchSync;
  61. _pAPIDispatchSync = NULL;
  62. ASSERTMSG(_hService == NULL, "_hService should be released in CService::~CService");
  63. }
  64. // --------------------------------------------------------------------------
  65. // CService::IsValid
  66. //
  67. // Arguments: address of CService instance
  68. //
  69. // Returns: <none>
  70. //
  71. // Purpose: Reports whether the specified address points to a valid
  72. // CService object.
  73. //
  74. // Found that there are cases when SCM launches a thread to
  75. // interrogate the service (SERVICE_CONTROL_INTERROGATE) when
  76. // trying to restart a CService who has already been deleted, but
  77. // whose status has not yet gone from STOP_PENDING to STOPPED.
  78. //
  79. // This is unavoidable because SCM will dump the service process once
  80. // STOPPED, not giving us a chance to delete the CService. Thus
  81. // we assign STOPPED as late as possible.
  82. //
  83. // History: 2002-03-21 scotthan created
  84. // --------------------------------------------------------------------------
  85. BOOL CService::IsValid(CService* pService)
  86. {
  87. return pService ?
  88. (0 == memcmp(pService->_szTag, CSVC_TAG, CB_CSVC_TAG)) :
  89. FALSE;
  90. }
  91. // --------------------------------------------------------------------------
  92. // CService::Start
  93. //
  94. // Arguments: <none>
  95. //
  96. // Returns: <none>
  97. //
  98. // Purpose: Called from ServiceMain of the service. This registers the
  99. // handler and starts the service (listens to the API port).
  100. // When the listen call returns it sets the status of the service
  101. // as stopped and exits.
  102. //
  103. // History: 2000-11-29 vtan created
  104. // 2002-03-21 scotthan add robustness.
  105. // --------------------------------------------------------------------------
  106. void CService::Start (void)
  107. {
  108. AddRef(); // defensive addref
  109. _hService = RegisterServiceCtrlHandlerEx(_pszServiceName, CB_HandlerEx, this);
  110. if (_hService != NULL)
  111. {
  112. NTSTATUS status;
  113. BOOL fExit = FALSE;
  114. ASSERTMSG(_pAPIDispatchSync == NULL, "CService::Start - _pAPIDispatchSync != NULL: reentered before shutdown\n");
  115. _pAPIDispatchSync = new CAPIDispatchSync;
  116. if( _pAPIDispatchSync != NULL )
  117. {
  118. _serviceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
  119. _serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
  120. _serviceStatus.dwWin32ExitCode = NO_ERROR;
  121. _serviceStatus.dwCheckPoint = 0;
  122. _serviceStatus.dwWaitHint = 0;
  123. TSTATUS(SignalStartStop(TRUE));
  124. // Add a reference for the HandlerEx callback. When the handler receives
  125. // a stop code it will release its reference.
  126. AddRef();
  127. _serviceStatus.dwCurrentState = SERVICE_RUNNING;
  128. TBOOL(_SetServiceStatus(_hService, &_serviceStatus, this));
  129. status = _pAPIConnection->Listen(_pAPIDispatchSync);
  130. if( CAPIDispatchSync::WaitForServiceControlStop(
  131. _pAPIDispatchSync, DISPATCHSYNC_TIMEOUT) != WAIT_TIMEOUT )
  132. {
  133. fExit = TRUE;
  134. }
  135. else
  136. {
  137. _serviceStatus.dwCurrentState = SERVICE_STOPPED;
  138. _serviceStatus.dwWin32ExitCode = ERROR_TIMEOUT;
  139. DISPLAYMSG("CService::Start - Timed out waiting for SERVICE_CONTROL_STOP/SHUTDOWN.");
  140. TBOOL(_SetServiceStatus(_hService, &_serviceStatus, this));
  141. }
  142. }
  143. else
  144. {
  145. _serviceStatus.dwCurrentState = SERVICE_STOPPED;
  146. _serviceStatus.dwWin32ExitCode = ERROR_OUTOFMEMORY;
  147. TBOOL(_SetServiceStatus(_hService, &_serviceStatus, this));
  148. }
  149. }
  150. Release(); // defensive addref
  151. }
  152. // --------------------------------------------------------------------------
  153. // CService::Install
  154. //
  155. // Arguments: pszName = Name of the service.
  156. // pszImage = Executable image of the service.
  157. // pszGroup = Group to which the service belongs.
  158. // pszAccount = Account under which the service runs.
  159. // pszDllName = Name of the hosting dll.
  160. // pszDependencies = Any dependencies the service has.
  161. // pszSvchostGroup = The svchost group.
  162. // dwStartType = Start type of the service.
  163. // hInstance = HINSTANCE for resources.
  164. // uiDisplayNameID = Resource ID of the display name.
  165. // uiDescriptionID = Resource ID of the description.
  166. //
  167. // Returns: NTSTATUS
  168. //
  169. // Purpose: Use the service control manager to create the service. Add
  170. // additional information that CreateService does not allow us to
  171. // directly specify and add additional information that is
  172. // required to run in svchost.exe as a shared service process.
  173. //
  174. // History: 2000-11-29 vtan created
  175. // --------------------------------------------------------------------------
  176. NTSTATUS CService::Install (const TCHAR *pszName,
  177. const TCHAR *pszImage,
  178. const TCHAR *pszGroup,
  179. const TCHAR *pszAccount,
  180. const TCHAR *pszDllName,
  181. const TCHAR *pszDependencies,
  182. const TCHAR *pszSvchostGroup,
  183. const TCHAR *pszServiceMainName,
  184. DWORD dwStartType,
  185. HINSTANCE hInstance,
  186. UINT uiDisplayNameID,
  187. UINT uiDescriptionID,
  188. SERVICE_FAILURE_ACTIONS *psfa)
  189. {
  190. NTSTATUS status;
  191. status = AddService(pszName, pszImage, pszGroup, pszAccount, pszDependencies, dwStartType, hInstance, uiDisplayNameID, psfa);
  192. if (NT_SUCCESS(status))
  193. {
  194. status = AddServiceDescription(pszName, hInstance, uiDescriptionID);
  195. if (NT_SUCCESS(status))
  196. {
  197. status = AddServiceParameters(pszName, pszDllName, pszServiceMainName);
  198. if (NT_SUCCESS(status))
  199. {
  200. status = AddServiceToGroup(pszName, pszSvchostGroup);
  201. }
  202. }
  203. }
  204. if (!NT_SUCCESS(status))
  205. {
  206. TSTATUS(Remove(pszName));
  207. }
  208. return(status);
  209. }
  210. // --------------------------------------------------------------------------
  211. // CService::Remove
  212. //
  213. // Arguments: pszName = Name of service to remove.
  214. //
  215. // Returns: NTSTATUS
  216. //
  217. // Purpose: Use the service control manager to delete the service. This
  218. // doesn't clean up the turds left for svchost usage.
  219. //
  220. // History: 2000-11-29 vtan created
  221. // --------------------------------------------------------------------------
  222. NTSTATUS CService::Remove (const TCHAR *pszName)
  223. {
  224. NTSTATUS status;
  225. SC_HANDLE hSCManager;
  226. hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
  227. if (hSCManager != NULL)
  228. {
  229. SC_HANDLE hSCService;
  230. hSCService = OpenService(hSCManager, pszName, DELETE);
  231. if (hSCService != NULL)
  232. {
  233. if (DeleteService(hSCService) != FALSE)
  234. {
  235. status = STATUS_SUCCESS;
  236. }
  237. else
  238. {
  239. status = CStatusCode::StatusCodeOfLastError();
  240. }
  241. TBOOL(CloseServiceHandle(hSCService));
  242. }
  243. else
  244. {
  245. status = CStatusCode::StatusCodeOfLastError();
  246. }
  247. TBOOL(CloseServiceHandle(hSCManager));
  248. }
  249. else
  250. {
  251. status = CStatusCode::StatusCodeOfLastError();
  252. }
  253. return(status);
  254. }
  255. // --------------------------------------------------------------------------
  256. // CService::SignalStartStop
  257. //
  258. // Arguments: BOOL fStart
  259. //
  260. // Returns: NTSTATUS
  261. //
  262. // Purpose: Base class implementation of signal service started function.
  263. // MUST BE INVOKED BY CHILD OVERRIDE!
  264. //
  265. // History: 2000-11-29 vtan created
  266. // 2002-03-11 scotthan renamed to 'SignalStartStop' from 'Signal',
  267. // added boolean arg,
  268. // 2002-03-24 scotthan added firing of 'stopping'notification
  269. // --------------------------------------------------------------------------
  270. NTSTATUS CService::SignalStartStop (BOOL fStart)
  271. {
  272. if( !fStart )
  273. {
  274. CAPIDispatchSync::SignalServiceStopping(_pAPIDispatchSync);
  275. }
  276. return(STATUS_SUCCESS);
  277. }
  278. // --------------------------------------------------------------------------
  279. // Default return codes for SCM control requests
  280. typedef struct
  281. {
  282. DWORD dwControl;
  283. DWORD dwRet;
  284. } SERVICE_CONTROL_RETURN;
  285. const SERVICE_CONTROL_RETURN _rgDefaultControlRet[] =
  286. {
  287. { SERVICE_CONTROL_STOP, NO_ERROR},
  288. { SERVICE_CONTROL_SHUTDOWN, NO_ERROR},
  289. { SERVICE_CONTROL_INTERROGATE, NO_ERROR},
  290. { SERVICE_CONTROL_PAUSE, ERROR_CALL_NOT_IMPLEMENTED},
  291. { SERVICE_CONTROL_CONTINUE, ERROR_CALL_NOT_IMPLEMENTED},
  292. { SERVICE_CONTROL_PARAMCHANGE, ERROR_CALL_NOT_IMPLEMENTED},
  293. { SERVICE_CONTROL_NETBINDADD, ERROR_CALL_NOT_IMPLEMENTED},
  294. { SERVICE_CONTROL_NETBINDREMOVE, ERROR_CALL_NOT_IMPLEMENTED},
  295. { SERVICE_CONTROL_NETBINDENABLE, ERROR_CALL_NOT_IMPLEMENTED},
  296. { SERVICE_CONTROL_NETBINDDISABLE, ERROR_CALL_NOT_IMPLEMENTED},
  297. { SERVICE_CONTROL_DEVICEEVENT, ERROR_CALL_NOT_IMPLEMENTED},
  298. { SERVICE_CONTROL_HARDWAREPROFILECHANGE, ERROR_CALL_NOT_IMPLEMENTED},
  299. { SERVICE_CONTROL_POWEREVENT, ERROR_CALL_NOT_IMPLEMENTED},
  300. };
  301. // --------------------------------------------------------------------------
  302. DWORD _GetDefaultControlRet(DWORD dwControl)
  303. {
  304. for(int i = 0; i < ARRAYSIZE(_rgDefaultControlRet); i++)
  305. {
  306. if( dwControl == _rgDefaultControlRet[i].dwControl )
  307. return _rgDefaultControlRet[i].dwRet;
  308. }
  309. DISPLAYMSG("Unknown service control code passed to CService::CB_HandlerEx");
  310. return ERROR_CALL_NOT_IMPLEMENTED;
  311. }
  312. // --------------------------------------------------------------------------
  313. // CService::HandlerEx
  314. //
  315. // Arguments: dwControl = Control code from service control manager.
  316. //
  317. // Returns: DWORD
  318. //
  319. // Purpose: HandlerEx function for the service. The base class implements
  320. // most of the useful things that the service will want to do.
  321. // It's declared virtual in case overriding is required.
  322. //
  323. // History: 2000-11-29 vtan created
  324. // 2002-03-21 scotthan Make shutdown more robust.
  325. // --------------------------------------------------------------------------
  326. DWORD CService::HandlerEx (DWORD dwControl)
  327. {
  328. DWORD dwErrorCode = _GetDefaultControlRet(dwControl);
  329. SERVICE_STATUS_HANDLE hService = _hService;
  330. if( hService != NULL )
  331. {
  332. switch (dwControl)
  333. {
  334. case SERVICE_CONTROL_STOP:
  335. case SERVICE_CONTROL_SHUTDOWN:
  336. {
  337. // In the stop/shutdown case, we do the following:
  338. // (1) respond to the message by setting the status to SERVICE_STOP_PENDING.
  339. // (2) Signal to all blocking LPC request handler threads that the service
  340. // is coming down. This should cause them to terminate gracefully and
  341. // come home.
  342. // (3) Send an API_GENERIC_STOP request down the LPC port, telling it to quit.
  343. // (this call can only succeed if it comes from within this process.)
  344. // (4) Wait until the port finishes shutting down.
  345. // (5) Signal to ServiceMain that the SERVICE_CONTROL_STOP/SHUTDOWN has completed.
  346. // (6) ServiceMain exits.
  347. // Step (1): update status to SERVICE_STOP_PENDING.
  348. _serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
  349. TBOOL(_SetServiceStatus(hService, &_serviceStatus, this));
  350. // Step (2): Call home any waiting LPC request handler threads
  351. SignalStartStop(FALSE);
  352. // Step (3) Send an API_GENERIC_STOP LPC request to stop listening on
  353. // the port (this will immediately release ServiceMain,
  354. // who in turn needs to wait until we're completely finished here before exiting.)
  355. NTSTATUS status;
  356. TSTATUS((status = _pServerAPI->Stop()));
  357. if( NT_SUCCESS(status) )
  358. {
  359. // Step (4): Wait until the API_GENERIC_STOP is finished.
  360. if( CAPIDispatchSync::WaitForPortShutdown(
  361. _pAPIDispatchSync, DISPATCHSYNC_TIMEOUT) != WAIT_TIMEOUT )
  362. {
  363. _serviceStatus.dwCurrentState = SERVICE_STOPPED;
  364. _serviceStatus.dwWin32ExitCode = CStatusCode::ErrorCodeOfStatusCode(status);
  365. TBOOL(_SetServiceStatus(_hService, &_serviceStatus, this));
  366. _hService = hService = NULL;
  367. // Release reference on ourselves.
  368. // The matching AddRef occurs in CService::Start.
  369. Release();
  370. }
  371. else
  372. {
  373. dwErrorCode = ERROR_TIMEOUT;
  374. DISPLAYMSG("CService::HandlerEx - Timed out waiting for port shutdown.");
  375. }
  376. }
  377. else
  378. {
  379. _serviceStatus.dwCurrentState = SERVICE_RUNNING;
  380. TBOOL(_SetServiceStatus(hService, &_serviceStatus, this));
  381. dwErrorCode = CStatusCode::ErrorCodeOfStatusCode(status);
  382. }
  383. // Step (5): signal to ServiceMain that SERVICE_CONTROL_STOP/SHUTDOWN
  384. // has completed; now he's safe to exit.
  385. CAPIDispatchSync::SignalServiceControlStop(_pAPIDispatchSync);
  386. break;
  387. }
  388. default:
  389. {
  390. // Report current status:
  391. TBOOL(_SetServiceStatus(hService, &_serviceStatus, this));
  392. break;
  393. }
  394. }
  395. }
  396. return(dwErrorCode);
  397. }
  398. // --------------------------------------------------------------------------
  399. // CService::CB_HandlerEx
  400. //
  401. // Arguments: See the platform SDK under HandlerEx.
  402. //
  403. // Returns: DWORD
  404. //
  405. // Purpose: Static function stub to call into the class.
  406. //
  407. // History: 2000-11-29 vtan created
  408. // 2002-03-21 scotthan Add robustness.
  409. // --------------------------------------------------------------------------
  410. DWORD WINAPI CService::CB_HandlerEx (DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
  411. {
  412. UNREFERENCED_PARAMETER(dwEventType);
  413. UNREFERENCED_PARAMETER(lpEventData);
  414. DWORD dwRet = ERROR_SUCCESS;
  415. CService* pService = reinterpret_cast<CService*>(lpContext);
  416. DEBUG_TRY();
  417. if( CService::IsValid(pService) )
  418. {
  419. pService->AddRef(); // purely defensive; not until we call SetServiceStatus(SERVICE_STOPPED)
  420. // will SCM stop calling into us via HandlerEx, so we need to ensure we stay alive.
  421. dwRet = pService->HandlerEx(dwControl);
  422. pService->Release(); // remove defensive AddRef().
  423. }
  424. else
  425. {
  426. DISPLAYMSG("CService::CB_HandlerEx - Warning: SCM control entrypoint invoked vs. invalid CService instance");
  427. dwRet = _GetDefaultControlRet(dwControl);
  428. }
  429. DEBUG_EXCEPT("Breaking in CService::CB_HandlerEx exception handler");
  430. return dwRet;
  431. }
  432. // --------------------------------------------------------------------------
  433. // CService:AddService
  434. //
  435. // Arguments: pszName = Name of the service.
  436. // pszImage = Executable image of the service.
  437. // pszGroup = Group to which the service belongs.
  438. // pszAccount = Account under which the service runs.
  439. // pszDependencies = Any dependencies the service has.
  440. // dwStartType = Start type of the service.
  441. // hInstance = HINSTANCE for resources.
  442. // uiDisplayNameID = Resource ID of the display name.
  443. //
  444. // Returns: NTSTATUS
  445. //
  446. // Purpose: Uses the service control manager to create the service and add
  447. // it into the database.
  448. //
  449. // History: 2000-12-09 vtan created
  450. // --------------------------------------------------------------------------
  451. NTSTATUS CService::AddService (const TCHAR *pszName,
  452. const TCHAR *pszImage,
  453. const TCHAR *pszGroup,
  454. const TCHAR *pszAccount,
  455. const TCHAR *pszDependencies,
  456. DWORD dwStartType,
  457. HINSTANCE hInstance,
  458. UINT uiDisplayNameID,
  459. SERVICE_FAILURE_ACTIONS *psfa)
  460. {
  461. DWORD dwErrorCode;
  462. SC_HANDLE hSCManager;
  463. hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
  464. if (hSCManager != NULL)
  465. {
  466. TCHAR sz[256];
  467. if (LoadString(hInstance, uiDisplayNameID, sz, ARRAYSIZE(sz)) != 0)
  468. {
  469. SC_HANDLE hSCService;
  470. hSCService = CreateService(hSCManager,
  471. pszName,
  472. sz,
  473. SERVICE_ALL_ACCESS,
  474. SERVICE_WIN32_SHARE_PROCESS,
  475. dwStartType,
  476. SERVICE_ERROR_NORMAL,
  477. pszImage,
  478. pszGroup,
  479. NULL,
  480. pszDependencies,
  481. pszAccount,
  482. NULL);
  483. if (hSCService != NULL)
  484. {
  485. // Apply the failure action configuration, if any
  486. if (psfa != NULL)
  487. {
  488. // If CreateService succeeded, why would this fail?
  489. TBOOL(ChangeServiceConfig2(hSCService, SERVICE_CONFIG_FAILURE_ACTIONS, psfa));
  490. }
  491. TBOOL(CloseServiceHandle(hSCService));
  492. dwErrorCode = ERROR_SUCCESS;
  493. }
  494. else
  495. {
  496. // Blow off ERROR_SERVICE_EXISTS. If in the future the need
  497. // to change the configuration arises add the code here.
  498. dwErrorCode = GetLastError();
  499. if (dwErrorCode == ERROR_SERVICE_EXISTS)
  500. {
  501. dwErrorCode = ERROR_SUCCESS;
  502. // Update service information for upgrade cases
  503. hSCService = OpenService(hSCManager, pszName, SERVICE_ALL_ACCESS);
  504. if (hSCService != NULL)
  505. {
  506. // Update the start type
  507. TBOOL(ChangeServiceConfig(hSCService,
  508. SERVICE_NO_CHANGE, // dwServiceType
  509. dwStartType,
  510. SERVICE_NO_CHANGE, // dwErrorControl
  511. NULL, // lpBinaryPathName
  512. NULL, // lpLoadOrderGroup
  513. NULL, // lpdwTagId
  514. NULL, // lpDependencies
  515. NULL, // lpServiceStartName
  516. NULL, // lpPassword
  517. NULL // lpDisplayName
  518. ));
  519. // Apply the failure action configuration, if any
  520. if (psfa != NULL)
  521. {
  522. TBOOL(ChangeServiceConfig2(hSCService, SERVICE_CONFIG_FAILURE_ACTIONS, psfa));
  523. }
  524. TBOOL(CloseServiceHandle(hSCService));
  525. }
  526. }
  527. }
  528. TBOOL(CloseServiceHandle(hSCManager));
  529. }
  530. else
  531. {
  532. dwErrorCode = GetLastError();
  533. }
  534. }
  535. else
  536. {
  537. dwErrorCode = GetLastError();
  538. }
  539. return(CStatusCode::StatusCodeOfErrorCode(dwErrorCode));
  540. }
  541. // --------------------------------------------------------------------------
  542. // CService:AddServiceDescription
  543. //
  544. // Arguments: pszName = Name of service.
  545. // hInstance = HINSTANCE of module.
  546. // uiDescriptionID = Resource ID of description.
  547. //
  548. // Returns: NTSTATUS
  549. //
  550. // Purpose: Reads the string resource from the given location and writes
  551. // it as the description of the given service in the registry.
  552. //
  553. // History: 2000-12-09 vtan created
  554. // --------------------------------------------------------------------------
  555. NTSTATUS CService::AddServiceDescription (const TCHAR *pszName, HINSTANCE hInstance, UINT uiDescriptionID)
  556. {
  557. LONG lErrorCode;
  558. TCHAR szKeyName[256];
  559. CRegKey regKeyService;
  560. if (!pszName || !pszName[0])
  561. {
  562. lErrorCode = ERROR_INVALID_PARAMETER;
  563. }
  564. else
  565. {
  566. StringCchCopy(szKeyName, ARRAYSIZE(szKeyName), TEXT("SYSTEM\\CurrentControlSet\\Services\\"));
  567. StringCchCatN(szKeyName, ARRAYSIZE(szKeyName), pszName, (ARRAYSIZE(szKeyName) - 1) - lstrlen(szKeyName));
  568. lErrorCode = regKeyService.Open(HKEY_LOCAL_MACHINE,
  569. szKeyName,
  570. KEY_SET_VALUE);
  571. if (ERROR_SUCCESS == lErrorCode)
  572. {
  573. TCHAR sz[256];
  574. if (LoadString(hInstance, uiDescriptionID, sz, ARRAYSIZE(sz)) != 0)
  575. {
  576. lErrorCode = regKeyService.SetString(TEXT("Description"), sz);
  577. }
  578. else
  579. {
  580. lErrorCode = GetLastError();
  581. }
  582. }
  583. }
  584. return CStatusCode::StatusCodeOfErrorCode(lErrorCode);
  585. }
  586. // --------------------------------------------------------------------------
  587. // CService:AddServiceParameters
  588. //
  589. // Arguments: pszName = Name of service.
  590. // pszDllName = Name of DLL hosting service.
  591. //
  592. // Returns: NTSTATUS
  593. //
  594. // Purpose: Adds parameters required for svchost to host this service.
  595. //
  596. // History: 2000-12-09 vtan created
  597. // --------------------------------------------------------------------------
  598. NTSTATUS CService::AddServiceParameters (const TCHAR* pszName, const TCHAR* pszDllName, const TCHAR* pszServiceMainName)
  599. {
  600. LONG lErrorCode;
  601. TCHAR szKeyName[256];
  602. CRegKey regKey;
  603. // we handle a null pszServiceMainName
  604. if (!pszName || !pszName[0] ||
  605. !pszDllName || !pszDllName[0])
  606. {
  607. lErrorCode = ERROR_INVALID_PARAMETER;
  608. }
  609. else
  610. {
  611. StringCchCopy(szKeyName, ARRAYSIZE(szKeyName), TEXT("SYSTEM\\CurrentControlSet\\Services\\"));
  612. StringCchCatN(szKeyName, ARRAYSIZE(szKeyName), pszName, (ARRAYSIZE(szKeyName) - 1) - lstrlen(szKeyName));
  613. StringCchCatN(szKeyName, ARRAYSIZE(szKeyName), TEXT("\\Parameters"), (ARRAYSIZE(szKeyName) - 1) - lstrlen(szKeyName));
  614. lErrorCode = regKey.Create(HKEY_LOCAL_MACHINE,
  615. szKeyName,
  616. REG_OPTION_NON_VOLATILE,
  617. KEY_SET_VALUE,
  618. NULL);
  619. if (ERROR_SUCCESS == lErrorCode)
  620. {
  621. TCHAR sz[256];
  622. StringCchCopy(sz, ARRAYSIZE(sz), TEXT("%SystemRoot%\\System32\\"));
  623. StringCchCatN(sz, ARRAYSIZE(sz), pszDllName, (ARRAYSIZE(sz) - 1) - lstrlen(sz));
  624. lErrorCode = regKey.SetPath(TEXT("ServiceDll"), sz);
  625. if (ERROR_SUCCESS == lErrorCode)
  626. {
  627. if (!pszServiceMainName || !pszServiceMainName[0])
  628. {
  629. StringCchCopy(sz, ARRAYSIZE(sz), TEXT("ServiceMain"));
  630. pszServiceMainName = sz;
  631. }
  632. lErrorCode = regKey.SetString(TEXT("ServiceMain"), pszServiceMainName);
  633. }
  634. }
  635. }
  636. return CStatusCode::StatusCodeOfErrorCode(lErrorCode);
  637. }
  638. // --------------------------------------------------------------------------
  639. // CService:AddServiceToGroup
  640. //
  641. // Arguments: pszName = Name of service.
  642. // pszSvchostGroup = Group to which the service belongs.
  643. //
  644. // Returns: NTSTATUS
  645. //
  646. // Purpose: Adds the service as part of the group of services hosted in
  647. // a single instance of svchost.exe.
  648. //
  649. // History: 2000-12-09 vtan created
  650. // --------------------------------------------------------------------------
  651. NTSTATUS CService::AddServiceToGroup (const TCHAR *pszName, const TCHAR *pszSvchostGroup)
  652. {
  653. LONG lErrorCode;
  654. CRegKey regKey;
  655. lErrorCode = regKey.Open(HKEY_LOCAL_MACHINE,
  656. TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost"),
  657. KEY_QUERY_VALUE | KEY_SET_VALUE);
  658. if (ERROR_SUCCESS == lErrorCode)
  659. {
  660. DWORD dwType, dwBaseDataSize, dwDataSize;
  661. dwType = dwBaseDataSize = dwDataSize = 0;
  662. lErrorCode = regKey.QueryValue(pszSvchostGroup,
  663. &dwType,
  664. NULL,
  665. &dwBaseDataSize);
  666. if ((REG_MULTI_SZ == dwType) && (dwBaseDataSize != 0))
  667. {
  668. TCHAR *pszData;
  669. dwDataSize = dwBaseDataSize + ((lstrlen(pszName) + 1) * sizeof(TCHAR));
  670. pszData = static_cast<TCHAR*>(LocalAlloc(LMEM_FIXED, dwDataSize));
  671. if (pszData != NULL)
  672. {
  673. lErrorCode = regKey.QueryValue(pszSvchostGroup,
  674. NULL,
  675. pszData,
  676. &dwBaseDataSize);
  677. if (ERROR_SUCCESS == lErrorCode)
  678. {
  679. if (*(pszData + (dwBaseDataSize / sizeof(TCHAR)) - 1) == L'\0')
  680. {
  681. if (!StringInMulitpleStringList(pszData, pszName))
  682. {
  683. StringInsertInMultipleStringList(pszData, pszName, dwDataSize);
  684. lErrorCode = regKey.SetValue(pszSvchostGroup,
  685. dwType,
  686. pszData,
  687. dwDataSize);
  688. }
  689. }
  690. else
  691. {
  692. lErrorCode = ERROR_INVALID_DATA;
  693. }
  694. }
  695. (HLOCAL)LocalFree(pszData);
  696. }
  697. else
  698. {
  699. lErrorCode = ERROR_OUTOFMEMORY;
  700. }
  701. }
  702. else
  703. {
  704. lErrorCode = ERROR_INVALID_DATA;
  705. }
  706. }
  707. return(CStatusCode::StatusCodeOfErrorCode(lErrorCode));
  708. }
  709. // --------------------------------------------------------------------------
  710. // CService:StringInMulitpleStringList
  711. //
  712. // Arguments: pszStringList = String list to search.
  713. // pszString = String to search for.
  714. //
  715. // Returns: bool
  716. //
  717. // Purpose: Searches the REG_MULTI_SZ string list looking for matches.
  718. //
  719. // History: 2000-12-01 vtan created
  720. // --------------------------------------------------------------------------
  721. bool CService::StringInMulitpleStringList (const TCHAR *pszStringList, const TCHAR *pszString)
  722. {
  723. bool fFound;
  724. fFound = false;
  725. while (!fFound && (pszStringList[0] != TEXT('\0')))
  726. {
  727. fFound = (lstrcmpi(pszStringList, pszString) == 0);
  728. if (!fFound)
  729. {
  730. pszStringList += (lstrlen(pszStringList) + 1);
  731. }
  732. }
  733. return(fFound);
  734. }
  735. // --------------------------------------------------------------------------
  736. // CService:StringInsertInMultipleStringList
  737. //
  738. // Arguments: pszStringList = String list to insert string in.
  739. // pszString = String to insert.
  740. // cbStringListSize = Byte count of string list.
  741. //
  742. // Returns: bool
  743. //
  744. // Purpose: Inserts the given string into the multiple string list in
  745. // the first alphabetical position encountered. If the list is
  746. // kept alphabetical then this preserves it.
  747. //
  748. // History: 2000-12-02 vtan created
  749. // --------------------------------------------------------------------------
  750. void CService::StringInsertInMultipleStringList (TCHAR *pszStringList, const TCHAR *pszString, DWORD cbStringListSize)
  751. {
  752. int iResult, cchSize;
  753. TCHAR *pszFirstString, *pszLastString;
  754. pszFirstString = pszLastString = pszStringList;
  755. cchSize = lstrlen(pszString) + 1;
  756. iResult = -1;
  757. while ((iResult < 0) && (pszStringList[0] != TEXT('\0')))
  758. {
  759. pszLastString = pszStringList;
  760. iResult = lstrcmpi(pszStringList, pszString);
  761. ASSERTMSG(iResult != 0, "Found exact match in StringInsertInMultipleStringList");
  762. // 1 is for the '\0' terminator
  763. pszStringList += (lstrlen(pszStringList) + 1);
  764. }
  765. if (iResult < 0)
  766. {
  767. pszLastString = pszStringList;
  768. }
  769. int cbLenToMove = cbStringListSize - (int(pszLastString - pszFirstString) * sizeof(TCHAR)) - (cchSize * sizeof(TCHAR));
  770. if (cbLenToMove > 0) // Means that pszLastString + cchSize < pszFirstString + cbStringListSize
  771. {
  772. MoveMemory(pszLastString + cchSize, pszLastString, cbLenToMove);
  773. StringCchCopy(pszLastString, cchSize, pszString);
  774. }
  775. }
  776. // --------------------------------------------------------------------------
  777. // CServiceWorkItem::CServiceWorkItem
  778. //
  779. // Arguments: pServerAPI = CServerAPI to use.
  780. //
  781. // Returns: <none>
  782. //
  783. // Purpose: Constructor for CServiceWorkItem.
  784. //
  785. // History: 2000-11-29 vtan created
  786. // --------------------------------------------------------------------------
  787. CServiceWorkItem::CServiceWorkItem (CServerAPI *pServerAPI) :
  788. _pServerAPI(pServerAPI)
  789. {
  790. pServerAPI->AddRef();
  791. }
  792. // --------------------------------------------------------------------------
  793. // CServiceWorkItem::~CServiceWorkItem
  794. //
  795. // Arguments: <none>
  796. //
  797. // Returns: <none>
  798. //
  799. // Purpose: Destructor for CServiceWorkItem. Release resources used.
  800. //
  801. // History: 2000-11-29 vtan created
  802. // --------------------------------------------------------------------------
  803. CServiceWorkItem::~CServiceWorkItem (void)
  804. {
  805. _pServerAPI->Release();
  806. _pServerAPI = NULL;
  807. }
  808. // --------------------------------------------------------------------------
  809. // CServiceWorkItem::Entry
  810. //
  811. // Arguments: <none>
  812. //
  813. // Returns: <none>
  814. //
  815. // Purpose: Executes work item request (stop the server).
  816. //
  817. // History: 2000-11-29 vtan created
  818. // --------------------------------------------------------------------------
  819. void CServiceWorkItem::Entry (void)
  820. {
  821. TSTATUS(_pServerAPI->Stop());
  822. }