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.

1469 lines
44 KiB

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