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.

780 lines
28 KiB

  1. //--------------------------------------------------------------------
  2. // ServiceHost - implementation
  3. // Copyright (C) Microsoft Corporation, 1999
  4. //
  5. // Created by: Louis Thomas (louisth), 9-9-99
  6. //
  7. // Stuff for hosting a service dll
  8. //
  9. #include "pch.h" // precompiled headers
  10. #include "wchar.h"
  11. //####################################################################
  12. // module private
  13. //--------------------------------------------------------------------
  14. // module globals
  15. MODULEPRIVATE HANDLE g_hServiceThread=NULL;
  16. MODULEPRIVATE HANDLE g_hCtrlHandlerAvailEvent=NULL;
  17. MODULEPRIVATE void * g_pvServiceContext=NULL;
  18. MODULEPRIVATE LPHANDLER_FUNCTION_EX g_fnServiceCtrlHandler=NULL;
  19. MODULEPRIVATE HWND g_hwServiceCtrlDlg=NULL;
  20. MODULEPRIVATE SERVICE_STATUS g_ssLastStatus;
  21. #define MYSERVICESTATUSHANDLE ((SERVICE_STATUS_HANDLE)3)
  22. //--------------------------------------------------------------------
  23. MODULEPRIVATE SERVICE_STATUS_HANDLE WINAPI W32TmRegisterServiceCtrlHandlerEx(const WCHAR * wszServiceName, LPHANDLER_FUNCTION_EX fnServiceCtrlHandler, void * pvContext) {
  24. DWORD dwWaitResult;
  25. DebugWPrintf3(L"RegisterServiceCtrlHandlerEx(0x%p, 0x%p, 0x%p) called.\n",wszServiceName, fnServiceCtrlHandler, pvContext);
  26. // make sure we haven't set this already
  27. _MyAssert(NULL!=g_hCtrlHandlerAvailEvent);
  28. dwWaitResult=WaitForSingleObject(g_hCtrlHandlerAvailEvent, 0);
  29. if (WAIT_FAILED==dwWaitResult) {
  30. _IgnoreLastError("WaitForSingleObject");
  31. }
  32. _MyAssert(WAIT_TIMEOUT==dwWaitResult);
  33. // check the service name, just for kicks
  34. _MyAssert(NULL!=wszServiceName);
  35. _MyAssert(NULL==wszServiceName || 0==wcscmp(wszServiceName, wszSERVICENAME));
  36. // save the context
  37. g_pvServiceContext=pvContext;
  38. // save the handler
  39. _MyAssert(NULL!=fnServiceCtrlHandler);
  40. g_fnServiceCtrlHandler=fnServiceCtrlHandler;
  41. if (!SetEvent(g_hCtrlHandlerAvailEvent)) {
  42. _IgnoreLastError("SetEvent");
  43. }
  44. return MYSERVICESTATUSHANDLE;
  45. }
  46. //--------------------------------------------------------------------
  47. MODULEPRIVATE void MyAppendString(WCHAR ** pwszString, const WCHAR * wszAdd) {
  48. // calculate the length
  49. DWORD dwLen=1;
  50. if (NULL!=*pwszString) {
  51. dwLen+=wcslen(*pwszString);
  52. }
  53. dwLen+=wcslen(wszAdd);
  54. // allocate space
  55. WCHAR * wszResult;
  56. wszResult=(WCHAR *)LocalAlloc(LPTR, dwLen*sizeof(WCHAR));
  57. if (NULL==wszResult) {
  58. DebugWPrintf0(L"Out Of Memory in MyAppendString\n");
  59. return;
  60. }
  61. // build the new string
  62. if (NULL==*pwszString) {
  63. wszResult[0]=L'\0';
  64. } else {
  65. wcscpy(wszResult, *pwszString);
  66. }
  67. wcscat(wszResult, wszAdd);
  68. // replace the old one
  69. if (NULL!=*pwszString) {
  70. LocalFree(*pwszString);
  71. }
  72. *pwszString=wszResult;
  73. }
  74. //--------------------------------------------------------------------
  75. MODULEPRIVATE void UpdateServiceCtrlDlg(void) {
  76. if (NULL!=g_hwServiceCtrlDlg) {
  77. WCHAR * wszDesc=NULL;
  78. //SERVICE_STATUS::dwServiceType
  79. MyAppendString(&wszDesc, L"Type: ");
  80. switch (g_ssLastStatus.dwServiceType&(~SERVICE_INTERACTIVE_PROCESS)) {
  81. case SERVICE_WIN32_OWN_PROCESS:
  82. MyAppendString(&wszDesc, L"SERVICE_WIN32_OWN_PROCESS");
  83. break;
  84. case SERVICE_WIN32_SHARE_PROCESS:
  85. MyAppendString(&wszDesc, L"SERVICE_WIN32_SHARE_PROCESS");
  86. break;
  87. case SERVICE_KERNEL_DRIVER:
  88. MyAppendString(&wszDesc, L"SERVICE_KERNEL_DRIVER");
  89. break;
  90. case SERVICE_FILE_SYSTEM_DRIVER:
  91. MyAppendString(&wszDesc, L"SERVICE_FILE_SYSTEM_DRIVER");
  92. break;
  93. default:
  94. MyAppendString(&wszDesc, L"(unknown)");
  95. break;
  96. }
  97. if (g_ssLastStatus.dwServiceType&SERVICE_INTERACTIVE_PROCESS) {
  98. MyAppendString(&wszDesc, L" | SERVICE_INTERACTIVE_PROCESS");
  99. }
  100. //SERVICE_STATUS::dwCurrentState,
  101. MyAppendString(&wszDesc, L"\r\nState: ");
  102. switch (g_ssLastStatus.dwCurrentState) {
  103. case SERVICE_STOPPED:
  104. MyAppendString(&wszDesc, L"SERVICE_STOPPED");
  105. break;
  106. case SERVICE_START_PENDING:
  107. MyAppendString(&wszDesc, L"SERVICE_START_PENDING");
  108. break;
  109. case SERVICE_STOP_PENDING:
  110. MyAppendString(&wszDesc, L"SERVICE_STOP_PENDING");
  111. break;
  112. case SERVICE_RUNNING:
  113. MyAppendString(&wszDesc, L"SERVICE_RUNNING");
  114. break;
  115. case SERVICE_CONTINUE_PENDING:
  116. MyAppendString(&wszDesc, L"SERVICE_CONTINUE_PENDING");
  117. break;
  118. case SERVICE_PAUSE_PENDING:
  119. MyAppendString(&wszDesc, L"SERVICE_PAUSE_PENDING");
  120. break;
  121. case SERVICE_PAUSED:
  122. MyAppendString(&wszDesc, L"SERVICE_PAUSED");
  123. break;
  124. default:
  125. MyAppendString(&wszDesc, L"(unknown)");
  126. break;
  127. }
  128. //SERVICE_STATUS::dwControlsAccepted,
  129. MyAppendString(&wszDesc, L"\r\nControls Accepted: ");
  130. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_DEVICEEVENT), false);
  131. bool bFirst=true;
  132. //-----
  133. if (g_ssLastStatus.dwControlsAccepted&SERVICE_ACCEPT_STOP) {
  134. bFirst=false;
  135. MyAppendString(&wszDesc, L"SERVICE_ACCEPT_STOP");
  136. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_STOP), true);
  137. } else {
  138. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_STOP), false);
  139. }
  140. //-----
  141. if (g_ssLastStatus.dwControlsAccepted&SERVICE_ACCEPT_PAUSE_CONTINUE) {
  142. if (bFirst) {
  143. bFirst=false;
  144. } else {
  145. MyAppendString(&wszDesc, L" | ");
  146. }
  147. MyAppendString(&wszDesc, L"SERVICE_ACCEPT_PAUSE_CONTINUE");
  148. if (SERVICE_PAUSE_PENDING==g_ssLastStatus.dwCurrentState || SERVICE_PAUSED==g_ssLastStatus.dwCurrentState) {
  149. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_PAUSE), false);
  150. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_CONTINUE), true);
  151. } else {
  152. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_PAUSE), true);
  153. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_CONTINUE), false);
  154. }
  155. } else {
  156. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_PAUSE), false);
  157. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_CONTINUE), false);
  158. }
  159. //-----
  160. if (g_ssLastStatus.dwControlsAccepted&SERVICE_ACCEPT_SHUTDOWN) {
  161. if (bFirst) {
  162. bFirst=false;
  163. } else {
  164. MyAppendString(&wszDesc, L" | ");
  165. }
  166. MyAppendString(&wszDesc, L"SERVICE_ACCEPT_SHUTDOWN");
  167. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_SHUTDOWN), true);
  168. } else {
  169. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_SHUTDOWN), false);
  170. }
  171. //-----
  172. if (g_ssLastStatus.dwControlsAccepted&SERVICE_ACCEPT_PARAMCHANGE) {
  173. if (bFirst) {
  174. bFirst=false;
  175. } else {
  176. MyAppendString(&wszDesc, L" | ");
  177. }
  178. MyAppendString(&wszDesc, L"SERVICE_ACCEPT_PARAMCHANGE");
  179. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_PARAMCHANGE), true);
  180. } else {
  181. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_PARAMCHANGE), false);
  182. }
  183. //-----
  184. if (g_ssLastStatus.dwControlsAccepted&SERVICE_ACCEPT_NETBINDCHANGE) {
  185. if (bFirst) {
  186. bFirst=false;
  187. } else {
  188. MyAppendString(&wszDesc, L" | ");
  189. }
  190. MyAppendString(&wszDesc, L"SERVICE_ACCEPT_NETBINDCHANGE");
  191. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_NETBINDADD), true);
  192. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_NETBINDREMOVE), true);
  193. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_NETBINDENABLE), true);
  194. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_NETBINDDISABLE), true);
  195. } else {
  196. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_NETBINDADD), false);
  197. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_NETBINDREMOVE), false);
  198. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_NETBINDENABLE), false);
  199. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_NETBINDDISABLE), false);
  200. }
  201. //-----
  202. if (g_ssLastStatus.dwControlsAccepted&SERVICE_ACCEPT_HARDWAREPROFILECHANGE) {
  203. if (bFirst) {
  204. bFirst=false;
  205. } else {
  206. MyAppendString(&wszDesc, L" | ");
  207. }
  208. MyAppendString(&wszDesc, L"SERVICE_ACCEPT_HARDWAREPROFILECHANGE");
  209. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_HARDWAREPROFILECHANGE), true);
  210. } else {
  211. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_HARDWAREPROFILECHANGE), false);
  212. }
  213. //-----
  214. if (g_ssLastStatus.dwControlsAccepted&SERVICE_ACCEPT_POWEREVENT) {
  215. if (bFirst) {
  216. bFirst=false;
  217. } else {
  218. MyAppendString(&wszDesc, L" | ");
  219. }
  220. MyAppendString(&wszDesc, L"SERVICE_ACCEPT_POWEREVENT");
  221. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_POWEREVENT), true);
  222. } else {
  223. EnableWindow(GetDlgItem(g_hwServiceCtrlDlg, IDC_SC_POWEREVENT), false);
  224. }
  225. //-----
  226. if (bFirst) {
  227. MyAppendString(&wszDesc, L"<none>");
  228. }
  229. //SERVICE_STATUS::dwWin32ExitCode,
  230. //SERVICE_STATUS::dwServiceSpecificExitCode,
  231. //SERVICE_STATUS::dwCheckPoint,
  232. //SERVICE_STATUS::dwWaitHint
  233. WCHAR wszBuf[256];
  234. _snwprintf(wszBuf, 256, L"\r\nWin32 Exit Code: 0x%08X\r\nService Specific Exit Code: 0x%08X\r\nCheckpoint: 0x%08X\r\nWait Hint: 0x%08X",
  235. g_ssLastStatus.dwWin32ExitCode,
  236. g_ssLastStatus.dwServiceSpecificExitCode,
  237. g_ssLastStatus.dwCheckPoint,
  238. g_ssLastStatus.dwWaitHint);
  239. MyAppendString(&wszDesc, wszBuf);
  240. SendDlgItemMessage(g_hwServiceCtrlDlg, IDC_STATUS, WM_SETTEXT, 0, (LPARAM) wszDesc);
  241. LocalFree(wszDesc);
  242. }
  243. }
  244. //--------------------------------------------------------------------
  245. MODULEPRIVATE BOOL WINAPI W32TmSetServiceStatus(SERVICE_STATUS_HANDLE ssh, SERVICE_STATUS * pss) {
  246. const WCHAR * wszState;
  247. switch (pss->dwCurrentState) {
  248. case SERVICE_STOPPED:
  249. wszState=L"SERVICE_STOPPED";
  250. break;
  251. case SERVICE_START_PENDING:
  252. wszState=L"SERVICE_START_PENDING";
  253. break;
  254. case SERVICE_STOP_PENDING:
  255. wszState=L"SERVICE_STOP_PENDING";
  256. break;
  257. case SERVICE_RUNNING:
  258. wszState=L"SERVICE_RUNNING";
  259. break;
  260. case SERVICE_CONTINUE_PENDING:
  261. wszState=L"SERVICE_CONTINUE_PENDING";
  262. break;
  263. case SERVICE_PAUSE_PENDING:
  264. wszState=L"SERVICE_PAUSE_PENDING";
  265. break;
  266. case SERVICE_PAUSED:
  267. wszState=L"SERVICE_PAUSED";
  268. break;
  269. default:
  270. wszState=L"(unknown)";
  271. break;
  272. }
  273. switch (pss->dwCurrentState) {
  274. case SERVICE_STOPPED:
  275. DebugWPrintf4(L"SetServiceStatus called; %s Accept:0x%08X Ret:0x%08X(0x%08X)\n",
  276. wszState,
  277. pss->dwControlsAccepted,
  278. pss->dwWin32ExitCode,
  279. pss->dwServiceSpecificExitCode,
  280. );
  281. break;
  282. case SERVICE_START_PENDING:
  283. case SERVICE_STOP_PENDING:
  284. case SERVICE_PAUSE_PENDING:
  285. case SERVICE_CONTINUE_PENDING:
  286. DebugWPrintf4(L"SetServiceStatus called; %s Accept:0x%08X ChkPt:0x%08X Wait:0x%08X\n",
  287. wszState,
  288. pss->dwControlsAccepted,
  289. pss->dwCheckPoint,
  290. pss->dwWaitHint
  291. );
  292. break;
  293. case SERVICE_RUNNING:
  294. case SERVICE_PAUSED:
  295. default:
  296. DebugWPrintf2(L"SetServiceStatus called; %s Accept:0x%08X\n",
  297. wszState,
  298. pss->dwControlsAccepted
  299. );
  300. break;
  301. }
  302. _MyAssert(MYSERVICESTATUSHANDLE==ssh);
  303. memcpy(&g_ssLastStatus, pss, sizeof(SERVICE_STATUS));
  304. UpdateServiceCtrlDlg();
  305. return true;
  306. }
  307. //--------------------------------------------------------------------
  308. MODULEPRIVATE DWORD WINAPI MyServiceThread(void * pvServiceMain) {
  309. DebugWPrintf0(L"Starting service thread.\n");
  310. ((LPSERVICE_MAIN_FUNCTION)pvServiceMain)(0, NULL);
  311. DebugWPrintf0(L"Service thread exited.\n"); // service may still be running!
  312. return S_OK;
  313. }
  314. //--------------------------------------------------------------------
  315. MODULEPRIVATE INT_PTR CALLBACK ServiceCtrlDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  316. DWORD dwError;
  317. HRESULT hrExit;
  318. if (NULL==g_hwServiceCtrlDlg) {
  319. g_hwServiceCtrlDlg=hwndDlg;
  320. }
  321. switch (uMsg) {
  322. case WM_INITDIALOG:
  323. UpdateServiceCtrlDlg();
  324. return true;
  325. case WM_COMMAND:
  326. switch (LOWORD(wParam)) {
  327. case IDCANCEL:
  328. if (g_ssLastStatus.dwCurrentState!=SERVICE_STOPPED) {
  329. hrExit=HRESULT_FROM_WIN32(ERROR_CANCELLED);
  330. DebugWPrintf1(L"Aborting with error 0x%08X\n", hrExit);
  331. } else {
  332. hrExit=g_ssLastStatus.dwServiceSpecificExitCode;
  333. DebugWPrintf1(L"Exiting with service return value 0x%08X\n", hrExit);
  334. }
  335. EndDialog(hwndDlg, hrExit);
  336. return true;
  337. case IDC_SC_STOP:
  338. DebugWPrintf0(L"Passing SERVICE_CONTROL_STOP to service's control handler.\n");
  339. dwError=g_fnServiceCtrlHandler(SERVICE_CONTROL_STOP, NULL, NULL, g_pvServiceContext);
  340. DebugWPrintf1(L"Service's control handler returns 0x%08X.\n", dwError);
  341. return false;
  342. case IDC_SC_PAUSE:
  343. DebugWPrintf0(L"Passing SERVICE_CONTROL_PAUSE to service's control handler.\n");
  344. dwError=g_fnServiceCtrlHandler(SERVICE_CONTROL_PAUSE, NULL, NULL, g_pvServiceContext);
  345. DebugWPrintf1(L"Service's control handler returns 0x%08X.\n", dwError);
  346. return false;
  347. case IDC_SC_CONTINUE:
  348. DebugWPrintf0(L"Passing SERVICE_CONTROL_CONTINUE to service's control handler.\n");
  349. dwError=g_fnServiceCtrlHandler(SERVICE_CONTROL_CONTINUE, NULL, NULL, g_pvServiceContext);
  350. DebugWPrintf1(L"Service's control handler returns 0x%08X.\n", dwError);
  351. return false;
  352. case IDC_SC_INTERROGATE:
  353. DebugWPrintf0(L"Passing SERVICE_CONTROL_INTERROGATE to service's control handler.\n");
  354. dwError=g_fnServiceCtrlHandler(SERVICE_CONTROL_INTERROGATE, NULL, NULL, g_pvServiceContext);
  355. DebugWPrintf1(L"Service's control handler returns 0x%08X.\n", dwError);
  356. return false;
  357. case IDC_SC_SHUTDOWN:
  358. DebugWPrintf0(L"IDC_SC_SHUTDOWN\n");
  359. return false;
  360. case IDC_SC_PARAMCHANGE:
  361. DebugWPrintf0(L"Passing SERVICE_CONTROL_PARAMCHANGE to service's control handler.\n");
  362. dwError=g_fnServiceCtrlHandler(SERVICE_CONTROL_PARAMCHANGE, NULL, NULL, g_pvServiceContext);
  363. DebugWPrintf1(L"Service's control handler returns 0x%08X.\n", dwError);
  364. return false;
  365. case IDC_SC_NETBINDADD:
  366. DebugWPrintf0(L"Passing SERVICE_CONTROL_NETBINDADD to service's control handler.\n");
  367. dwError=g_fnServiceCtrlHandler(SERVICE_CONTROL_NETBINDADD, NULL, NULL, g_pvServiceContext);
  368. DebugWPrintf1(L"Service's control handler returns 0x%08X.\n", dwError);
  369. return false;
  370. case IDC_SC_NETBINDREMOVE:
  371. DebugWPrintf0(L"Passing SERVICE_CONTROL_NETBINDREMOVE to service's control handler.\n");
  372. dwError=g_fnServiceCtrlHandler(SERVICE_CONTROL_NETBINDREMOVE, NULL, NULL, g_pvServiceContext);
  373. DebugWPrintf1(L"Service's control handler returns 0x%08X.\n", dwError);
  374. return false;
  375. case IDC_SC_NETBINDENABLE:
  376. DebugWPrintf0(L"Passing SERVICE_CONTROL_NETBINDENABLE to service's control handler.\n");
  377. dwError=g_fnServiceCtrlHandler(SERVICE_CONTROL_NETBINDENABLE, NULL, NULL, g_pvServiceContext);
  378. DebugWPrintf1(L"Service's control handler returns 0x%08X.\n", dwError);
  379. return false;
  380. case IDC_SC_NETBINDDISABLE:
  381. DebugWPrintf0(L"Passing SERVICE_CONTROL_NETBINDDISABLE to service's control handler.\n");
  382. dwError=g_fnServiceCtrlHandler(SERVICE_CONTROL_NETBINDDISABLE, NULL, NULL, g_pvServiceContext);
  383. DebugWPrintf1(L"Service's control handler returns 0x%08X.\n", dwError);
  384. return false;
  385. case IDC_SC_DEVICEEVENT:
  386. DebugWPrintf0(L"IDC_SC_DEVICEEVENT NYI\n");
  387. return false;
  388. case IDC_SC_HARDWAREPROFILECHANGE:
  389. DebugWPrintf0(L"IDC_SC_HARDWAREPROFILECHANGE NYI\n");
  390. return false;
  391. case IDC_SC_POWEREVENT:
  392. DebugWPrintf0(L"IDC_SC_POWEREVENT NYI\n");
  393. return false;
  394. default:
  395. //DebugWPrintf2(L"Unknown WM_COMMAND: wParam:0x%08X lParam:0x%08X\n", wParam, lParam);
  396. return false; // unhandled
  397. }
  398. return false; // unhandled
  399. // end case WM_COMMAND
  400. default:
  401. return false; // unhandled
  402. }
  403. return false; // unhandled
  404. }
  405. //--------------------------------------------------------------------
  406. MODULEPRIVATE HRESULT MyServiceCtrlDispatcher(LPSERVICE_MAIN_FUNCTION fnW32TmServiceMain) {
  407. HRESULT hr;
  408. DWORD dwThreadID;
  409. DWORD dwWaitResult;
  410. INT_PTR nDialogError;
  411. g_hCtrlHandlerAvailEvent=CreateEvent(NULL, TRUE, FALSE, NULL);
  412. if (NULL==g_hCtrlHandlerAvailEvent) {
  413. _JumpLastError(hr, error, "CreateEvent");
  414. }
  415. // 'start' the service
  416. g_hServiceThread=CreateThread(NULL, 0, MyServiceThread, (void *)fnW32TmServiceMain, 0, &dwThreadID);
  417. if (NULL==g_hServiceThread) {
  418. _JumpLastError(hr, error, "CreateThread");
  419. }
  420. DebugWPrintf0(L"Waiting for service to register ctrl handler.\n");
  421. _Verify(WAIT_FAILED!=WaitForSingleObject(g_hCtrlHandlerAvailEvent, INFINITE), hr, error);
  422. // do dialog box
  423. nDialogError=DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_SERVICECTRL), NULL, ServiceCtrlDialogProc);
  424. if (-1==nDialogError) {
  425. _JumpLastError(hr, error, "DialogBox");
  426. }
  427. hr=(HRESULT)nDialogError;
  428. _JumpIfError(hr, error, "DialogBox");
  429. // confirm that the thread exited
  430. dwWaitResult=WaitForSingleObject(g_hServiceThread, 0);
  431. if (WAIT_FAILED==dwWaitResult) {
  432. _IgnoreLastError("WaitForSingleObject");
  433. }
  434. _Verify(WAIT_TIMEOUT!=dwWaitResult, hr, error);
  435. // When this exits, everything ends.
  436. hr=S_OK;
  437. error:
  438. if (NULL!=g_hServiceThread) {
  439. CloseHandle(g_hServiceThread);
  440. g_hServiceThread=NULL;
  441. }
  442. if (NULL!=g_hCtrlHandlerAvailEvent) {
  443. CloseHandle(g_hCtrlHandlerAvailEvent);
  444. g_hCtrlHandlerAvailEvent=NULL;
  445. }
  446. return hr;
  447. }
  448. //--------------------------------------------------------------------
  449. MODULEPRIVATE HRESULT GetDllName(WCHAR ** pwszDllName) {
  450. HRESULT hr;
  451. DWORD dwError;
  452. DWORD dwSize;
  453. DWORD dwType;
  454. // must be cleaned up
  455. HKEY hkParams=NULL;
  456. WCHAR * wszDllName=NULL;
  457. WCHAR * wszDllExpandedName=NULL;
  458. // get our config key
  459. dwError=RegOpenKeyEx(HKEY_LOCAL_MACHINE, wszW32TimeRegKeyParameters, 0, KEY_READ, &hkParams);
  460. if (ERROR_SUCCESS!=dwError) {
  461. hr=HRESULT_FROM_WIN32(dwError);
  462. _JumpErrorStr(hr, error, "RegOpenKeyEx", wszW32TimeRegKeyParameters);
  463. }
  464. // read the value containing the DLL name
  465. dwSize=0;
  466. dwError=RegQueryValueEx(hkParams, wszW32TimeRegValueServiceDll, NULL, &dwType, NULL, &dwSize);
  467. if (ERROR_SUCCESS!=dwError) {
  468. hr=HRESULT_FROM_WIN32(dwError);
  469. _JumpErrorStr(hr, error, "RegQueryValueEx", wszW32TimeRegValueServiceDll);
  470. }
  471. _Verify(REG_EXPAND_SZ==dwType, hr, error);
  472. wszDllName=(WCHAR *)LocalAlloc(LPTR, dwSize);
  473. _JumpIfOutOfMemory(hr, error, wszDllName);
  474. dwError=RegQueryValueEx(hkParams, wszW32TimeRegValueServiceDll, NULL, &dwType, (BYTE *)wszDllName, &dwSize);
  475. if (ERROR_SUCCESS!=dwError) {
  476. hr=HRESULT_FROM_WIN32(dwError);
  477. _JumpErrorStr(hr, error, "RegQueryValueEx", wszW32TimeRegValueServiceDll);
  478. }
  479. // expand environment string
  480. dwSize=ExpandEnvironmentStrings(wszDllName, NULL, 0);
  481. if (0==dwSize) {
  482. _JumpLastError(hr, error, "ExpandEnvironmentStrings");
  483. }
  484. wszDllExpandedName=(WCHAR *)LocalAlloc(LPTR, dwSize*sizeof(WCHAR));
  485. _JumpIfOutOfMemory(hr, error, wszDllExpandedName);
  486. dwSize=ExpandEnvironmentStrings(wszDllName, wszDllExpandedName, dwSize);
  487. if (0==dwSize) {
  488. _JumpLastError(hr, error, "ExpandEnvironmentStrings");
  489. }
  490. // success
  491. *pwszDllName=wszDllExpandedName;
  492. wszDllExpandedName=NULL;
  493. error:
  494. if (NULL!=wszDllExpandedName) {
  495. LocalFree(wszDllExpandedName);
  496. }
  497. if (NULL!=wszDllName) {
  498. LocalFree(wszDllName);
  499. }
  500. if (NULL!=hkParams) {
  501. RegCloseKey(hkParams);
  502. }
  503. return hr;
  504. }
  505. //####################################################################
  506. // module public
  507. //--------------------------------------------------------------------
  508. // run W32Time as a real service under the SCM
  509. HRESULT RunAsService(void) {
  510. HRESULT hr;
  511. SERVICE_STATUS_HANDLE (WINAPI ** pfnW32TmRegisterServiceCtrlHandlerEx)(LPCWSTR, LPHANDLER_FUNCTION_EX, LPVOID);
  512. BOOL (WINAPI ** pfnW32TmSetServiceStatus)(SERVICE_STATUS_HANDLE, LPSERVICE_STATUS);
  513. SERVICE_TABLE_ENTRY rgsteDispatchTable[]= {
  514. { wszSERVICENAME, NULL},
  515. {NULL, NULL}
  516. };
  517. // must be cleaned up
  518. HINSTANCE hW32Time=NULL;
  519. WCHAR * wszDllName=NULL;
  520. // load the library
  521. hr=GetDllName(&wszDllName);
  522. _JumpIfError(hr, error, "GetDllName");
  523. hW32Time=LoadLibrary(wszDllName);
  524. if (NULL==hW32Time) {
  525. _JumpLastError(hr, error, "LoadLibrary");
  526. }
  527. // get the entry point
  528. rgsteDispatchTable[0].lpServiceProc=(LPSERVICE_MAIN_FUNCTION)GetProcAddress(hW32Time, "W32TmServiceMain");
  529. if (NULL==rgsteDispatchTable[0].lpServiceProc) {
  530. _JumpLastErrorStr(hr, error, "GetProcAddress", L"W32TmServiceMain");
  531. }
  532. // adjust the function pointers
  533. pfnW32TmRegisterServiceCtrlHandlerEx=(SERVICE_STATUS_HANDLE (WINAPI **)(LPCWSTR, LPHANDLER_FUNCTION_EX, LPVOID))GetProcAddress(hW32Time, "fnW32TmRegisterServiceCtrlHandlerEx");
  534. if (NULL==pfnW32TmRegisterServiceCtrlHandlerEx) {
  535. _JumpLastErrorStr(hr, error, "GetProcAddress", L"fnW32TmRegisterServiceCtrlHandlerEx");
  536. }
  537. *pfnW32TmRegisterServiceCtrlHandlerEx=RegisterServiceCtrlHandlerExW;
  538. pfnW32TmSetServiceStatus=(BOOL (WINAPI **)(SERVICE_STATUS_HANDLE, LPSERVICE_STATUS))GetProcAddress(hW32Time, "fnW32TmSetServiceStatus");
  539. if (NULL==pfnW32TmSetServiceStatus) {
  540. _JumpLastErrorStr(hr, error, "GetProcAddress", L"fnW32TmSetServiceStatus");
  541. }
  542. *pfnW32TmSetServiceStatus=SetServiceStatus;
  543. // This thread becomes the service control dispatcher.
  544. if (!StartServiceCtrlDispatcher(rgsteDispatchTable)) {
  545. _JumpLastError(hr, error, "StartServiceCtrlDispatcher");
  546. }
  547. // service is stopped.
  548. hr=S_OK;
  549. error:
  550. if (NULL!=wszDllName) {
  551. LocalFree(wszDllName);
  552. }
  553. if (NULL!=hW32Time) {
  554. FreeLibrary(hW32Time);
  555. }
  556. if (FAILED(hr)) {
  557. WCHAR * wszError;
  558. HRESULT hr2=GetSystemErrorString(hr, &wszError);
  559. if (FAILED(hr2)) {
  560. _IgnoreError(hr2, "GetSystemErrorString");
  561. } else {
  562. LocalizedWPrintf2(IDS_W32TM_ERRORGENERAL_ERROR_OCCURED, L" %s\n", wszError);
  563. LocalFree(wszError);
  564. }
  565. }
  566. return hr;
  567. }
  568. //--------------------------------------------------------------------
  569. // pretend to run as a service for easier debugging
  570. HRESULT RunAsTestService(void) {
  571. HRESULT hr;
  572. LPSERVICE_MAIN_FUNCTION fnW32TmServiceMain;
  573. SERVICE_STATUS_HANDLE (WINAPI ** pfnW32TmRegisterServiceCtrlHandlerEx)(LPCWSTR, LPHANDLER_FUNCTION_EX, LPVOID);
  574. BOOL (WINAPI ** pfnW32TmSetServiceStatus)(SERVICE_STATUS_HANDLE, LPSERVICE_STATUS);
  575. // must be cleaned up
  576. HINSTANCE hW32Time=NULL;
  577. WCHAR * wszDllName=NULL;
  578. // load the library
  579. hr=GetDllName(&wszDllName);
  580. _JumpIfError(hr, error, "GetDllName");
  581. hW32Time=LoadLibrary(wszDllName);
  582. if (NULL==hW32Time) {
  583. _JumpLastError(hr, error, "LoadLibrary");
  584. }
  585. // get the entry point
  586. fnW32TmServiceMain=(LPSERVICE_MAIN_FUNCTION)GetProcAddress(hW32Time, "W32TmServiceMain");
  587. if (NULL==fnW32TmServiceMain) {
  588. _JumpLastErrorStr(hr, error, "GetProcAddress", L"W32TmServiceMain");
  589. }
  590. // adjust the function pointers
  591. pfnW32TmRegisterServiceCtrlHandlerEx=(SERVICE_STATUS_HANDLE (WINAPI **)(LPCWSTR, LPHANDLER_FUNCTION_EX, LPVOID))GetProcAddress(hW32Time, "fnW32TmRegisterServiceCtrlHandlerEx");
  592. if (NULL==pfnW32TmRegisterServiceCtrlHandlerEx) {
  593. _JumpLastErrorStr(hr, error, "GetProcAddress", L"fnW32TmRegisterServiceCtrlHandlerEx");
  594. }
  595. *pfnW32TmRegisterServiceCtrlHandlerEx=W32TmRegisterServiceCtrlHandlerEx;
  596. // adjust the function pointers
  597. pfnW32TmSetServiceStatus=(BOOL (WINAPI **)(SERVICE_STATUS_HANDLE, LPSERVICE_STATUS))GetProcAddress(hW32Time, "fnW32TmSetServiceStatus");
  598. if (NULL==pfnW32TmSetServiceStatus) {
  599. _JumpLastErrorStr(hr, error, "GetProcAddress", L"fnW32TmSetServiceStatus");
  600. }
  601. *pfnW32TmSetServiceStatus=W32TmSetServiceStatus;
  602. // This thread becomes the service control dispatcher.
  603. hr=MyServiceCtrlDispatcher(fnW32TmServiceMain);
  604. _JumpIfError(hr, error, "MyServiceCtrlDispatcher");
  605. // service is stopped.
  606. hr=S_OK;
  607. error:
  608. if (NULL!=wszDllName) {
  609. LocalFree(wszDllName);
  610. }
  611. if (NULL!=hW32Time) {
  612. FreeLibrary(hW32Time);
  613. }
  614. if (FAILED(hr)) {
  615. WCHAR * wszError;
  616. HRESULT hr2=GetSystemErrorString(hr, &wszError);
  617. if (FAILED(hr2)) {
  618. _IgnoreError(hr2, "GetSystemErrorString");
  619. } else {
  620. LocalizedWPrintf2(IDS_W32TM_ERRORGENERAL_ERROR_OCCURED, L" %s\n", wszError);
  621. LocalFree(wszError);
  622. }
  623. }
  624. return hr;
  625. }
  626. //--------------------------------------------------------------------
  627. HRESULT RegisterDll(void) {
  628. HRESULT hr;
  629. HRESULT (__stdcall * pfnDllRegisterServer)(void);
  630. // must be cleaned up
  631. HINSTANCE hW32Time=NULL;
  632. // load the library
  633. hW32Time=LoadLibrary(wszDLLNAME);
  634. if (NULL==hW32Time) {
  635. _JumpLastError(hr, error, "LoadLibrary");
  636. }
  637. // get the entry point
  638. pfnDllRegisterServer=(HRESULT (__stdcall *) (void))GetProcAddress(hW32Time, "DllRegisterServer");
  639. if (NULL==pfnDllRegisterServer) {
  640. _JumpLastErrorStr(hr, error, "GetProcAddress", L"DllRegisterServer");
  641. }
  642. hr=pfnDllRegisterServer();
  643. _JumpIfError(hr, error, "DllRegisterServer");
  644. LocalizedWPrintfCR(IDS_W32TM_STATUS_REGISTER_SUCCESSFUL);
  645. hr=S_OK;
  646. error:
  647. if (NULL!=hW32Time) {
  648. FreeLibrary(hW32Time);
  649. }
  650. if (FAILED(hr)) {
  651. WCHAR * wszError;
  652. HRESULT hr2=GetSystemErrorString(hr, &wszError);
  653. if (FAILED(hr2)) {
  654. _IgnoreError(hr2, "GetSystemErrorString");
  655. } else {
  656. LocalizedWPrintf2(IDS_W32TM_ERRORGENERAL_ERROR_OCCURED, L" %s\n", wszError);
  657. LocalFree(wszError);
  658. }
  659. }
  660. return hr;
  661. };
  662. //--------------------------------------------------------------------
  663. HRESULT UnregisterDll(void) {
  664. HRESULT hr;
  665. HRESULT (__stdcall * pfnDllUnregisterServer)(void);
  666. // must be cleaned up
  667. HINSTANCE hW32Time=NULL;
  668. // load the library
  669. hW32Time=LoadLibrary(wszDLLNAME);
  670. if (NULL==hW32Time) {
  671. _JumpLastError(hr, error, "LoadLibrary");
  672. }
  673. // get the entry point
  674. pfnDllUnregisterServer=(HRESULT (__stdcall *) (void))GetProcAddress(hW32Time, "DllUnregisterServer");
  675. if (NULL==pfnDllUnregisterServer) {
  676. _JumpLastErrorStr(hr, error, "GetProcAddress", L"DllUnregisterServer");
  677. }
  678. hr=pfnDllUnregisterServer();
  679. _JumpIfError(hr, error, "DllUnregisterServer");
  680. LocalizedWPrintfCR(IDS_W32TM_STATUS_REGISTER_SUCCESSFUL);
  681. hr=S_OK;
  682. error:
  683. if (NULL!=hW32Time) {
  684. FreeLibrary(hW32Time);
  685. }
  686. if (FAILED(hr)) {
  687. WCHAR * wszError;
  688. HRESULT hr2=GetSystemErrorString(hr, &wszError);
  689. if (FAILED(hr2)) {
  690. _IgnoreError(hr2, "GetSystemErrorString");
  691. } else {
  692. LocalizedWPrintf2(IDS_W32TM_ERRORGENERAL_ERROR_OCCURED, L" %s\n", wszError);
  693. LocalFree(wszError);
  694. }
  695. }
  696. return hr;
  697. };