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.

762 lines
26 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. #include "Service.h"
  13. #include "RegistryResources.h"
  14. #include "StatusCode.h"
  15. // --------------------------------------------------------------------------
  16. // CService::CService
  17. //
  18. // Arguments: pAPIConnection = CAPIConnection used to implement service.
  19. // pServerAPI = CServerAPI used to stop service.
  20. // pszServiceName = Name of service.
  21. //
  22. // Returns: <none>
  23. //
  24. // Purpose: Constructor for CService.
  25. //
  26. // History: 2000-11-29 vtan created
  27. // --------------------------------------------------------------------------
  28. CService::CService (CAPIConnection *pAPIConnection, CServerAPI *pServerAPI, const TCHAR *pszServiceName) :
  29. _hService(NULL),
  30. _pszServiceName(pszServiceName),
  31. _pAPIConnection(pAPIConnection),
  32. _pServerAPI(pServerAPI)
  33. {
  34. ZeroMemory(&_serviceStatus, sizeof(_serviceStatus));
  35. pAPIConnection->AddRef();
  36. pServerAPI->AddRef();
  37. }
  38. // --------------------------------------------------------------------------
  39. // CService::~CService
  40. //
  41. // Arguments: <none>
  42. //
  43. // Returns: <none>
  44. //
  45. // Purpose: Destructor for CService. Release used resources.
  46. //
  47. // History: 2000-11-29 vtan created
  48. // --------------------------------------------------------------------------
  49. CService::~CService (void)
  50. {
  51. _pServerAPI->Release();
  52. _pServerAPI = NULL;
  53. _pAPIConnection->Release();
  54. _pAPIConnection = NULL;
  55. ASSERTMSG(_hService == NULL, "_hService should be released in CService::~CService");
  56. }
  57. // --------------------------------------------------------------------------
  58. // CService::Start
  59. //
  60. // Arguments: <none>
  61. //
  62. // Returns: <none>
  63. //
  64. // Purpose: Called from ServiceMain of the service. This registers the
  65. // handler and starts the service (listens to the API port).
  66. // When the listen call returns it sets the status of the service
  67. // as stopped and exits.
  68. //
  69. // History: 2000-11-29 vtan created
  70. // --------------------------------------------------------------------------
  71. void CService::Start (void)
  72. {
  73. // Add a reference for the HandlerEx callback. When the handler receives
  74. // a stop code it will release its reference.
  75. AddRef();
  76. _hService = RegisterServiceCtrlHandlerEx(_pszServiceName, CB_HandlerEx, this);
  77. if (_hService != NULL)
  78. {
  79. NTSTATUS status;
  80. _serviceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
  81. _serviceStatus.dwCurrentState = SERVICE_RUNNING;
  82. _serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
  83. _serviceStatus.dwWin32ExitCode = NO_ERROR;
  84. _serviceStatus.dwCheckPoint = 0;
  85. _serviceStatus.dwWaitHint = 0;
  86. TBOOL(SetServiceStatus(_hService, &_serviceStatus));
  87. TSTATUS(Signal());
  88. status = _pAPIConnection->Listen();
  89. _serviceStatus.dwCurrentState = SERVICE_STOPPED;
  90. _serviceStatus.dwWin32ExitCode = CStatusCode::ErrorCodeOfStatusCode(status);
  91. _serviceStatus.dwCheckPoint = 0;
  92. _serviceStatus.dwWaitHint = 0;
  93. TBOOL(SetServiceStatus(_hService, &_serviceStatus));
  94. _hService = NULL;
  95. }
  96. else
  97. {
  98. Release();
  99. }
  100. }
  101. // --------------------------------------------------------------------------
  102. // CService::Install
  103. //
  104. // Arguments: pszName = Name of the service.
  105. // pszImage = Executable image of the service.
  106. // pszGroup = Group to which the service belongs.
  107. // pszAccount = Account under which the service runs.
  108. // pszDllName = Name of the hosting dll.
  109. // pszDependencies = Any dependencies the service has.
  110. // pszSvchostGroup = The svchost group.
  111. // dwStartType = Start type of the service.
  112. // hInstance = HINSTANCE for resources.
  113. // uiDisplayNameID = Resource ID of the display name.
  114. // uiDescriptionID = Resource ID of the description.
  115. //
  116. // Returns: NTSTATUS
  117. //
  118. // Purpose: Use the service control manager to create the service. Add
  119. // additional information that CreateService does not allow us to
  120. // directly specify and add additional information that is
  121. // required to run in svchost.exe as a shared service process.
  122. //
  123. // History: 2000-11-29 vtan created
  124. // --------------------------------------------------------------------------
  125. NTSTATUS CService::Install (const TCHAR *pszName,
  126. const TCHAR *pszImage,
  127. const TCHAR *pszGroup,
  128. const TCHAR *pszAccount,
  129. const TCHAR *pszDllName,
  130. const TCHAR *pszDependencies,
  131. const TCHAR *pszSvchostGroup,
  132. const TCHAR *pszServiceMainName,
  133. DWORD dwStartType,
  134. HINSTANCE hInstance,
  135. UINT uiDisplayNameID,
  136. UINT uiDescriptionID,
  137. SERVICE_FAILURE_ACTIONS *psfa)
  138. {
  139. NTSTATUS status;
  140. status = AddService(pszName, pszImage, pszGroup, pszAccount, pszDependencies, dwStartType, hInstance, uiDisplayNameID, psfa);
  141. if (NT_SUCCESS(status))
  142. {
  143. status = AddServiceDescription(pszName, hInstance, uiDescriptionID);
  144. if (NT_SUCCESS(status))
  145. {
  146. status = AddServiceParameters(pszName, pszDllName, pszServiceMainName);
  147. if (NT_SUCCESS(status))
  148. {
  149. status = AddServiceToGroup(pszName, pszSvchostGroup);
  150. }
  151. }
  152. }
  153. if (!NT_SUCCESS(status))
  154. {
  155. TSTATUS(Remove(pszName));
  156. }
  157. return(status);
  158. }
  159. // --------------------------------------------------------------------------
  160. // CService::Remove
  161. //
  162. // Arguments: pszName = Name of service to remove.
  163. //
  164. // Returns: NTSTATUS
  165. //
  166. // Purpose: Use the service control manager to delete the service. This
  167. // doesn't clean up the turds left for svchost usage.
  168. //
  169. // History: 2000-11-29 vtan created
  170. // --------------------------------------------------------------------------
  171. NTSTATUS CService::Remove (const TCHAR *pszName)
  172. {
  173. NTSTATUS status;
  174. SC_HANDLE hSCManager;
  175. hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
  176. if (hSCManager != NULL)
  177. {
  178. SC_HANDLE hSCService;
  179. hSCService = OpenService(hSCManager, pszName, DELETE);
  180. if (hSCService != NULL)
  181. {
  182. if (DeleteService(hSCService) != FALSE)
  183. {
  184. status = STATUS_SUCCESS;
  185. }
  186. else
  187. {
  188. status = CStatusCode::StatusCodeOfLastError();
  189. }
  190. TBOOL(CloseServiceHandle(hSCService));
  191. }
  192. else
  193. {
  194. status = CStatusCode::StatusCodeOfLastError();
  195. }
  196. TBOOL(CloseServiceHandle(hSCManager));
  197. }
  198. else
  199. {
  200. status = CStatusCode::StatusCodeOfLastError();
  201. }
  202. return(status);
  203. }
  204. // --------------------------------------------------------------------------
  205. // CService::Signal
  206. //
  207. // Arguments: <none>
  208. //
  209. // Returns: NTSTATUS
  210. //
  211. // Purpose: Base class implementation of signal service started function.
  212. // This does nothing.
  213. //
  214. // History: 2000-11-29 vtan created
  215. // --------------------------------------------------------------------------
  216. NTSTATUS CService::Signal (void)
  217. {
  218. return(STATUS_SUCCESS);
  219. }
  220. // --------------------------------------------------------------------------
  221. // CService::HandlerEx
  222. //
  223. // Arguments: dwControl = Control code from service control manager.
  224. //
  225. // Returns: DWORD
  226. //
  227. // Purpose: HandlerEx function for the service. The base class implements
  228. // most of the useful things that the service will want to do.
  229. // It's declared virtual in case overriding is required.
  230. //
  231. // History: 2000-11-29 vtan created
  232. // --------------------------------------------------------------------------
  233. DWORD CService::HandlerEx (DWORD dwControl)
  234. {
  235. DWORD dwErrorCode;
  236. SERVICE_STATUS_HANDLE hService;
  237. hService = _hService;
  238. switch (dwControl)
  239. {
  240. case SERVICE_CONTROL_STOP:
  241. case SERVICE_CONTROL_SHUTDOWN:
  242. {
  243. NTSTATUS status;
  244. CServiceWorkItem *pServiceWorkItem;
  245. // In the stop/shutdown case respond to the message by setting
  246. // the status to SERVICE_STOP_PENDING. Create a workitem to end
  247. // the main service thread by sending an LPC request down the
  248. // port telling it to quit. This call can only succeed if it
  249. // comes from within the process. If the queue fails the stop
  250. // the server inline on the shared dispatcher thread.
  251. _serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
  252. TBOOL(SetServiceStatus(hService, &_serviceStatus));
  253. pServiceWorkItem = new CServiceWorkItem(_pServerAPI);
  254. if (pServiceWorkItem != NULL)
  255. {
  256. status = pServiceWorkItem->Queue();
  257. pServiceWorkItem->Release();
  258. }
  259. else
  260. {
  261. status = STATUS_NO_MEMORY;
  262. }
  263. if (!NT_SUCCESS(status))
  264. {
  265. TSTATUS(_pServerAPI->Stop());
  266. }
  267. hService = NULL;
  268. dwErrorCode = CStatusCode::ErrorCodeOfStatusCode(status);
  269. break;
  270. }
  271. case SERVICE_CONTROL_PAUSE:
  272. dwErrorCode = ERROR_CALL_NOT_IMPLEMENTED;
  273. break;
  274. case SERVICE_CONTROL_CONTINUE:
  275. dwErrorCode = ERROR_CALL_NOT_IMPLEMENTED;
  276. break;
  277. case SERVICE_CONTROL_INTERROGATE:
  278. dwErrorCode = NO_ERROR;
  279. break;
  280. case SERVICE_CONTROL_PARAMCHANGE:
  281. case SERVICE_CONTROL_NETBINDADD:
  282. case SERVICE_CONTROL_NETBINDREMOVE:
  283. case SERVICE_CONTROL_NETBINDENABLE:
  284. case SERVICE_CONTROL_NETBINDDISABLE:
  285. case SERVICE_CONTROL_DEVICEEVENT:
  286. case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
  287. case SERVICE_CONTROL_POWEREVENT:
  288. dwErrorCode = ERROR_CALL_NOT_IMPLEMENTED;
  289. break;
  290. default:
  291. DISPLAYMSG("Unknown service control code passed to CService::HandlerEx");
  292. dwErrorCode = ERROR_CALL_NOT_IMPLEMENTED;
  293. break;
  294. }
  295. // If the SERVICE_STATUS_HANDLE is still valid then set the service
  296. // status code. Otherwise the service thread has been terminated by
  297. // a SERVICE_CONTROL_STOP or SERVICE_CONTROL_SHUTDOWN code.
  298. if (hService != NULL)
  299. {
  300. TBOOL(SetServiceStatus(hService, &_serviceStatus));
  301. }
  302. else
  303. {
  304. // In the stop case release the reference so the object is destroyed.
  305. Release();
  306. }
  307. return(dwErrorCode);
  308. }
  309. // --------------------------------------------------------------------------
  310. // CService::CB_HandlerEx
  311. //
  312. // Arguments: See the platform SDK under HandlerEx.
  313. //
  314. // Returns: DWORD
  315. //
  316. // Purpose: Static function stub to call into the class.
  317. //
  318. // History: 2000-11-29 vtan created
  319. // --------------------------------------------------------------------------
  320. DWORD WINAPI CService::CB_HandlerEx (DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
  321. {
  322. UNREFERENCED_PARAMETER(dwEventType);
  323. UNREFERENCED_PARAMETER(lpEventData);
  324. return(reinterpret_cast<CService*>(lpContext)->HandlerEx(dwControl));
  325. }
  326. // --------------------------------------------------------------------------
  327. // CService:AddService
  328. //
  329. // Arguments: pszName = Name of the service.
  330. // pszImage = Executable image of the service.
  331. // pszGroup = Group to which the service belongs.
  332. // pszAccount = Account under which the service runs.
  333. // pszDependencies = Any dependencies the service has.
  334. // dwStartType = Start type of the service.
  335. // hInstance = HINSTANCE for resources.
  336. // uiDisplayNameID = Resource ID of the display name.
  337. //
  338. // Returns: NTSTATUS
  339. //
  340. // Purpose: Uses the service control manager to create the service and add
  341. // it into the database.
  342. //
  343. // History: 2000-12-09 vtan created
  344. // --------------------------------------------------------------------------
  345. NTSTATUS CService::AddService (const TCHAR *pszName,
  346. const TCHAR *pszImage,
  347. const TCHAR *pszGroup,
  348. const TCHAR *pszAccount,
  349. const TCHAR *pszDependencies,
  350. DWORD dwStartType,
  351. HINSTANCE hInstance,
  352. UINT uiDisplayNameID,
  353. SERVICE_FAILURE_ACTIONS *psfa)
  354. {
  355. DWORD dwErrorCode;
  356. SC_HANDLE hSCManager;
  357. hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
  358. if (hSCManager != NULL)
  359. {
  360. TCHAR sz[256];
  361. if (LoadString(hInstance, uiDisplayNameID, sz, ARRAYSIZE(sz)) != 0)
  362. {
  363. SC_HANDLE hSCService;
  364. hSCService = CreateService(hSCManager,
  365. pszName,
  366. sz,
  367. SERVICE_ALL_ACCESS,
  368. SERVICE_WIN32_SHARE_PROCESS,
  369. dwStartType,
  370. SERVICE_ERROR_NORMAL,
  371. pszImage,
  372. pszGroup,
  373. NULL,
  374. pszDependencies,
  375. pszAccount,
  376. NULL);
  377. if (hSCService != NULL)
  378. {
  379. // Apply the failure action configuration, if any
  380. if (psfa != NULL)
  381. {
  382. // If CreateService succeeded, why would this fail?
  383. TBOOL(ChangeServiceConfig2(hSCService, SERVICE_CONFIG_FAILURE_ACTIONS, psfa));
  384. }
  385. TBOOL(CloseServiceHandle(hSCService));
  386. dwErrorCode = ERROR_SUCCESS;
  387. }
  388. else
  389. {
  390. // Blow off ERROR_SERVICE_EXISTS. If in the future the need
  391. // to change the configuration arises add the code here.
  392. dwErrorCode = GetLastError();
  393. if (dwErrorCode == ERROR_SERVICE_EXISTS)
  394. {
  395. dwErrorCode = ERROR_SUCCESS;
  396. // Apply the failure action configuration, if any
  397. if (psfa != NULL)
  398. {
  399. hSCService = OpenService(hSCManager, pszName, SERVICE_ALL_ACCESS);
  400. if (hSCService != NULL)
  401. {
  402. TBOOL(ChangeServiceConfig2(hSCService, SERVICE_CONFIG_FAILURE_ACTIONS, psfa));
  403. TBOOL(CloseServiceHandle(hSCService));
  404. }
  405. }
  406. }
  407. }
  408. TBOOL(CloseServiceHandle(hSCManager));
  409. }
  410. else
  411. {
  412. dwErrorCode = GetLastError();
  413. }
  414. }
  415. else
  416. {
  417. dwErrorCode = GetLastError();
  418. }
  419. return(CStatusCode::StatusCodeOfErrorCode(dwErrorCode));
  420. }
  421. // --------------------------------------------------------------------------
  422. // CService:AddServiceDescription
  423. //
  424. // Arguments: pszName = Name of service.
  425. // hInstance = HINSTANCE of module.
  426. // uiDescriptionID = Resource ID of description.
  427. //
  428. // Returns: NTSTATUS
  429. //
  430. // Purpose: Reads the string resource from the given location and writes
  431. // it as the description of the given service in the registry.
  432. //
  433. // History: 2000-12-09 vtan created
  434. // --------------------------------------------------------------------------
  435. NTSTATUS CService::AddServiceDescription (const TCHAR *pszName, HINSTANCE hInstance, UINT uiDescriptionID)
  436. {
  437. LONG lErrorCode;
  438. TCHAR szKeyName[256];
  439. CRegKey regKeyService;
  440. (TCHAR*)lstrcpy(szKeyName, TEXT("SYSTEM\\CurrentControlSet\\Services\\"));
  441. (TCHAR*)lstrcat(szKeyName, pszName);
  442. lErrorCode = regKeyService.Open(HKEY_LOCAL_MACHINE,
  443. szKeyName,
  444. KEY_SET_VALUE);
  445. if (ERROR_SUCCESS == lErrorCode)
  446. {
  447. TCHAR sz[256];
  448. if (LoadString(hInstance, uiDescriptionID, sz, ARRAYSIZE(sz)) != 0)
  449. {
  450. lErrorCode = regKeyService.SetString(TEXT("Description"), sz);
  451. }
  452. else
  453. {
  454. lErrorCode = GetLastError();
  455. }
  456. }
  457. return(CStatusCode::StatusCodeOfErrorCode(lErrorCode));
  458. }
  459. // --------------------------------------------------------------------------
  460. // CService:AddServiceParameters
  461. //
  462. // Arguments: pszName = Name of service.
  463. // pszDllName = Name of DLL hosting service.
  464. //
  465. // Returns: NTSTATUS
  466. //
  467. // Purpose: Adds parameters required for svchost to host this service.
  468. //
  469. // History: 2000-12-09 vtan created
  470. // --------------------------------------------------------------------------
  471. NTSTATUS CService::AddServiceParameters (const TCHAR *pszName, const TCHAR *pszDllName, const TCHAR *pszServiceMainName)
  472. {
  473. LONG lErrorCode;
  474. TCHAR szKeyName[256];
  475. CRegKey regKey;
  476. (TCHAR*)lstrcpy(szKeyName, TEXT("SYSTEM\\CurrentControlSet\\Services\\"));
  477. (TCHAR*)lstrcat(szKeyName, pszName);
  478. (TCHAR*)lstrcat(szKeyName, TEXT("\\Parameters"));
  479. lErrorCode = regKey.Create(HKEY_LOCAL_MACHINE,
  480. szKeyName,
  481. REG_OPTION_NON_VOLATILE,
  482. KEY_SET_VALUE,
  483. NULL);
  484. if (ERROR_SUCCESS == lErrorCode)
  485. {
  486. TCHAR sz[256];
  487. (TCHAR*)lstrcpy(sz, TEXT("%SystemRoot%\\System32\\"));
  488. (TCHAR*)lstrcat(sz, pszDllName);
  489. lErrorCode = regKey.SetPath(TEXT("ServiceDll"), sz);
  490. if (ERROR_SUCCESS == lErrorCode)
  491. {
  492. if (pszServiceMainName == NULL)
  493. {
  494. (TCHAR*)lstrcpy(sz, TEXT("ServiceMain"));
  495. pszServiceMainName = sz;
  496. }
  497. lErrorCode = regKey.SetString(TEXT("ServiceMain"), pszServiceMainName);
  498. }
  499. }
  500. return(CStatusCode::StatusCodeOfErrorCode(lErrorCode));
  501. }
  502. // --------------------------------------------------------------------------
  503. // CService:AddServiceToGroup
  504. //
  505. // Arguments: pszName = Name of service.
  506. // pszSvchostGroup = Group to which the service belongs.
  507. //
  508. // Returns: NTSTATUS
  509. //
  510. // Purpose: Adds the service as part of the group of services hosted in
  511. // a single instance of svchost.exe.
  512. //
  513. // History: 2000-12-09 vtan created
  514. // --------------------------------------------------------------------------
  515. NTSTATUS CService::AddServiceToGroup (const TCHAR *pszName, const TCHAR *pszSvchostGroup)
  516. {
  517. LONG lErrorCode;
  518. CRegKey regKey;
  519. lErrorCode = regKey.Open(HKEY_LOCAL_MACHINE,
  520. TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost"),
  521. KEY_QUERY_VALUE | KEY_SET_VALUE);
  522. if (ERROR_SUCCESS == lErrorCode)
  523. {
  524. DWORD dwType, dwBaseDataSize, dwDataSize;
  525. dwType = dwBaseDataSize = dwDataSize = 0;
  526. lErrorCode = regKey.QueryValue(pszSvchostGroup,
  527. &dwType,
  528. NULL,
  529. &dwBaseDataSize);
  530. if ((REG_MULTI_SZ == dwType) && (dwBaseDataSize != 0))
  531. {
  532. TCHAR *pszData;
  533. dwDataSize = dwBaseDataSize + ((lstrlen(pszName) + sizeof('\0')) * sizeof(TCHAR));
  534. pszData = static_cast<TCHAR*>(LocalAlloc(LMEM_FIXED, dwDataSize));
  535. if (pszData != NULL)
  536. {
  537. lErrorCode = regKey.QueryValue(pszSvchostGroup,
  538. NULL,
  539. pszData,
  540. &dwBaseDataSize);
  541. if (ERROR_SUCCESS == lErrorCode)
  542. {
  543. if (!StringInMulitpleStringList(pszData, pszName))
  544. {
  545. StringInsertInMultipleStringList(pszData, pszName, dwDataSize);
  546. lErrorCode = regKey.SetValue(pszSvchostGroup,
  547. dwType,
  548. pszData,
  549. dwDataSize);
  550. }
  551. else
  552. {
  553. lErrorCode = ERROR_SUCCESS;
  554. }
  555. }
  556. (HLOCAL)LocalFree(pszData);
  557. }
  558. else
  559. {
  560. lErrorCode = ERROR_OUTOFMEMORY;
  561. }
  562. }
  563. else
  564. {
  565. lErrorCode = ERROR_INVALID_DATA;
  566. }
  567. }
  568. return(CStatusCode::StatusCodeOfErrorCode(lErrorCode));
  569. }
  570. // --------------------------------------------------------------------------
  571. // CService:StringInMulitpleStringList
  572. //
  573. // Arguments: pszStringList = String list to search.
  574. // pszString = String to search for.
  575. //
  576. // Returns: bool
  577. //
  578. // Purpose: Searches the REG_MULTI_SZ string list looking for matches.
  579. //
  580. // History: 2000-12-01 vtan created
  581. // --------------------------------------------------------------------------
  582. bool CService::StringInMulitpleStringList (const TCHAR *pszStringList, const TCHAR *pszString)
  583. {
  584. bool fFound;
  585. fFound = false;
  586. while (!fFound && (pszStringList[0] != TEXT('\0')))
  587. {
  588. fFound = (lstrcmpi(pszStringList, pszString) == 0);
  589. if (!fFound)
  590. {
  591. pszStringList += (lstrlen(pszStringList) + sizeof('\0'));
  592. }
  593. }
  594. return(fFound);
  595. }
  596. // --------------------------------------------------------------------------
  597. // CService:StringInsertInMultipleStringList
  598. //
  599. // Arguments: pszStringList = String list to insert string in.
  600. // pszString = String to insert.
  601. // dwStringListSize = Byte count of string list.
  602. //
  603. // Returns: bool
  604. //
  605. // Purpose: Inserts the given string into the multiple string list in
  606. // the first alphabetical position encountered. If the list is
  607. // kept alphabetical then this preserves it.
  608. //
  609. // History: 2000-12-02 vtan created
  610. // --------------------------------------------------------------------------
  611. void CService::StringInsertInMultipleStringList (TCHAR *pszStringList, const TCHAR *pszString, DWORD dwStringListSize)
  612. {
  613. int iResult, iSize;
  614. TCHAR *pszFirstString, *pszLastString;
  615. pszFirstString = pszLastString = pszStringList;
  616. iSize = lstrlen(pszString) + sizeof('\0');
  617. iResult = -1;
  618. while ((iResult < 0) && (pszStringList[0] != TEXT('\0')))
  619. {
  620. pszLastString = pszStringList;
  621. iResult = lstrcmpi(pszStringList, pszString);
  622. ASSERTMSG(iResult != 0, "Found exact match in StringInsertInMultipleStringList");
  623. pszStringList += (lstrlen(pszStringList) + sizeof('\0'));
  624. }
  625. if (iResult < 0)
  626. {
  627. pszLastString = pszStringList;
  628. }
  629. MoveMemory(pszLastString + iSize, pszLastString, dwStringListSize - ((pszLastString - pszFirstString) * sizeof(TCHAR)) - (iSize * sizeof(TCHAR)));
  630. (TCHAR*)lstrcpy(pszLastString, pszString);
  631. }
  632. // --------------------------------------------------------------------------
  633. // CServiceWorkItem::CServiceWorkItem
  634. //
  635. // Arguments: pServerAPI = CServerAPI to use.
  636. //
  637. // Returns: <none>
  638. //
  639. // Purpose: Constructor for CServiceWorkItem.
  640. //
  641. // History: 2000-11-29 vtan created
  642. // --------------------------------------------------------------------------
  643. CServiceWorkItem::CServiceWorkItem (CServerAPI *pServerAPI) :
  644. _pServerAPI(pServerAPI)
  645. {
  646. pServerAPI->AddRef();
  647. }
  648. // --------------------------------------------------------------------------
  649. // CServiceWorkItem::~CServiceWorkItem
  650. //
  651. // Arguments: <none>
  652. //
  653. // Returns: <none>
  654. //
  655. // Purpose: Destructor for CServiceWorkItem. Release resources used.
  656. //
  657. // History: 2000-11-29 vtan created
  658. // --------------------------------------------------------------------------
  659. CServiceWorkItem::~CServiceWorkItem (void)
  660. {
  661. _pServerAPI->Release();
  662. _pServerAPI = NULL;
  663. }
  664. // --------------------------------------------------------------------------
  665. // CServiceWorkItem::Entry
  666. //
  667. // Arguments: <none>
  668. //
  669. // Returns: <none>
  670. //
  671. // Purpose: Executes work item request (stop the server).
  672. //
  673. // History: 2000-11-29 vtan created
  674. // --------------------------------------------------------------------------
  675. void CServiceWorkItem::Entry (void)
  676. {
  677. TSTATUS(_pServerAPI->Stop());
  678. }