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.

1566 lines
46 KiB

  1. #include "shsrvice.h"
  2. #include "service.h"
  3. #include "mischlpr.h"
  4. #include "sfstr.h"
  5. #include "reg.h"
  6. #include "resource.h"
  7. #include "dbg.h"
  8. #include "tfids.h"
  9. #include <dbt.h>
  10. #include <initguid.h>
  11. #include <ioevent.h>
  12. #include <shlwapi.h>
  13. #include <shlwapip.h>
  14. #define ARRAYSIZE(a) (sizeof((a))/sizeof((a)[0]))
  15. #define MAX_EVENTNAME 100
  16. struct CTRLEVENT
  17. {
  18. CTRLEVENT* peventNext;
  19. DWORD dwControl;
  20. DWORD dwEventType;
  21. BYTE rgbEventData[1];
  22. };
  23. const LPWSTR pszSVCHostGroup = TEXT("netsvcs");
  24. ///////////////////////////////////////////////////////////////////////////////
  25. //
  26. SERVICE_TABLE_ENTRY CGenericServiceManager::_rgste[] =
  27. {
  28. { TEXT("ShellHWDetection"), CGenericServiceManager::_ServiceMain },
  29. { NULL, NULL },
  30. };
  31. CGenericServiceManager::SUBSERVICE CGenericServiceManager::_rgsubservice[] =
  32. {
  33. { TEXT("Shell.HWEventDetector"), IDS_SHELLHWDETECTION_FRIENDLYNAME,
  34. TEXT("RpcSs\0"), TEXT("ShellSvcGroup"), IDS_SHELLHWDETECTION_DESCRIPTION,
  35. {0} },
  36. };
  37. // "- 1": Last entry of both arrays are NULL terminators
  38. DWORD CGenericServiceManager::_cste =
  39. ARRAYSIZE(CGenericServiceManager::_rgste) - 1;
  40. CRITICAL_SECTION CGenericServiceManager::_cs = {0};
  41. BOOL CGenericServiceManager::_fInitializationDone = FALSE;
  42. ULONG CGenericServiceManager::_cRefCS = 0;
  43. HANDLE CGenericServiceManager::_hEventInitCS = NULL;
  44. BOOL CGenericServiceManager::_fSVCHosted = FALSE;
  45. #ifdef DEBUG
  46. BOOL CGenericServiceManager::_fRunAsService = TRUE;
  47. #endif
  48. ///////////////////////////////////////////////////////////////////////////////
  49. //
  50. HRESULT _GetServiceEventName(LPCWSTR pszServiceName, LPWSTR pszEventName,
  51. DWORD cchEventName);
  52. ///////////////////////////////////////////////////////////////////////////////
  53. //
  54. // static
  55. BOOL _IsAlreadyInstalled(LPCWSTR pszRegStr, LPCWSTR pszServiceName)
  56. {
  57. LPCWSTR psz = pszRegStr;
  58. BOOL fThere = FALSE;
  59. do
  60. {
  61. if (!lstrcmp(psz, pszServiceName))
  62. {
  63. fThere = TRUE;
  64. break;
  65. }
  66. psz += lstrlen(psz) + 1;
  67. }
  68. while (*psz);
  69. return fThere;
  70. }
  71. HRESULT _UnInstall(LPCWSTR pszServiceName)
  72. {
  73. HRESULT hres = E_FAIL;
  74. SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  75. // Need to do it for all services
  76. if (hSCM)
  77. {
  78. hres = S_OK;
  79. SC_HANDLE hService = OpenService(hSCM, pszServiceName,
  80. DELETE);
  81. if (hService)
  82. {
  83. DeleteService(hService);
  84. CloseServiceHandle(hService);
  85. }
  86. else
  87. {
  88. // Don't fail, if somebody manually removed the service n
  89. // from the reg, then all n + x services will not uninstall.
  90. hres = S_FALSE;
  91. }
  92. CloseServiceHandle(hSCM);
  93. }
  94. return hres;
  95. }
  96. HRESULT _InstSetSVCHostInfo(LPWSTR pszServiceName)
  97. {
  98. HRESULT hres = E_FAIL;
  99. HKEY hkey;
  100. DWORD dwDisp;
  101. BOOL fAlreadyThere = FALSE;
  102. if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  103. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Svchost"),
  104. 0, NULL, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, &hkey,
  105. &dwDisp))
  106. {
  107. DWORD cbSize;
  108. DWORD cbSizeNew;
  109. BOOL fEmpty = FALSE;
  110. LPWSTR pszNew;
  111. if (ERROR_SUCCESS != RegQueryValueEx(hkey, pszSVCHostGroup, 0, NULL,
  112. NULL, &cbSize))
  113. {
  114. fEmpty = TRUE;
  115. // Set cbSize to the size of the 2nd NULL terminator
  116. cbSize = sizeof(WCHAR);
  117. }
  118. cbSizeNew = cbSize + (lstrlen(pszServiceName) + 1) * sizeof(WCHAR);
  119. pszNew = (LPWSTR)LocalAlloc(LPTR, cbSizeNew);
  120. if (pszNew)
  121. {
  122. DWORD cbSize2 = cbSizeNew;
  123. hres = S_OK;
  124. if (!fEmpty)
  125. {
  126. if (ERROR_SUCCESS == RegQueryValueEx(hkey, pszSVCHostGroup, 0,
  127. NULL, (PBYTE)pszNew, &cbSize2))
  128. {
  129. if (cbSize2 == cbSize)
  130. {
  131. fAlreadyThere = _IsAlreadyInstalled(pszNew,
  132. pszServiceName);
  133. }
  134. else
  135. {
  136. hres = E_FAIL;
  137. }
  138. }
  139. else
  140. {
  141. hres = E_FAIL;
  142. }
  143. }
  144. else
  145. {
  146. cbSize2 = sizeof(WCHAR);
  147. }
  148. if (SUCCEEDED(hres) && !fAlreadyThere)
  149. {
  150. lstrcpy(pszNew + (cbSize2 / sizeof(WCHAR)) - 1,
  151. pszServiceName);
  152. if (ERROR_SUCCESS != RegSetValueEx(hkey, pszSVCHostGroup, 0,
  153. REG_MULTI_SZ, (PBYTE)pszNew, cbSizeNew))
  154. {
  155. hres = E_FAIL;
  156. }
  157. }
  158. LocalFree((HLOCAL)pszNew);
  159. }
  160. else
  161. {
  162. hres = E_OUTOFMEMORY;
  163. }
  164. // We should have an entry in the SUBSERVICE array for this...
  165. if (SUCCEEDED(hres))
  166. {
  167. HKEY hkey2;
  168. if (ERROR_SUCCESS == RegCreateKeyEx(hkey, pszSVCHostGroup,
  169. 0, NULL, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL,
  170. &hkey2, &dwDisp))
  171. {
  172. DWORD dwSec = 0x00000001;
  173. DWORD cbSec = sizeof(dwSec);
  174. // We set this magic value of 1 and svchost.exe will
  175. // call CoInitializeSecurity for us
  176. if (ERROR_SUCCESS != RegSetValueEx(hkey2,
  177. TEXT("CoInitializeSecurityParam"), 0, REG_DWORD,
  178. (PBYTE)&dwSec, cbSec))
  179. {
  180. hres = E_FAIL;
  181. }
  182. }
  183. RegCloseKey(hkey2);
  184. }
  185. RegCloseKey(hkey);
  186. }
  187. return hres;
  188. }
  189. HRESULT _InstSetParameters(LPWSTR pszServiceName)
  190. {
  191. HKEY hkeyServices;
  192. HRESULT hres = E_FAIL;
  193. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  194. TEXT("System\\CurrentControlSet\\Services\\"), 0,
  195. MAXIMUM_ALLOWED, &hkeyServices))
  196. {
  197. HKEY hkeySvc;
  198. if (ERROR_SUCCESS == RegOpenKeyEx(hkeyServices, pszServiceName, 0,
  199. MAXIMUM_ALLOWED, &hkeySvc))
  200. {
  201. HKEY hkeyParam;
  202. if (ERROR_SUCCESS == RegCreateKeyEx(hkeySvc,
  203. TEXT("Parameters"), 0, NULL,
  204. REG_OPTION_NON_VOLATILE,
  205. MAXIMUM_ALLOWED, NULL, &hkeyParam, NULL))
  206. {
  207. // Watch out! Hard coded path and filename!
  208. WCHAR szServiceDll[] =
  209. TEXT("%SystemRoot%\\System32\\shsvcs.dll");
  210. if (ERROR_SUCCESS == RegSetValueEx(hkeyParam,
  211. TEXT("ServiceDll"), 0, REG_EXPAND_SZ,
  212. (PBYTE)szServiceDll, sizeof(szServiceDll)))
  213. {
  214. WCHAR szServiceMain[] =
  215. TEXT("HardwareDetectionServiceMain");
  216. if (ERROR_SUCCESS == RegSetValueEx(
  217. hkeyParam, TEXT("ServiceMain"), 0,
  218. REG_SZ, (PBYTE)szServiceMain,
  219. sizeof(szServiceMain)))
  220. {
  221. hres = S_OK;
  222. }
  223. }
  224. RegCloseKey(hkeyParam);
  225. }
  226. RegCloseKey(hkeySvc);
  227. }
  228. RegCloseKey(hkeyServices);
  229. }
  230. return hres;
  231. }
  232. // static
  233. HRESULT CGenericServiceManager::UnInstall()
  234. {
  235. HRESULT hr = S_FALSE;
  236. for (DWORD dw = 0; SUCCEEDED(hr) && (dw < _cste); ++dw)
  237. {
  238. hr = _UnInstall(_rgste[dw].lpServiceName);
  239. }
  240. return hr;
  241. }
  242. HRESULT _GetFriendlyStrings(CGenericServiceManager::SUBSERVICE* psubservice,
  243. LPWSTR pszFriendlyName, DWORD cchFriendlyName, LPWSTR pszDescription,
  244. DWORD cchDescription)
  245. {
  246. *pszFriendlyName = 0;
  247. *pszDescription = 0;
  248. HMODULE hmodule = GetModuleHandle(TEXT("shsvcs.dll"));
  249. if (hmodule)
  250. {
  251. LoadString(hmodule, psubservice->uFriendlyName, pszFriendlyName,
  252. cchFriendlyName);
  253. LoadString(hmodule, psubservice->uDescription, pszDescription,
  254. cchDescription);
  255. }
  256. return S_OK;
  257. }
  258. // static
  259. HRESULT CGenericServiceManager::Install()
  260. {
  261. HRESULT hres = S_FALSE;
  262. if (!IsOS(OS_WOW6432))
  263. {
  264. hres = E_FAIL;
  265. SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
  266. WCHAR szFileName[MAX_PATH];
  267. DWORD dwStartType = SERVICE_AUTO_START;
  268. if (hSCM)
  269. {
  270. WCHAR szFriendlyName[200];
  271. // Doc says limit is 1024 bytes
  272. WCHAR szDescription[1024 / sizeof(WCHAR)];
  273. // Need to do it for all services
  274. hres = S_OK;
  275. if (!_fSVCHosted)
  276. {
  277. if (GetModuleFileName(NULL, szFileName, ARRAYSIZE(szFileName)))
  278. {
  279. for (DWORD dw = 0; SUCCEEDED(hres) && (dw < _cste); ++dw)
  280. {
  281. _GetFriendlyStrings(&(_rgsubservice[dw]), szFriendlyName,
  282. ARRAYSIZE(szFriendlyName), szDescription,
  283. ARRAYSIZE(szDescription));
  284. SC_HANDLE hService = CreateService(hSCM,
  285. _rgste[dw].lpServiceName,
  286. szFriendlyName,
  287. 0,
  288. SERVICE_WIN32_SHARE_PROCESS,
  289. dwStartType, SERVICE_ERROR_IGNORE,
  290. szFileName,
  291. _rgsubservice[dw].pszLoadOrderGroup,
  292. NULL, _rgsubservice[dw].pszDependencies,
  293. NULL, NULL);
  294. if (hService)
  295. {
  296. SERVICE_DESCRIPTION sd;
  297. sd.lpDescription = szDescription;
  298. ChangeServiceConfig2(hService,
  299. SERVICE_CONFIG_DESCRIPTION, &sd);
  300. CloseServiceHandle(hService);
  301. }
  302. else
  303. {
  304. hres = E_FAIL;
  305. }
  306. }
  307. }
  308. }
  309. else
  310. {
  311. for (DWORD dw = 0; SUCCEEDED(hres) && (dw < _cste); ++dw)
  312. {
  313. WCHAR szCmd[MAX_PATH] =
  314. TEXT("%SystemRoot%\\System32\\svchost.exe -k ");
  315. hres = SafeStrCatN(szCmd, pszSVCHostGroup, ARRAYSIZE(szCmd));
  316. if (SUCCEEDED(hres))
  317. {
  318. _GetFriendlyStrings(&(_rgsubservice[dw]), szFriendlyName,
  319. ARRAYSIZE(szFriendlyName), szDescription,
  320. ARRAYSIZE(szDescription));
  321. SC_HANDLE hService = CreateService(hSCM,
  322. _rgste[dw].lpServiceName,
  323. szFriendlyName,
  324. 0,
  325. SERVICE_WIN32_SHARE_PROCESS,
  326. dwStartType, SERVICE_ERROR_IGNORE,
  327. szCmd,
  328. _rgsubservice[dw].pszLoadOrderGroup,
  329. NULL, _rgsubservice[dw].pszDependencies,
  330. NULL, NULL);
  331. if (hService)
  332. {
  333. SERVICE_DESCRIPTION sd;
  334. sd.lpDescription = szDescription;
  335. ChangeServiceConfig2(hService,
  336. SERVICE_CONFIG_DESCRIPTION, &sd);
  337. CloseServiceHandle(hService);
  338. hres = _InstSetParameters(_rgste[dw].lpServiceName);
  339. if (SUCCEEDED(hres))
  340. {
  341. hres = _InstSetSVCHostInfo(
  342. _rgste[dw].lpServiceName);
  343. }
  344. }
  345. else
  346. {
  347. if (ERROR_SERVICE_EXISTS == GetLastError())
  348. {
  349. // We had this problem on upgrade. The service is
  350. // already there, so CreateService fails. As a result the
  351. // StartType was not switched from Demand Start to Auto Start.
  352. // The following lines will do just that.
  353. // This code should be expanded for general upgraded cases.
  354. // All the other values in the structure should be passed here.
  355. hService = OpenService(hSCM,
  356. _rgste[dw].lpServiceName, SERVICE_CHANGE_CONFIG);
  357. if (hService)
  358. {
  359. if (ChangeServiceConfig(
  360. hService, // handle to service
  361. SERVICE_NO_CHANGE, // type of service
  362. dwStartType, // when to start service
  363. SERVICE_NO_CHANGE, // severity of start failure
  364. szCmd, // service binary file name
  365. _rgsubservice[dw].pszLoadOrderGroup, // load ordering group name
  366. NULL, // tag identifier
  367. NULL, // array of dependency names
  368. NULL, // account name
  369. NULL, // account password
  370. NULL // display name
  371. ))
  372. {
  373. // Do this un upgrade too
  374. hres = _InstSetSVCHostInfo(
  375. _rgste[dw].lpServiceName);
  376. if (SUCCEEDED(hres))
  377. {
  378. hres = _InstSetParameters(_rgste[dw].lpServiceName);
  379. }
  380. }
  381. else
  382. {
  383. hres = E_FAIL;
  384. }
  385. SERVICE_DESCRIPTION sd;
  386. sd.lpDescription = szDescription;
  387. ChangeServiceConfig2(hService,
  388. SERVICE_CONFIG_DESCRIPTION, &sd);
  389. CloseServiceHandle(hService);
  390. }
  391. }
  392. else
  393. {
  394. hres = E_FAIL;
  395. }
  396. }
  397. }
  398. }
  399. }
  400. CloseServiceHandle(hSCM);
  401. }
  402. // We don't need the ShellCOMServer anymore, so let's nuke it away on upgrades
  403. _UnInstall(TEXT("ShellCOMServer"));
  404. // Also remove the following reg entry on upgrade
  405. _RegDeleteValue(HKEY_LOCAL_MACHINE,
  406. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\SvcHost"), TEXT("shsvc"));
  407. }
  408. return hres;
  409. }
  410. // static
  411. HRESULT CGenericServiceManager::Init()
  412. {
  413. return _Init();
  414. }
  415. // static
  416. HRESULT CGenericServiceManager::Cleanup()
  417. {
  418. return _Cleanup();
  419. }
  420. ///////////////////////////////////////////////////////////////////////////////
  421. // Private
  422. // static
  423. HRESULT CGenericServiceManager::_Init()
  424. {
  425. HRESULT hres = E_FAIL;
  426. ASSERT(ARRAYSIZE(_rgste) == (ARRAYSIZE(_rgsubservice) + 1));
  427. if (!InterlockedCompareExchange((LONG*)&_fInitializationDone, TRUE,
  428. FALSE))
  429. {
  430. _hEventInitCS = CreateEvent(NULL, TRUE, FALSE,
  431. TEXT("CGenericServiceManager__Init"));
  432. if (_hEventInitCS)
  433. {
  434. InitializeCriticalSection(&_cs);
  435. SetEvent(_hEventInitCS);
  436. hres = S_OK;
  437. }
  438. }
  439. else
  440. {
  441. HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE,
  442. TEXT("CGenericServiceManager__Init"));
  443. if (hEvent)
  444. {
  445. WaitForSingleObject(hEvent, INFINITE);
  446. CloseHandle(hEvent);
  447. hres = S_OK;
  448. }
  449. }
  450. if (SUCCEEDED(hres))
  451. {
  452. ::InterlockedIncrement((LONG*)&_cRefCS);
  453. // Per thread
  454. hres = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
  455. }
  456. return hres;
  457. }
  458. // static
  459. HRESULT CGenericServiceManager::_Cleanup()
  460. {
  461. if (_fInitializationDone)
  462. {
  463. ULONG cRef = ::InterlockedDecrement((LONG*)&_cRefCS);
  464. if (!cRef)
  465. {
  466. DeleteCriticalSection(&_cs);
  467. CloseHandle(_hEventInitCS);
  468. }
  469. // Per thread
  470. CoUninitialize();
  471. InterlockedExchange((LONG*)&_fInitializationDone, FALSE);
  472. }
  473. return S_OK;
  474. }
  475. __inline void _TraceServiceCode(DWORD
  476. #ifdef DEBUG
  477. dwControl
  478. #endif
  479. )
  480. {
  481. #ifdef DEBUG
  482. LPWSTR pszControl = TEXT("Unknown");
  483. switch (dwControl)
  484. {
  485. case SERVICE_CONTROL_STOP: pszControl = TEXT("SERVICE_CONTROL_STOP"); break;
  486. case SERVICE_CONTROL_PAUSE: pszControl = TEXT("SERVICE_CONTROL_PAUSE"); break;
  487. case SERVICE_CONTROL_CONTINUE: pszControl = TEXT("SERVICE_CONTROL_CONTINUE"); break;
  488. case SERVICE_CONTROL_INTERROGATE: pszControl = TEXT("SERVICE_CONTROL_INTERROGATE"); break;
  489. case SERVICE_CONTROL_SHUTDOWN: pszControl = TEXT("SERVICE_CONTROL_SHUTDOWN"); break;
  490. case SERVICE_CONTROL_PARAMCHANGE: pszControl = TEXT("SERVICE_CONTROL_PARAMCHANGE"); break;
  491. case SERVICE_CONTROL_NETBINDADD: pszControl = TEXT("SERVICE_CONTROL_NETBINDADD"); break;
  492. case SERVICE_CONTROL_NETBINDREMOVE: pszControl = TEXT("SERVICE_CONTROL_NETBINDREMOVE"); break;
  493. case SERVICE_CONTROL_NETBINDENABLE: pszControl = TEXT("SERVICE_CONTROL_NETBINDENABLE"); break;
  494. case SERVICE_CONTROL_NETBINDDISABLE: pszControl = TEXT("SERVICE_CONTROL_NETBINDDISABLE"); break;
  495. case SERVICE_CONTROL_DEVICEEVENT: pszControl = TEXT("SERVICE_CONTROL_DEVICEEVENT"); break;
  496. case SERVICE_CONTROL_HARDWAREPROFILECHANGE: pszControl = TEXT("SERVICE_CONTROL_HARDWAREPROFILECHANGE"); break;
  497. case SERVICE_CONTROL_POWEREVENT: pszControl = TEXT("SERVICE_CONTROL_POWEREVENT"); break;
  498. case SERVICE_CONTROL_SESSIONCHANGE: pszControl = TEXT("SERVICE_CONTROL_SESSIONCHANGE"); break;
  499. }
  500. TRACE(TF_SERVICE, TEXT("Received Service Control code: %s (0x%08X)"),
  501. pszControl, dwControl);
  502. #endif
  503. }
  504. ///////////////////////////////////////////////////////////////////////////////
  505. // Private
  506. //static
  507. DWORD WINAPI CGenericServiceManager::_ServiceHandler(DWORD dwControl,
  508. DWORD dwEventType, LPVOID pvEventData, LPVOID lpContext)
  509. {
  510. // We don't want to deny any request, so return NO_ERROR whatever happens
  511. DWORD dwRet = NO_ERROR;
  512. // This is called on the main thread not the thread of the specific
  513. // service, so keep it short and sweet
  514. SERVICEENTRY* pse = (SERVICEENTRY*)lpContext;
  515. if (pse)
  516. {
  517. BOOL fProcess = FALSE;
  518. BOOL fSynch = FALSE;
  519. HRESULT hres = S_OK;
  520. switch (dwControl)
  521. {
  522. case SERVICE_CONTROL_STOP:
  523. case SERVICE_CONTROL_SHUTDOWN:
  524. TRACE(TF_SERVICE, TEXT("Received SERVICE_CONTROL_SHUTDOWN or STOP, will skip all other terminating events"));
  525. if (!pse->_fSkipTerminatingEvents)
  526. {
  527. fProcess = TRUE;
  528. pse->_fSkipTerminatingEvents = TRUE;
  529. }
  530. else
  531. {
  532. TRACE(TF_SERVICE, TEXT("Skipping terminating event"));
  533. }
  534. break;
  535. case SERVICE_CONTROL_INTERROGATE:
  536. // Special case SERVICE_CONTROL_INTERROGATE. We don't really need the
  537. // IService impl to process this. The service will also be more
  538. // responsive this way. The state can be queried in the middle of
  539. // execution.
  540. TRACE(TF_SERVICE, TEXT("Received SERVICE_CONTROL_INTERROGATE"));
  541. _SetServiceStatus(pse);
  542. break;
  543. default:
  544. if (!pse->_fSkipTerminatingEvents)
  545. {
  546. fProcess = TRUE;
  547. hres = _EventNeedsToBeProcessedSynchronously(dwControl,
  548. dwEventType, pvEventData, pse, &fSynch);
  549. }
  550. break;
  551. }
  552. if (SUCCEEDED(hres) && fProcess)
  553. {
  554. _TraceServiceCode(dwControl);
  555. EnterCriticalSection(&_cs);
  556. hres = _QueueEvent(pse, dwControl, dwEventType, pvEventData);
  557. if (SUCCEEDED(hres))
  558. {
  559. // Let the service process events
  560. SetEvent(pse->_hEventRelinquishControl);
  561. ResetEvent(pse->_hEventSynchProcessing);
  562. }
  563. LeaveCriticalSection(&_cs);
  564. if (SUCCEEDED(hres) && fSynch)
  565. {
  566. Sleep(0);
  567. TRACE(TF_SERVICE,
  568. TEXT("=========== Processing SYNCHRONOUSLY ==========="));
  569. // We have to wait before we return... (at most 20 sec)
  570. DWORD dwWait = WaitForSingleObject(pse->_hEventSynchProcessing,
  571. 20000);
  572. if (WAIT_TIMEOUT == dwWait)
  573. {
  574. TRACE(TF_SERVICE,
  575. TEXT("=========== WAIT TIMED OUT ==========="));
  576. }
  577. TRACE(TF_SERVICE,
  578. TEXT("=========== FINISHED processing SYNCHRONOUSLY ==========="));
  579. #ifdef DEBUG
  580. // If we get the notifs from a windowproc, return TRUE,
  581. // or else we'll deny any request to remove, lock, ...
  582. if (!_fRunAsService)
  583. {
  584. if (SERVICE_CONTROL_DEVICEEVENT == dwControl)
  585. {
  586. dwRet = TRUE;
  587. }
  588. }
  589. #endif
  590. }
  591. }
  592. }
  593. return dwRet;
  594. }
  595. //static
  596. void WINAPI CGenericServiceManager::_ServiceMain(DWORD cArg, LPWSTR* ppszArgs)
  597. {
  598. SERVICEENTRY* pse;
  599. LPCWSTR pszServiceName = *ppszArgs;
  600. HRESULT hres = _Init();
  601. if (SUCCEEDED(hres))
  602. {
  603. hres = _InitServiceEntry(pszServiceName, &pse);
  604. if (SUCCEEDED(hres))
  605. {
  606. hres = _RegisterServiceCtrlHandler(pszServiceName, pse);
  607. if (SUCCEEDED(hres))
  608. {
  609. pse->_servicestatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
  610. pse->_servicestatus.dwCurrentState = SERVICE_START_PENDING;
  611. _SetServiceStatus(pse);
  612. hres = _CreateIService(pszServiceName, &(pse->_pservice));
  613. if (SUCCEEDED(hres))
  614. {
  615. WCHAR szEventName[MAX_EVENTNAME];
  616. hres = _GetServiceEventName(pszServiceName, szEventName,
  617. ARRAYSIZE(szEventName));
  618. if (SUCCEEDED(hres))
  619. {
  620. hres = pse->_pservice->InitMinimum(cArg, ppszArgs,
  621. szEventName, &(pse->_servicestatus.dwControlsAccepted),
  622. &(pse->_fWantsDeviceEvents));
  623. if (SUCCEEDED(hres))
  624. {
  625. hres = _HandleWantsDeviceEvents(pszServiceName,
  626. pse->_fWantsDeviceEvents);
  627. if (SUCCEEDED(hres))
  628. {
  629. if (pse->_fWantsDeviceEvents)
  630. {
  631. hres = pse->_pservice->InitDeviceEventHandler(
  632. pse->_ssh);
  633. }
  634. if (SUCCEEDED(hres))
  635. {
  636. pse->_servicestatus.dwCurrentState =
  637. SERVICE_RUNNING;
  638. _SetServiceStatus(pse);
  639. hres = pse->_pservice->InitFinal();
  640. if (SUCCEEDED(hres))
  641. {
  642. do
  643. {
  644. hres = pse->_pservice->Run();
  645. if (SUCCEEDED(hres))
  646. {
  647. // The service has finished its business or it
  648. // relinquished control because
  649. // _hEventRelinquishControl is set
  650. //
  651. // If it relinquished control because of a
  652. // service control event, then let's process it
  653. DWORD dwWait = WaitForSingleObject(
  654. pse->_hEventRelinquishControl,
  655. INFINITE);
  656. TRACE(TF_SERVICEDETAILED,
  657. TEXT("WaitForSingleObj returned with: 0x%08X"),
  658. dwWait);
  659. if (WAIT_OBJECT_0 == dwWait)
  660. {
  661. // Process all Service Control codes
  662. // received.
  663. hres = _ProcessServiceControlCodes(
  664. pse);
  665. }
  666. else
  667. {
  668. hres = E_FAIL;
  669. }
  670. }
  671. }
  672. while (SUCCEEDED(hres) &&
  673. (SERVICE_STOPPED !=
  674. pse->_servicestatus.dwCurrentState));
  675. }
  676. }
  677. }
  678. // What do we do with hres?
  679. }
  680. }
  681. }
  682. }
  683. else
  684. {
  685. #ifdef DEBUG
  686. TRACE(TF_SERVICEDETAILED,
  687. TEXT("%s: _RegisterServiceCtrlHandler FAILED: 0x%08X"),
  688. pse->_szServiceName, hres);
  689. #endif
  690. }
  691. _CleanupServiceEntry(pse);
  692. }
  693. if (SUCCEEDED(hres) &&
  694. (SERVICE_STOPPED == pse->_servicestatus.dwCurrentState))
  695. {
  696. _SetServiceStatus(pse);
  697. }
  698. _Cleanup();
  699. }
  700. TRACE(TF_SERVICE, TEXT("Exiting _ServiceMain for Service: %s"), pszServiceName);
  701. }
  702. //static
  703. HRESULT CGenericServiceManager::_ProcessServiceControlCodes(SERVICEENTRY* pse)
  704. {
  705. HRESULT hres;
  706. BOOL fEndLoop = FALSE;
  707. TRACE(TF_SERVICEDETAILED, TEXT("Entered _ProcessServiceControlCodes"));
  708. do
  709. {
  710. CTRLEVENT* pevent;
  711. EnterCriticalSection(&_cs);
  712. TRACE(TF_SERVICEDETAILED, TEXT("Entered _ProcessServiceControlCodes' Critical Section"));
  713. hres = _DeQueueEvent(pse, &pevent);
  714. TRACE(TF_SERVICE, TEXT("DeQueued Event: 0x%08X"), hres);
  715. if (!pse->_peventQueueHead)
  716. {
  717. ASSERT(!pse->_cEvents);
  718. fEndLoop = TRUE;
  719. ResetEvent(pse->_hEventRelinquishControl);
  720. }
  721. LeaveCriticalSection(&_cs);
  722. if (SUCCEEDED(hres))
  723. {
  724. ///////////////////////////////////////////////////////////////////
  725. // If we're here then we should have received some service control,
  726. // or the IService decided it had nothing more to process
  727. //
  728. TRACE(TF_SERVICEDETAILED, TEXT("Will call _HandleServiceControls (dwControl = 0x%08X)"),
  729. pevent->dwControl);
  730. hres = _HandleServiceControls(pse, pevent->dwControl,
  731. pevent->dwEventType, (PVOID)(pevent->rgbEventData));
  732. if (SERVICE_CONTROL_DEVICEEVENT == pevent->dwControl)
  733. {
  734. // Never ever return something else than NO_ERROR (S_OK) for these
  735. hres = NO_ERROR;
  736. }
  737. TRACE(TF_SERVICE, TEXT("_HandleServiceControls returned: 0x%08X"), hres);
  738. LocalFree((HLOCAL)pevent);
  739. }
  740. if (fEndLoop)
  741. {
  742. TRACE(TF_SERVICEDETAILED, TEXT("Resetting RelinquishEvent"));
  743. SetEvent(pse->_hEventSynchProcessing);
  744. }
  745. }
  746. while (!fEndLoop && SUCCEEDED(hres));
  747. TRACE(TF_SERVICEDETAILED, TEXT("Exiting _ProcessServiceControlCodes"));
  748. return hres;
  749. }
  750. #pragma warning(push)
  751. // FALSE positive below: fPending
  752. #pragma warning(disable : 4701)
  753. //static
  754. HRESULT CGenericServiceManager::_HandleServiceControls(SERVICEENTRY* pse,
  755. DWORD dwControl, DWORD dwEventType, PVOID pvEventData)
  756. {
  757. HRESULT hres = _HandlePreState(pse, dwControl);
  758. TRACE(TF_SERVICEDETAILED, TEXT("_HandlePreState returned: 0x%08X, status: 0x%08X"), hres,
  759. pse->_servicestatus.dwCurrentState);
  760. if (SUCCEEDED(hres))
  761. {
  762. if (S_OK == hres)
  763. {
  764. switch (dwControl)
  765. {
  766. case SERVICE_CONTROL_STOP:
  767. case SERVICE_CONTROL_PAUSE:
  768. case SERVICE_CONTROL_CONTINUE:
  769. case SERVICE_CONTROL_SHUTDOWN:
  770. {
  771. BOOL fPending;
  772. do
  773. {
  774. // This will return S_FALSE if it's pending
  775. hres = pse->_pservice->HandleServiceControl(dwControl,
  776. &(pse->_servicestatus.dwWaitHint));
  777. if (SUCCEEDED(hres))
  778. {
  779. if (S_FALSE == hres)
  780. {
  781. ASSERT(pse->_servicestatus.dwWaitHint);
  782. fPending = TRUE;
  783. }
  784. else
  785. {
  786. fPending = FALSE;
  787. }
  788. TRACE(TF_SERVICE, TEXT("Will call _HandlePostState (fPending = %d)"),
  789. fPending);
  790. hres = _HandlePostState(pse, dwControl, fPending);
  791. TRACE(TF_SERVICE, TEXT("_HandlePostState returned: 0x%08X, status: 0x%08X"),
  792. hres, pse->_servicestatus.dwCurrentState);
  793. }
  794. }
  795. while (SUCCEEDED(hres) && fPending);
  796. break;
  797. }
  798. case SERVICE_CONTROL_DEVICEEVENT:
  799. TRACE(TF_SERVICE, TEXT("Received SERVICE_CONTROL_DEVICEEVENT"));
  800. if (!(pse->_fSkipTerminatingEvents))
  801. {
  802. hres = pse->_pservice->HandleDeviceEvent(dwEventType,
  803. pvEventData);
  804. }
  805. else
  806. {
  807. hres = S_OK;
  808. }
  809. break;
  810. case SERVICE_CONTROL_SESSIONCHANGE:
  811. TRACE(TF_SERVICE, TEXT("Received: SERVICE_CONTROL_SESSIONCHANGE"));
  812. if (!(pse->_fSkipTerminatingEvents))
  813. {
  814. hres = pse->_pservice->HandleSessionChange(dwEventType, pvEventData);
  815. }
  816. else
  817. {
  818. hres = S_OK;
  819. }
  820. break;
  821. default:
  822. TRACE(TF_SERVICE, TEXT("Received unhandled service control"));
  823. hres = S_FALSE;
  824. break;
  825. }
  826. }
  827. }
  828. return hres;
  829. }
  830. #pragma warning(pop)
  831. // static
  832. HRESULT CGenericServiceManager::_GetServiceIndex(LPCWSTR pszServiceName,
  833. DWORD* pdw)
  834. {
  835. HRESULT hres = E_FAIL;
  836. ASSERT(pszServiceName);
  837. ASSERT(pdw);
  838. for (DWORD dw = 0; FAILED(hres) && (dw < _cste); ++dw)
  839. {
  840. if (!lstrcmp(pszServiceName, _rgste[dw].lpServiceName))
  841. {
  842. // Found it
  843. *pdw = dw;
  844. hres = S_OK;
  845. }
  846. }
  847. return hres;
  848. }
  849. HRESULT CGenericServiceManager::_GetServiceCLSID(LPCWSTR pszServiceName,
  850. CLSID* pclsid)
  851. {
  852. ASSERT(pszServiceName);
  853. ASSERT(pclsid);
  854. DWORD dw;
  855. HRESULT hres = _GetServiceIndex(pszServiceName, &dw);
  856. if (SUCCEEDED(hres))
  857. {
  858. // Found it
  859. hres = CLSIDFromProgID(_rgsubservice[dw].pszProgID, pclsid);
  860. }
  861. return hres;
  862. }
  863. HRESULT CGenericServiceManager::_CreateIService(LPCWSTR pszServiceName,
  864. IService** ppservice)
  865. {
  866. CLSID clsid;
  867. HRESULT hres = _GetServiceCLSID(pszServiceName, &clsid);
  868. *ppservice = NULL;
  869. if (SUCCEEDED(hres))
  870. {
  871. hres = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
  872. IID_PPV_ARG(IService, ppservice));
  873. }
  874. return hres;
  875. }
  876. HRESULT CGenericServiceManager::_InitServiceEntry(LPCWSTR pszServiceName,
  877. SERVICEENTRY** ppse)
  878. {
  879. DWORD dw;
  880. HRESULT hres = _GetServiceIndex(pszServiceName, &dw);
  881. if (SUCCEEDED(hres))
  882. {
  883. WCHAR szEventName[MAX_EVENTNAME];
  884. *ppse = &(_rgsubservice[dw].se);
  885. ZeroMemory(*ppse, sizeof(**ppse));
  886. hres = _GetServiceEventName(pszServiceName, szEventName,
  887. ARRAYSIZE(szEventName));
  888. if (SUCCEEDED(hres))
  889. {
  890. (*ppse)->_hEventRelinquishControl = CreateEvent(NULL, TRUE, FALSE,
  891. szEventName);
  892. if (!((*ppse)->_hEventRelinquishControl))
  893. {
  894. hres = E_FAIL;
  895. }
  896. if (SUCCEEDED(hres))
  897. {
  898. (*ppse)->_hEventSynchProcessing = CreateEvent(NULL, TRUE, TRUE,
  899. NULL);
  900. if (!((*ppse)->_hEventSynchProcessing))
  901. {
  902. hres = E_FAIL;
  903. }
  904. }
  905. if (FAILED(hres))
  906. {
  907. _CleanupServiceEntry(*ppse);
  908. }
  909. }
  910. }
  911. return hres;
  912. }
  913. HRESULT CGenericServiceManager::_CleanupServiceEntry(SERVICEENTRY* pse)
  914. {
  915. if (pse->_pservice)
  916. {
  917. pse->_pservice->Release();
  918. }
  919. if (pse->_hEventRelinquishControl)
  920. {
  921. CloseHandle(pse->_hEventRelinquishControl);
  922. }
  923. if (pse->_hEventSynchProcessing)
  924. {
  925. CloseHandle(pse->_hEventSynchProcessing);
  926. }
  927. return S_OK;
  928. }
  929. //static
  930. HRESULT CGenericServiceManager::_HandlePreState(SERVICEENTRY* pse,
  931. DWORD dwControl)
  932. {
  933. HRESULT hres;
  934. BOOL fSetServiceStatus = TRUE;
  935. // _HandleServiceControls will loop until we are not in a pending state.
  936. // All incoming ctrl events are queued, and will be processed on this same
  937. // thread, so we should never enter this fct in a pending state.
  938. ASSERT(SERVICE_STOP_PENDING != pse->_servicestatus.dwCurrentState);
  939. ASSERT(SERVICE_START_PENDING != pse->_servicestatus.dwCurrentState);
  940. ASSERT(SERVICE_CONTINUE_PENDING != pse->_servicestatus.dwCurrentState);
  941. ASSERT(SERVICE_PAUSE_PENDING != pse->_servicestatus.dwCurrentState);
  942. // Should have been processed in _ServiceHandler
  943. ASSERT(SERVICE_CONTROL_INTERROGATE != dwControl);
  944. // We cleanup a bit. If the request is incompatible with the current state
  945. // then we return S_FALSE to instruct _HandleServiceControls to not call
  946. // the IService impl for nothing.
  947. switch (dwControl)
  948. {
  949. case SERVICE_CONTROL_STOP:
  950. switch (pse->_servicestatus.dwCurrentState)
  951. {
  952. case SERVICE_STOPPED:
  953. hres = S_FALSE;
  954. break;
  955. case SERVICE_RUNNING:
  956. case SERVICE_PAUSED:
  957. default:
  958. pse->_servicestatus.dwCurrentState = SERVICE_STOP_PENDING;
  959. hres = S_OK;
  960. break;
  961. }
  962. break;
  963. case SERVICE_CONTROL_PAUSE:
  964. ASSERT(SERVICE_STOPPED != pse->_servicestatus.dwCurrentState);
  965. switch (pse->_servicestatus.dwCurrentState)
  966. {
  967. case SERVICE_PAUSED:
  968. hres = S_FALSE;
  969. break;
  970. case SERVICE_STOPPED:
  971. // Weird, think about it...
  972. hres = S_FALSE;
  973. break;
  974. case SERVICE_RUNNING:
  975. default:
  976. pse->_servicestatus.dwCurrentState = SERVICE_PAUSE_PENDING;
  977. hres = S_OK;
  978. break;
  979. }
  980. break;
  981. case SERVICE_CONTROL_CONTINUE:
  982. ASSERT(SERVICE_STOPPED != pse->_servicestatus.dwCurrentState);
  983. switch (pse->_servicestatus.dwCurrentState)
  984. {
  985. case SERVICE_RUNNING:
  986. hres = S_FALSE;
  987. break;
  988. case SERVICE_STOPPED:
  989. // Weird, think about it...
  990. hres = S_FALSE;
  991. break;
  992. case SERVICE_PAUSED:
  993. default:
  994. pse->_servicestatus.dwCurrentState = SERVICE_CONTINUE_PENDING;
  995. hres = S_OK;
  996. break;
  997. }
  998. break;
  999. case SERVICE_CONTROL_SHUTDOWN:
  1000. fSetServiceStatus = FALSE;
  1001. hres = S_OK;
  1002. break;
  1003. case SERVICE_CONTROL_DEVICEEVENT:
  1004. fSetServiceStatus = FALSE;
  1005. if (pse->_fWantsDeviceEvents)
  1006. {
  1007. hres = S_OK;
  1008. }
  1009. else
  1010. {
  1011. hres = S_FALSE;
  1012. }
  1013. break;
  1014. case SERVICE_CONTROL_SESSIONCHANGE:
  1015. fSetServiceStatus = FALSE;
  1016. hres = S_OK;
  1017. break;
  1018. default:
  1019. hres = S_FALSE;
  1020. break;
  1021. }
  1022. if (fSetServiceStatus)
  1023. {
  1024. _SetServiceStatus(pse);
  1025. }
  1026. return hres;
  1027. }
  1028. //static
  1029. HRESULT CGenericServiceManager::_HandlePostState(SERVICEENTRY* pse,
  1030. DWORD dwControl, BOOL fPending)
  1031. {
  1032. HRESULT hres = S_FALSE;
  1033. // All incoming ctrl events are queued, and will be processed on this same
  1034. // thread, so if we are pending, the dwControl should be compatible with
  1035. // our current pending state. We call _SetServiceStatus to update the
  1036. // dwWaitHint.
  1037. // We should already be in a pending state. This should have been set
  1038. // by _HandlePreState. Just make sure of this.
  1039. // Should have been processed in _ServiceHandler
  1040. ASSERT(SERVICE_CONTROL_INTERROGATE != dwControl);
  1041. switch (dwControl)
  1042. {
  1043. case SERVICE_CONTROL_STOP:
  1044. ASSERT(SERVICE_STOP_PENDING == pse->_servicestatus.dwCurrentState);
  1045. if (!fPending)
  1046. {
  1047. pse->_servicestatus.dwCurrentState = SERVICE_STOPPED;
  1048. }
  1049. break;
  1050. case SERVICE_CONTROL_PAUSE:
  1051. ASSERT(SERVICE_PAUSE_PENDING ==
  1052. pse->_servicestatus.dwCurrentState);
  1053. if (!fPending)
  1054. {
  1055. pse->_servicestatus.dwCurrentState = SERVICE_PAUSED;
  1056. }
  1057. break;
  1058. case SERVICE_CONTROL_CONTINUE:
  1059. ASSERT(SERVICE_CONTINUE_PENDING ==
  1060. pse->_servicestatus.dwCurrentState);
  1061. if (!fPending)
  1062. {
  1063. pse->_servicestatus.dwCurrentState = SERVICE_RUNNING;
  1064. }
  1065. break;
  1066. case SERVICE_CONTROL_SHUTDOWN:
  1067. ASSERT(!fPending);
  1068. pse->_servicestatus.dwCurrentState = SERVICE_STOPPED;
  1069. break;
  1070. }
  1071. if (SERVICE_STOPPED != pse->_servicestatus.dwCurrentState)
  1072. {
  1073. _SetServiceStatus(pse);
  1074. }
  1075. return hres;
  1076. }
  1077. // static
  1078. HRESULT CGenericServiceManager::_EventNeedsToBeProcessedSynchronously(
  1079. DWORD dwControl, DWORD dwEventType, LPVOID pvEventData, SERVICEENTRY*,
  1080. BOOL* pfBool)
  1081. {
  1082. *pfBool = FALSE;
  1083. if (SERVICE_CONTROL_DEVICEEVENT == dwControl)
  1084. {
  1085. if (pvEventData)
  1086. {
  1087. DEV_BROADCAST_HDR* dbhdr = (DEV_BROADCAST_HDR*)pvEventData;
  1088. if (DBT_DEVTYP_HANDLE == dbhdr->dbch_devicetype)
  1089. {
  1090. if (DBT_DEVICEQUERYREMOVE == dwEventType)
  1091. {
  1092. TRACE(TF_SERVICE, TEXT("Received DBT_DEVICEQUERYREMOVE"));
  1093. *pfBool = TRUE;
  1094. }
  1095. else
  1096. {
  1097. if (DBT_CUSTOMEVENT == dwEventType)
  1098. {
  1099. DEV_BROADCAST_HANDLE* pdbh =
  1100. (DEV_BROADCAST_HANDLE*)dbhdr;
  1101. if ((GUID_IO_VOLUME_LOCK == pdbh->dbch_eventguid))
  1102. {
  1103. TRACE(TF_SERVICE, TEXT("------------Received GUID_IO_VOLUME_LOCK------------"));
  1104. }
  1105. if ((GUID_IO_VOLUME_LOCK_FAILED == pdbh->dbch_eventguid))
  1106. {
  1107. TRACE(TF_SERVICE, TEXT("------------Received GUID_IO_VOLUME_LOCK_FAILED------------"));
  1108. }
  1109. if ((GUID_IO_VOLUME_UNLOCK == pdbh->dbch_eventguid))
  1110. {
  1111. TRACE(TF_SERVICE, TEXT("------------Received GUID_IO_VOLUME_UNLOCK------------"));
  1112. }
  1113. if ((GUID_IO_VOLUME_LOCK == pdbh->dbch_eventguid) ||
  1114. (GUID_IO_VOLUME_LOCK_FAILED == pdbh->dbch_eventguid) ||
  1115. (GUID_IO_VOLUME_UNLOCK == pdbh->dbch_eventguid))
  1116. {
  1117. *pfBool = TRUE;
  1118. }
  1119. }
  1120. }
  1121. }
  1122. }
  1123. }
  1124. return S_OK;
  1125. }
  1126. // static
  1127. HRESULT CGenericServiceManager::_MakeEvent(DWORD dwControl, DWORD dwEventType,
  1128. PVOID pvEventData, CTRLEVENT** ppevent)
  1129. {
  1130. HRESULT hres = S_OK;
  1131. DWORD cbSize = sizeof(CTRLEVENT);
  1132. CTRLEVENT* pevent;
  1133. if (SERVICE_CONTROL_DEVICEEVENT == dwControl)
  1134. {
  1135. if (pvEventData)
  1136. {
  1137. cbSize += ((DEV_BROADCAST_HDR*)pvEventData)->dbch_size;
  1138. }
  1139. }
  1140. pevent = (CTRLEVENT*)LocalAlloc(LPTR, cbSize);
  1141. if (pevent)
  1142. {
  1143. // Payload
  1144. pevent->dwControl = dwControl;
  1145. pevent->dwEventType = dwEventType;
  1146. *ppevent = pevent;
  1147. if (cbSize > sizeof(CTRLEVENT))
  1148. {
  1149. if (pvEventData)
  1150. {
  1151. CopyMemory(pevent->rgbEventData, pvEventData,
  1152. cbSize - sizeof(CTRLEVENT));
  1153. }
  1154. }
  1155. }
  1156. else
  1157. {
  1158. hres = E_OUTOFMEMORY;
  1159. }
  1160. return hres;
  1161. }
  1162. // static
  1163. HRESULT CGenericServiceManager::_QueueEvent(SERVICEENTRY* pse, DWORD dwControl,
  1164. DWORD dwEventType, PVOID pvEventData)
  1165. {
  1166. CTRLEVENT* pevent;
  1167. HRESULT hres = _MakeEvent(dwControl, dwEventType, pvEventData, &pevent);
  1168. if (SUCCEEDED(hres))
  1169. {
  1170. // We add at tail, remove at head
  1171. // Prev: closer to head
  1172. // Next: closer to tail
  1173. pevent->peventNext = NULL;
  1174. if (pse->_peventQueueTail)
  1175. {
  1176. ASSERT(!(pse->_peventQueueTail->peventNext));
  1177. pse->_peventQueueTail->peventNext = pevent;
  1178. }
  1179. pse->_peventQueueTail = pevent;
  1180. if (!pse->_peventQueueHead)
  1181. {
  1182. pse->_peventQueueHead = pse->_peventQueueTail;
  1183. }
  1184. #ifdef DEBUG
  1185. ++(pse->_cEvents);
  1186. if (1 == pse->_cEvents)
  1187. {
  1188. ASSERT(pse->_peventQueueHead == pse->_peventQueueTail);
  1189. }
  1190. else
  1191. {
  1192. if (0 == pse->_cEvents)
  1193. {
  1194. ASSERT(!pse->_peventQueueHead && !pse->_peventQueueTail);
  1195. }
  1196. else
  1197. {
  1198. ASSERT(pse->_peventQueueHead && pse->_peventQueueTail &&
  1199. (pse->_peventQueueHead != pse->_peventQueueTail));
  1200. }
  1201. }
  1202. #endif
  1203. }
  1204. else
  1205. {
  1206. hres = E_OUTOFMEMORY;
  1207. }
  1208. return hres;
  1209. }
  1210. // static
  1211. HRESULT CGenericServiceManager::_DeQueueEvent(SERVICEENTRY* pse,
  1212. CTRLEVENT** ppevent)
  1213. {
  1214. ASSERT(pse->_peventQueueHead);
  1215. // We add at tail, remove at head
  1216. // Prev: closer to head
  1217. // Next: closer to tail
  1218. CTRLEVENT* peventRet = pse->_peventQueueHead;
  1219. CTRLEVENT* peventNewHead = peventRet->peventNext;
  1220. // Any elem left after removing head?
  1221. if (!peventNewHead)
  1222. {
  1223. // No
  1224. pse->_peventQueueTail = NULL;
  1225. }
  1226. pse->_peventQueueHead = peventNewHead;
  1227. peventRet->peventNext = NULL;
  1228. *ppevent = peventRet;
  1229. #ifdef DEBUG
  1230. --(pse->_cEvents);
  1231. if (1 == pse->_cEvents)
  1232. {
  1233. ASSERT(pse->_peventQueueHead == pse->_peventQueueTail);
  1234. }
  1235. else
  1236. {
  1237. if (0 == pse->_cEvents)
  1238. {
  1239. ASSERT(!pse->_peventQueueHead && !pse->_peventQueueTail);
  1240. }
  1241. else
  1242. {
  1243. ASSERT(pse->_peventQueueHead && pse->_peventQueueTail &&
  1244. (pse->_peventQueueHead != pse->_peventQueueTail));
  1245. }
  1246. }
  1247. #endif
  1248. return S_OK;
  1249. }
  1250. HRESULT _GetServiceEventName(LPCWSTR pszServiceName, LPWSTR pszEventName,
  1251. DWORD cchEventName)
  1252. {
  1253. LPWSTR pszNext;
  1254. DWORD cchLeft;
  1255. HRESULT hres = SafeStrCpyNEx(pszEventName, pszServiceName, cchEventName,
  1256. &pszNext, &cchLeft);
  1257. if (SUCCEEDED(hres))
  1258. {
  1259. hres = SafeStrCpyN(pszNext, TEXT("'sEvent"), cchLeft);
  1260. }
  1261. return hres;
  1262. }