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.

406 lines
12 KiB

  1. #include "shsrvice.h"
  2. #include "mischlpr.h"
  3. #include "dbg.h"
  4. #include "tfids.h"
  5. #define ARRAYSIZE(a) (sizeof((a))/sizeof((a)[0]))
  6. #define SC_PAUSE 0
  7. #define SC_CONTINUE 1
  8. #define SC_STOP 2
  9. #define SC_SHUTDOWN 3
  10. #define SC_INTERROGATE 4
  11. DWORD rgdwControlCodes[] =
  12. {
  13. SERVICE_CONTROL_PAUSE, // 0x00000002
  14. SERVICE_CONTROL_CONTINUE, // 0x00000003
  15. SERVICE_CONTROL_STOP, // 0x00000001
  16. SERVICE_CONTROL_SHUTDOWN, // 0x00000005
  17. SERVICE_CONTROL_INTERROGATE, // 0x00000004
  18. };
  19. static SERVICEENTRY* g_pseWantsDeviceEvents = NULL;
  20. static SERVICEENTRY** g_ppse = NULL;
  21. static HWND g_hwnd = NULL;
  22. static HANDLE* g_phEvent = NULL;
  23. LRESULT _FakeWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  24. DWORD WINAPI _ServiceMainCaller(PVOID pvParam)
  25. {
  26. LPWSTR* ppsz = (LPWSTR*)pvParam;
  27. TRACE(TF_SERVICEASPROCESS, TEXT("%s: _ServiceMainCaller called"),
  28. (LPWSTR)*ppsz);
  29. CGenericServiceManager::_ServiceMain(1, (LPWSTR*)pvParam);
  30. return 0;
  31. }
  32. DWORD _ServiceIndexFromServiceName(SERVICE_TABLE_ENTRY* pste,
  33. LPCWSTR pszServiceName)
  34. {
  35. DWORD dw = 0;
  36. while (pste[dw].lpServiceName)
  37. {
  38. if (!lstrcmp(pste[dw].lpServiceName, pszServiceName))
  39. {
  40. break;
  41. }
  42. else
  43. {
  44. ++dw;
  45. }
  46. }
  47. return dw;
  48. }
  49. //static
  50. HRESULT CGenericServiceManager::_RegisterServiceCtrlHandler(
  51. LPCWSTR pszServiceName, SERVICEENTRY* pse)
  52. {
  53. ASSERT(pse);
  54. TRACE(TF_SERVICEASPROCESS, TEXT("%s: _RegisterServiceCtrlHandler called"),
  55. pszServiceName);
  56. g_ppse[_ServiceIndexFromServiceName(_rgste, pszServiceName)] = pse;
  57. #ifdef DEBUG
  58. lstrcpy(pse->_szServiceName, pszServiceName);
  59. #endif
  60. return S_OK;
  61. }
  62. // static
  63. HRESULT CGenericServiceManager::_HandleWantsDeviceEvents(
  64. LPCWSTR pszServiceName, BOOL UNREF_PARAM(fWantsDeviceEvents))
  65. {
  66. HRESULT hres = E_FAIL;
  67. DWORD dwWait;
  68. DWORD dwService = _ServiceIndexFromServiceName(_rgste, pszServiceName);
  69. TRACE(TF_SERVICEASPROCESS, TEXT("%s: _HandleWantsDeviceEvents (1)"),
  70. pszServiceName);
  71. // We need to release the main service thread, so that it can create
  72. // the fake wnd that will receive the WM_DEVICECHANGE msgs to fake
  73. // the SERVICE_CONTROL_DEVICEEVENT.
  74. SetEvent(g_phEvent[dwService]);
  75. TRACE(TF_SERVICEASPROCESS, TEXT("%s: _HandleWantsDeviceEvents (2)"),
  76. pszServiceName);
  77. // Let's relinquish our remaining time slice. Or else we won't wait on
  78. // the following line.
  79. // That's not fool proof (might not work) but this is test code...
  80. Sleep(0);
  81. TRACE(TF_SERVICEASPROCESS, TEXT("%s: _HandleWantsDeviceEvents (3)"),
  82. pszServiceName);
  83. // We wait until the main service thread is done with the window creation.
  84. // Then g_hwnd wil lbe set and we'll be able to use it to register for
  85. // notif.
  86. dwWait = WaitForSingleObject(g_phEvent[dwService], INFINITE);
  87. TRACE(TF_SERVICEASPROCESS, TEXT("%s: _HandleWantsDeviceEvents (4)"),
  88. pszServiceName);
  89. if (WAIT_OBJECT_0 == dwWait)
  90. {
  91. hres = S_OK;
  92. }
  93. CloseHandle(g_phEvent[dwService]);
  94. g_phEvent[dwService] = NULL;
  95. return hres;
  96. }
  97. // static
  98. HRESULT CGenericServiceManager::StartServiceCtrlDispatcher()
  99. {
  100. HRESULT hres = E_FAIL;
  101. HANDLE* phEvents;
  102. g_ppse = (SERVICEENTRY**)LocalAlloc(LPTR, sizeof(SERVICEENTRY*) * _cste);
  103. phEvents = (HANDLE*)LocalAlloc(LPTR, sizeof(HANDLE) * _cste * 5);
  104. g_phEvent = (HANDLE*)LocalAlloc(LPTR, sizeof(HANDLE) * _cste);
  105. if (g_ppse && phEvents && g_phEvent)
  106. {
  107. for (DWORD dwService = 0; dwService < _cste; ++dwService)
  108. {
  109. WCHAR szEventName[256];
  110. LPWSTR pszServiceName = _rgste[dwService].lpServiceName;
  111. hres = S_OK;
  112. lstrcpy(szEventName, _rgste[dwService].lpServiceName);
  113. lstrcat(szEventName, TEXT(".SC_PAUSE"));
  114. phEvents[dwService * 5 + SC_PAUSE] = CreateEvent(NULL, TRUE,
  115. FALSE, szEventName);
  116. lstrcpy(szEventName, _rgste[dwService].lpServiceName);
  117. lstrcat(szEventName, TEXT(".SC_CONTINUE"));
  118. phEvents[dwService * 5 + SC_CONTINUE] = CreateEvent(NULL, TRUE,
  119. FALSE, szEventName);
  120. lstrcpy(szEventName, _rgste[dwService].lpServiceName);
  121. lstrcat(szEventName, TEXT(".SC_STOP"));
  122. phEvents[dwService * 5 + SC_STOP] = CreateEvent(NULL, TRUE,
  123. FALSE, szEventName);
  124. lstrcpy(szEventName, _rgste[dwService].lpServiceName);
  125. lstrcat(szEventName, TEXT(".SC_SHUTDOWN"));
  126. phEvents[dwService * 5 + SC_SHUTDOWN] = CreateEvent(NULL, TRUE,
  127. FALSE, szEventName);
  128. lstrcpy(szEventName, _rgste[dwService].lpServiceName);
  129. lstrcat(szEventName, TEXT(".SC_INTERROGATE"));
  130. phEvents[dwService * 5 + SC_INTERROGATE] = CreateEvent(NULL, TRUE,
  131. FALSE, szEventName);
  132. for (DWORD dwEvent = SC_PAUSE; SUCCEEDED(hres) &&
  133. (dwEvent <= SC_INTERROGATE); ++dwEvent)
  134. {
  135. if (!phEvents[(dwService * 5) + dwEvent])
  136. {
  137. hres = E_FAIL;
  138. }
  139. }
  140. if (SUCCEEDED(hres))
  141. {
  142. g_phEvent[dwService] = CreateEvent(NULL, FALSE, FALSE, NULL);
  143. if (g_phEvent[dwService])
  144. {
  145. CreateThread(NULL, 0, _ServiceMainCaller,
  146. (LPWSTR*)&(_rgste[dwService].lpServiceName), 0, NULL);
  147. // We have to wait for the IService impl to be CoCreated and
  148. // queried for fWantsDeviceEvents. So we block here.
  149. // _HandleWantsDeviceEvents will unblock us when
  150. // fWantsDeviceEvents will be known.
  151. TRACE(TF_SERVICEASPROCESS,
  152. TEXT("%s: StartServiceCtrlDispatcher (1)"),
  153. pszServiceName);
  154. DWORD dwWait = WaitForSingleObject(g_phEvent[dwService],
  155. INFINITE);
  156. TRACE(TF_SERVICEASPROCESS,
  157. TEXT("%s: StartServiceCtrlDispatcher (2)"),
  158. pszServiceName);
  159. if (WAIT_OBJECT_0 == dwWait)
  160. {
  161. if (g_ppse[dwService]->_fWantsDeviceEvents)
  162. {
  163. WNDCLASSEX wndclass;
  164. HINSTANCE hinst = GetModuleHandle(NULL);
  165. g_pseWantsDeviceEvents = g_ppse[dwService];
  166. if (hinst)
  167. {
  168. wndclass.cbSize = sizeof(wndclass);
  169. wndclass.style = NULL;
  170. wndclass.lpfnWndProc = _FakeWndProc;
  171. wndclass.cbClsExtra = 0;
  172. wndclass.cbWndExtra = 0;
  173. wndclass.hInstance = hinst;
  174. wndclass.hIcon = NULL;
  175. wndclass.hCursor = NULL;
  176. wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  177. wndclass.lpszMenuName = NULL;
  178. wndclass.lpszClassName = TEXT("FakeWnd");
  179. wndclass.hIconSm = NULL;
  180. if (RegisterClassEx(&wndclass))
  181. {
  182. g_hwnd = CreateWindow(TEXT("FakeWnd"), TEXT("FakeWnd"),
  183. WS_POPUPWINDOW, 0, 0, 100, 200, NULL, NULL, hinst, NULL);
  184. if (g_hwnd)
  185. {
  186. g_pseWantsDeviceEvents->_ssh =
  187. (SERVICE_STATUS_HANDLE)g_hwnd;
  188. }
  189. }
  190. }
  191. }
  192. // We're done with the window creation, release the IService
  193. // impl thread.
  194. SetEvent(g_phEvent[dwService]);
  195. }
  196. }
  197. }
  198. TRACE(TF_SERVICEASPROCESS,
  199. TEXT("%s: StartServiceCtrlDispatcher (3)"),
  200. pszServiceName);
  201. }
  202. while (SUCCEEDED(hres))
  203. {
  204. DWORD dw = MsgWaitForMultipleObjects(_cste * 5,
  205. phEvents, FALSE, INFINITE, QS_ALLINPUT);
  206. if (WAIT_FAILED != dw)
  207. {
  208. if ((_cste * 5) == (dw - WAIT_OBJECT_0))
  209. {
  210. MSG msg;
  211. if (GetMessage(&msg, NULL, 0, 0))
  212. {
  213. if (WM_DEVICECHANGE != msg.message)
  214. {
  215. DispatchMessage(&msg);
  216. }
  217. else
  218. {
  219. // To mimic the true service behavior, deliver
  220. // these messages only if the "service" is
  221. // running
  222. if (SERVICE_RUNNING ==
  223. g_pseWantsDeviceEvents->_servicestatus.dwCurrentState)
  224. {
  225. DispatchMessage(&msg);
  226. }
  227. }
  228. }
  229. }
  230. else
  231. {
  232. DWORD dwService2 = ((dw - WAIT_OBJECT_0 + 1) / 5);
  233. if (NO_ERROR != _ServiceHandler(
  234. rgdwControlCodes[(dw - WAIT_OBJECT_0) -
  235. (dwService2 * 5)], 0, NULL, (PVOID)g_ppse[dwService2]))
  236. {
  237. hres = E_FAIL;
  238. }
  239. }
  240. }
  241. else
  242. {
  243. hres = E_FAIL;
  244. }
  245. }
  246. }
  247. else
  248. {
  249. hres = E_OUTOFMEMORY;
  250. }
  251. return hres;
  252. }
  253. #ifdef DEBUG
  254. BOOL CGenericServiceManager::_SetServiceStatus(SERVICEENTRY* pse)
  255. {
  256. WCHAR sz[256];
  257. lstrcpy(sz, pse->_szServiceName);
  258. switch (pse->_servicestatus.dwCurrentState)
  259. {
  260. case SERVICE_STOPPED:
  261. lstrcat(sz, TEXT(": SERVICE_STOPPED"));
  262. break;
  263. case SERVICE_START_PENDING:
  264. lstrcat(sz, TEXT(": SERVICE_START_PENDING"));
  265. break;
  266. case SERVICE_STOP_PENDING:
  267. lstrcat(sz, TEXT(": SERVICE_STOP_PENDING"));
  268. break;
  269. case SERVICE_RUNNING:
  270. lstrcat(sz, TEXT(": SERVICE_RUNNING"));
  271. break;
  272. case SERVICE_CONTINUE_PENDING:
  273. lstrcat(sz, TEXT(": SERVICE_CONTINUE_PENDING"));
  274. break;
  275. case SERVICE_PAUSE_PENDING:
  276. lstrcat(sz, TEXT(": SERVICE_PAUSE_PENDING"));
  277. break;
  278. case SERVICE_PAUSED:
  279. lstrcat(sz, TEXT(": SERVICE_PAUSED"));
  280. break;
  281. default:
  282. lstrcat(sz, TEXT(": Unknown state"));
  283. break;
  284. }
  285. TRACE(TF_SERVICE, sz);
  286. return TRUE;
  287. }
  288. #else
  289. BOOL CGenericServiceManager::_SetServiceStatus(SERVICEENTRY*)
  290. {
  291. return TRUE;
  292. }
  293. #endif
  294. ///////////////////////////////////////////////////////////////////////////////
  295. // Wnd stuff
  296. LRESULT _FakeWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  297. {
  298. LRESULT lRes = 0;
  299. BOOL fProcessed = FALSE;
  300. switch (uMsg)
  301. {
  302. case WM_DEVICECHANGE:
  303. {
  304. fProcessed = TRUE;
  305. lRes = CGenericServiceManager::_ServiceHandler(
  306. SERVICE_CONTROL_DEVICEEVENT, (DWORD)wParam, (PVOID)lParam,
  307. (PVOID)g_pseWantsDeviceEvents);
  308. if ((NO_ERROR != lRes) && (TRUE != lRes))
  309. {
  310. ASSERT(FALSE);
  311. }
  312. break;
  313. }
  314. case WM_DESTROY:
  315. // Should cleanup here
  316. fProcessed = FALSE;
  317. break;
  318. default:
  319. fProcessed = FALSE;
  320. break;
  321. }
  322. if (!fProcessed)
  323. {
  324. lRes = DefWindowProc(hWnd, uMsg, wParam, lParam);
  325. }
  326. return lRes;
  327. }