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.

401 lines
9.5 KiB

  1. //
  2. // Copyright (C) 1993-1997 Microsoft Corporation. All Rights Reserved.
  3. //
  4. // MODULE: service.c
  5. //
  6. // PURPOSE: Implements functions required by all services
  7. // windows.
  8. //
  9. // FUNCTIONS:
  10. // main(int argc, char **argv);
  11. // NTmain(int argc, char **argv);
  12. // W95main(int argc, char **argv);
  13. // service_ctrl(DWORD dwCtrlCode);
  14. // ControlHandler ( DWORD dwCtrlType ); // DEBUG only
  15. // GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize ); // DEBUG only
  16. //
  17. // COMMENTS:
  18. //
  19. // AUTHOR: Claus Giloi (based on SDK sample)
  20. //
  21. #include "precomp.h"
  22. #ifndef DEBUG
  23. #undef _tprintf
  24. #define _tprintf force_compile_error
  25. #endif // !DEBUG
  26. // internal variables
  27. SERVICE_STATUS g_ssStatus; // current status of the service
  28. SERVICE_STATUS_HANDLE g_sshStatusHandle;
  29. DWORD dwErr = 0;
  30. OSVERSIONINFO g_osvi; // The os version info structure global
  31. BOOL g_fInShutdown = FALSE;
  32. DWORD g_dwMainThreadID = 0;
  33. // internal function prototypes
  34. VOID WINAPI service_ctrl(DWORD dwCtrlCode);
  35. void __cdecl NTmain(int argc, char **argv);
  36. void __cdecl W95main(int argc, char **argv);
  37. // Debug only functionality
  38. #ifdef DEBUG
  39. TCHAR szErr[256];
  40. BOOL bDebug = FALSE;
  41. BOOL WINAPI ControlHandler ( DWORD dwCtrlType );
  42. LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize );
  43. extern BOOL InitDebugMemoryOptions(void);
  44. extern VOID DumpMemoryLeaksAndBreak(void);
  45. #endif // DEBUG
  46. typedef BOOL (WINAPI *PFNCHANGESERVICECONFIG2)(SC_HANDLE, DWORD, LPVOID);
  47. //
  48. // FUNCTION: main
  49. //
  50. // PURPOSE: entrypoint for service
  51. //
  52. // PARAMETERS:
  53. // argc - number of command line arguments
  54. // argv - array of command line arguments
  55. //
  56. // RETURN VALUE:
  57. // none
  58. //
  59. // COMMENTS:
  60. // Get Platform type and
  61. // call appropriate main for platform (NT or Win95)
  62. //
  63. void __cdecl main(int argc, char **argv)
  64. {
  65. #ifdef DEBUG
  66. InitDebugMemoryOptions();
  67. #endif // DEBUG
  68. // Store OS version info
  69. g_osvi.dwOSVersionInfoSize = sizeof(g_osvi);
  70. if (FALSE == ::GetVersionEx(&g_osvi))
  71. {
  72. ERROR_OUT(("GetVersionEx() failed!"));
  73. return;
  74. }
  75. if ( IS_NT )
  76. {
  77. NTmain( argc, argv );
  78. }
  79. else
  80. {
  81. W95main( argc, argv );
  82. }
  83. #ifdef DEBUG
  84. DumpMemoryLeaksAndBreak();
  85. #endif // DEBUG
  86. }
  87. //
  88. // FUNCTION: NTmain
  89. //
  90. // PURPOSE: entrypoint for service
  91. //
  92. // PARAMETERS:
  93. // argc - number of command line arguments
  94. // argv - array of command line arguments
  95. //
  96. // RETURN VALUE:
  97. // none
  98. //
  99. // COMMENTS:
  100. // NTmain() either performs the command line task, or
  101. // call StartServiceCtrlDispatcher to register the
  102. // main service thread. When the this call returns,
  103. // the service has stopped, so exit.
  104. //
  105. void __cdecl NTmain(int argc, char **argv)
  106. {
  107. DWORD dwArgc;
  108. LPTSTR *lpszArgv;
  109. #ifdef UNICODE
  110. lpszArgv = CommandLineToArgvW(GetCommandLineW(), &(dwArgc) );
  111. #else
  112. dwArgc = (DWORD) argc;
  113. lpszArgv = argv;
  114. #endif
  115. #ifdef DEBUG
  116. SetConsoleCtrlHandler( ControlHandler, TRUE );
  117. #endif // DEBUG
  118. MNMServiceStart( dwArgc, lpszArgv );
  119. }
  120. //
  121. // FUNCTION: W95main
  122. //
  123. // PURPOSE: entrypoint for pseudo-service on Win95
  124. //
  125. // PARAMETERS:
  126. // argc - number of command line arguments
  127. // argv - array of command line arguments
  128. //
  129. // RETURN VALUE:
  130. // none
  131. //
  132. // COMMENTS:
  133. // W95main() registers as Win95 service and calls Init routine directly
  134. //
  135. typedef DWORD (WINAPI * REGISTERSERVICEPROC)(DWORD, DWORD);
  136. #ifndef RSP_SIMPLE_SERVICE
  137. #define RSP_SIMPLE_SERVICE 0x00000001
  138. #endif
  139. void __cdecl W95main(int argc, char **argv)
  140. {
  141. HMODULE hKernel;
  142. REGISTERSERVICEPROC lpfnRegisterServiceProcess;
  143. if ( hKernel = GetModuleHandle("KERNEL32.DLL") )
  144. {
  145. if ( lpfnRegisterServiceProcess =
  146. (REGISTERSERVICEPROC)GetProcAddress ( hKernel,
  147. "RegisterServiceProcess" ))
  148. {
  149. if (!lpfnRegisterServiceProcess(NULL, RSP_SIMPLE_SERVICE))
  150. {
  151. ERROR_OUT(("RegisterServiceProcess failed"));
  152. }
  153. }
  154. else
  155. {
  156. ERROR_OUT(("GetProcAddr of RegisterServiceProcess failed"));
  157. }
  158. }
  159. else
  160. {
  161. ERROR_OUT(("GetModuleHandle of KERNEL32.DLL failed"));
  162. }
  163. MNMServiceStart(argc, argv);
  164. }
  165. //
  166. // FUNCTION: service_ctrl
  167. //
  168. // PURPOSE: This function is called by the SCM whenever
  169. // ControlService() is called on this service.
  170. //
  171. // PARAMETERS:
  172. // dwCtrlCode - type of control requested
  173. //
  174. // RETURN VALUE:
  175. // none
  176. //
  177. // COMMENTS:
  178. //
  179. VOID WINAPI service_ctrl(DWORD dwCtrlCode)
  180. {
  181. // Handle the requested control code.
  182. //
  183. switch(dwCtrlCode)
  184. {
  185. // Stop the service.
  186. //
  187. // SERVICE_STOP_PENDING should be reported before
  188. // setting the Stop Event - hServerStopEvent - in
  189. // MNMServiceStop(). This avoids a race condition
  190. // which may result in a 1053 - The Service did not respond...
  191. // error.
  192. case SERVICE_CONTROL_STOP:
  193. ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 30000);
  194. ::PostThreadMessage(g_dwMainThreadID, WM_QUIT, 0, 0);
  195. return;
  196. case SERVICE_CONTROL_SHUTDOWN:
  197. g_fInShutdown = TRUE;
  198. break;
  199. // Update the service status.
  200. //
  201. case SERVICE_CONTROL_INTERROGATE:
  202. break;
  203. case SERVICE_CONTROL_PAUSE:
  204. ReportStatusToSCMgr(SERVICE_PAUSE_PENDING, NO_ERROR, 30000);
  205. return;
  206. case SERVICE_CONTROL_CONTINUE:
  207. ReportStatusToSCMgr(SERVICE_CONTINUE_PENDING, NO_ERROR, 30000);
  208. return;
  209. default:
  210. break;
  211. }
  212. }
  213. //
  214. // FUNCTION: ReportStatusToSCMgr()
  215. //
  216. // PURPOSE: Sets the current status of the service and
  217. // reports it to the Service Control Manager
  218. //
  219. // PARAMETERS:
  220. // dwCurrentState - the state of the service
  221. // dwWin32ExitCode - error code to report
  222. // dwWaitHint - worst case estimate to next checkpoint
  223. //
  224. // RETURN VALUE:
  225. // TRUE - success
  226. // FALSE - failure
  227. //
  228. // COMMENTS:
  229. //
  230. BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
  231. DWORD dwWin32ExitCode,
  232. DWORD dwWaitHint)
  233. {
  234. static DWORD dwCheckPoint = 1;
  235. BOOL fResult = TRUE;
  236. #ifdef DEBUG
  237. if ( bDebug )
  238. return TRUE;
  239. #endif
  240. if ( IS_NT ) // when debugging we don't report to the SCM
  241. {
  242. switch ( dwCurrentState )
  243. {
  244. case SERVICE_START_PENDING:
  245. case SERVICE_STOP_PENDING:
  246. case SERVICE_CONTINUE_PENDING:
  247. case SERVICE_PAUSE_PENDING:
  248. break;
  249. case SERVICE_PAUSED:
  250. case SERVICE_STOPPED:
  251. case SERVICE_RUNNING:
  252. g_ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  253. SERVICE_ACCEPT_PAUSE_CONTINUE ;
  254. break;
  255. }
  256. g_ssStatus.dwCurrentState = dwCurrentState;
  257. g_ssStatus.dwWin32ExitCode = dwWin32ExitCode;
  258. g_ssStatus.dwWaitHint = dwWaitHint;
  259. if ( ( dwCurrentState == SERVICE_RUNNING ) ||
  260. ( dwCurrentState == SERVICE_STOPPED ) ||
  261. ( dwCurrentState == SERVICE_PAUSED ))
  262. g_ssStatus.dwCheckPoint = 0;
  263. else
  264. g_ssStatus.dwCheckPoint = dwCheckPoint++;
  265. // Report the status of the service to the service control manager.
  266. //
  267. if (!(fResult = SetServiceStatus( g_sshStatusHandle, &g_ssStatus))) {
  268. }
  269. }
  270. return fResult;
  271. }
  272. ///////////////////////////////////////////////////////////////////
  273. //
  274. // The following code handles service installation and removal
  275. //
  276. #ifdef DEBUG
  277. ///////////////////////////////////////////////////////////////////
  278. //
  279. // The following code is for running the service as a console app
  280. //
  281. //
  282. // FUNCTION: ControlHandler ( DWORD dwCtrlType )
  283. //
  284. // PURPOSE: Handled console control events
  285. //
  286. // PARAMETERS:
  287. // dwCtrlType - type of control event
  288. //
  289. // RETURN VALUE:
  290. // True - handled
  291. // False - unhandled
  292. //
  293. // COMMENTS:
  294. //
  295. BOOL WINAPI ControlHandler ( DWORD dwCtrlType )
  296. {
  297. switch( dwCtrlType )
  298. {
  299. case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate
  300. case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in debug mode
  301. PostThreadMessage(g_dwMainThreadID, WM_QUIT, 0, 0);
  302. return TRUE;
  303. break;
  304. }
  305. return FALSE;
  306. }
  307. //
  308. // FUNCTION: GetLastErrorText
  309. //
  310. // PURPOSE: copies error message text to string
  311. //
  312. // PARAMETERS:
  313. // lpszBuf - destination buffer
  314. // dwSize - size of buffer
  315. //
  316. // RETURN VALUE:
  317. // destination buffer
  318. //
  319. // COMMENTS:
  320. //
  321. LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize )
  322. {
  323. DWORD dwRet;
  324. LPTSTR lpszTemp = NULL;
  325. dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
  326. NULL,
  327. GetLastError(),
  328. LANG_NEUTRAL,
  329. (LPTSTR)&lpszTemp,
  330. 0,
  331. NULL );
  332. // supplied buffer is not long enough
  333. if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) )
  334. lpszBuf[0] = TEXT('\0');
  335. else
  336. {
  337. lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0'); //remove cr and newline character
  338. _stprintf( lpszBuf, TEXT("%s (0x%x)"), lpszTemp, GetLastError() );
  339. }
  340. if ( lpszTemp )
  341. LocalFree((HLOCAL) lpszTemp );
  342. return lpszBuf;
  343. }
  344. #endif // DEBUG