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.

392 lines
13 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. CNTSERV.CPP
  5. Abstract:
  6. A class which allows easy creation of Win32 Services. This class
  7. only allows one service per .EXE file. The process can be run as a
  8. service or a regular non-service EXE, a runtime option.
  9. This class is largly based on the SMS CService class which was created by
  10. a-raymcc. This differs in that it is simplified in two ways; First, it
  11. does not keep track of the worker threads since that is the responsibility
  12. of the derived code, and second, it doesnt use some SMS specific diagnostics
  13. NOTE: See the file SERVICE.TXT for details on how to use this class.
  14. There are a number of issues which cannot be conveyed by simply studying
  15. the class declaration.
  16. History:
  17. a-davj 20-June-96 Created.
  18. --*/
  19. #include "precomp.h"
  20. #include <wtypes.h>
  21. #include <stdio.h>
  22. #include "cntserv.h"
  23. //****************************************************************************
  24. //
  25. // CNtService::CNtService
  26. // CNtService::~CNtService
  27. //
  28. // Constructor and destructor.
  29. //
  30. //****************************************************************************
  31. CNtService::CNtService(DWORD ControlAccepted)
  32. {
  33. m_dwCtrlAccepted = ControlAccepted;
  34. m_bStarted = FALSE;
  35. m_pszServiceName = NULL;
  36. }
  37. CNtService::~CNtService()
  38. {
  39. if(m_pszServiceName)
  40. delete m_pszServiceName;
  41. }
  42. //
  43. //
  44. // CNtService::Run
  45. //
  46. //
  47. //////////////////////////////////////////////////////////////////
  48. DWORD CNtService::Run(LPWSTR pszServiceName,
  49. DWORD dwNumServicesArgs,
  50. LPWSTR *lpServiceArgVectors,
  51. PVOID lpData)
  52. {
  53. size_t cchSizeTmp = lstrlen(pszServiceName)+1;
  54. m_pszServiceName = new TCHAR[cchSizeTmp];
  55. if(m_pszServiceName == NULL)
  56. return ERROR_NOT_ENOUGH_MEMORY;
  57. StringCchCopyW(m_pszServiceName,cchSizeTmp,pszServiceName);
  58. // Register our service control handler.
  59. // =====================================
  60. sshStatusHandle = RegisterServiceCtrlHandlerEx(m_pszServiceName,
  61. (LPHANDLER_FUNCTION_EX)CNtService::_HandlerEx,
  62. lpData);
  63. if (!sshStatusHandle)
  64. {
  65. Log(TEXT("Initial call to RegisterServiceCtrlHandler failed"));
  66. goto cleanup;
  67. }
  68. ssStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
  69. ssStatus.dwServiceSpecificExitCode = 0;
  70. // Report the status to the service control manager.
  71. // =================================================
  72. if (!ReportStatusToSCMgr(
  73. SERVICE_START_PENDING, // service state
  74. NO_ERROR, // exit code
  75. 1, // checkpoint
  76. DEFAULT_WAIT_HINT)) // wait hint
  77. goto cleanup;
  78. if (!Initialize(dwNumServicesArgs, lpServiceArgVectors))
  79. {
  80. Log(TEXT("Initialize call failed, bailing out"));
  81. goto cleanup;
  82. }
  83. // Report the status to the service control manager.
  84. // =================================================
  85. if (!ReportStatusToSCMgr(
  86. SERVICE_RUNNING, // service state
  87. NO_ERROR, // exit code
  88. 0, // checkpoint
  89. 0)) // wait hint
  90. goto cleanup;
  91. m_bStarted = TRUE;
  92. // The next routine is always over ridden and is
  93. // where the acutal work of the service is done.
  94. // =============================================
  95. WorkerThread();
  96. // Service is done, send last report to SCM.
  97. // =========================================
  98. cleanup:
  99. m_bStarted = FALSE;
  100. //
  101. //
  102. // we cannot rely on the distructor to be called after
  103. // the SetServiceStatus(STOPPED) to perform operations
  104. //
  105. /////////////////////////////////////////////////////////
  106. FinalCleanup();
  107. ReportStatusToSCMgr(
  108. SERVICE_STOPPED, // service state
  109. NO_ERROR, // exit code
  110. 0, // checkpoint
  111. 0); // wait hint
  112. return 0;
  113. }
  114. //
  115. //
  116. // CNtService::Log
  117. //
  118. //
  119. //////////////////////////////////////////////////////////////////
  120. VOID CNtService::Log(LPCTSTR lpszMsg)
  121. {
  122. TCHAR szMsg[256];
  123. HANDLE hEventSource;
  124. LPCTSTR lpszStrings[2];
  125. DWORD dwErr = GetLastError();
  126. StringCchPrintf(szMsg,256, TEXT("%s error: %d"), m_pszServiceName, dwErr);
  127. // Dump the error code and text message out to the event log
  128. hEventSource = RegisterEventSource(NULL, m_pszServiceName);
  129. lpszStrings[0] = szMsg;
  130. lpszStrings[1] = lpszMsg;
  131. if (hEventSource != NULL)
  132. {
  133. ReportEvent(hEventSource, // handle of event source
  134. EVENTLOG_ERROR_TYPE, // event type
  135. 0, // event category
  136. 0, // event ID
  137. NULL, // current user's SID
  138. 2, // strings in lpszStrings
  139. 0, // no bytes of raw data
  140. lpszStrings, // array of error strings
  141. NULL); // no raw data
  142. DeregisterEventSource(hEventSource);
  143. }
  144. }
  145. //****************************************************************************
  146. //
  147. // CNtService::_Handler
  148. //
  149. // Entry points for calls from the NT service control manager. These entry
  150. // points just call the actual functions using the default object.
  151. //
  152. //****************************************************************************
  153. DWORD WINAPI CNtService::_HandlerEx(
  154. DWORD dwControl, // requested control code
  155. DWORD dwEventType, // event type
  156. LPVOID lpEventData, // event data
  157. LPVOID lpContext // user-defined context data
  158. )
  159. {
  160. _DBG_ASSERT(lpContext);
  161. return ((CNtService *)lpContext)->HandlerEx(dwControl,dwEventType,lpEventData,lpContext);
  162. }
  163. //****************************************************************************
  164. //
  165. // CNtService::ReportStatusToSCMgr
  166. //
  167. // Used by other member functions to report their status to the
  168. // service control manager.
  169. //
  170. // Parameters:
  171. // DWORD dwCurrentState One of the SERVICE_ codes.
  172. // DWORD dwWin32ExitCode A Win32 Error code; usually 0.
  173. // DWORD dwCheckPoint Checkpoint value (not used).
  174. // DWORD dwWaitHint Milliseconds before Service Control
  175. // Manager gets worried.
  176. // Returns:
  177. //
  178. // BOOL fResult Whatever code was returned
  179. // by SetServiceStatus().
  180. //
  181. //****************************************************************************
  182. BOOL CNtService::ReportStatusToSCMgr(DWORD dwCurrentState,
  183. DWORD dwWin32ExitCode, DWORD dwCheckPoint, DWORD dwWaitHint)
  184. {
  185. BOOL fResult;
  186. // Disable control requests until the service is started.
  187. // ======================================================
  188. if (dwCurrentState == SERVICE_START_PENDING)
  189. {
  190. ssStatus.dwControlsAccepted = 0;
  191. }
  192. else if (dwCurrentState == SERVICE_STOPPED)
  193. {
  194. ssStatus.dwControlsAccepted = 0;
  195. }
  196. else
  197. {
  198. ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN |
  199. m_dwCtrlAccepted;
  200. }
  201. // These SERVICE_STATUS members are set from parameters.
  202. // =====================================================
  203. ssStatus.dwCurrentState = dwCurrentState;
  204. ssStatus.dwWin32ExitCode = dwWin32ExitCode;
  205. ssStatus.dwCheckPoint = dwCheckPoint;
  206. ssStatus.dwWaitHint = dwWaitHint;
  207. // Report the status of the service to the service control manager.
  208. // ================================================================
  209. if (!(fResult = SetServiceStatus(
  210. sshStatusHandle, // service reference handle
  211. &ssStatus)))
  212. {
  213. // If an error occurs, log it.
  214. // =====================================
  215. Log(TEXT("Could not SetServiceStatus"));
  216. }
  217. return fResult;
  218. }
  219. //*****************************************************************************
  220. //
  221. // CNtService::Handler
  222. //
  223. // This handles incoming messages from the Service Controller.
  224. //
  225. // Parameters:
  226. //
  227. // DWORD dwControlCode One of the SERVICE_CONTROL_
  228. // codes or a user defined code 125..255.
  229. //
  230. //*****************************************************************************
  231. DWORD WINAPI
  232. CNtService::HandlerEx( DWORD dwControl, // requested control code
  233. DWORD dwEventType, // event type
  234. LPVOID lpEventData, // event data
  235. LPVOID lpContext // user-defined context data
  236. )
  237. {
  238. switch(dwControl) {
  239. // Pause, set initial status, call overriden function and set final status
  240. //========================================================================
  241. case SERVICE_CONTROL_PAUSE:
  242. ReportStatusToSCMgr(
  243. SERVICE_PAUSE_PENDING, // current state
  244. NO_ERROR, // exit code
  245. 1, // checkpoint
  246. DEFAULT_WAIT_HINT); // wait hint
  247. Pause();
  248. ReportStatusToSCMgr(
  249. SERVICE_PAUSED, // current state
  250. NO_ERROR, // exit code
  251. 0, // checkpoint
  252. 0); // wait hint
  253. break;
  254. // Continue, set initial status, call overriden function and set final status
  255. //===========================================================================
  256. case SERVICE_CONTROL_CONTINUE:
  257. ReportStatusToSCMgr(
  258. SERVICE_CONTINUE_PENDING, // current state
  259. NO_ERROR, // exit code
  260. 1, // checkpoint
  261. DEFAULT_WAIT_HINT); // wait hint
  262. Continue();
  263. ReportStatusToSCMgr(
  264. SERVICE_RUNNING, // current state
  265. NO_ERROR, // exit code
  266. 0, // checkpoint
  267. 0); // wait hint
  268. break;
  269. // Stop the service. Note that the Stop function is supposed
  270. // to signal the worker thread which should return which then
  271. // causes the StartMain() function to end which sends the
  272. // final status!
  273. //==========================================================
  274. case SERVICE_CONTROL_SHUTDOWN:
  275. case SERVICE_CONTROL_STOP:
  276. ReportStatusToSCMgr(
  277. SERVICE_STOP_PENDING, // current state
  278. NO_ERROR, // exit code
  279. 1, // checkpoint
  280. DEFAULT_WAIT_HINT); // wait hint
  281. Stop((dwControl == SERVICE_CONTROL_SHUTDOWN)?TRUE:FALSE);
  282. break;
  283. // Could get an interrogate at any time, just report the current status.
  284. //======================================================================
  285. case SERVICE_CONTROL_INTERROGATE:
  286. ReportStatusToSCMgr(
  287. ssStatus.dwCurrentState, // current state
  288. NO_ERROR, // exit code
  289. 1, // checkpoint
  290. DEFAULT_WAIT_HINT); // wait hint
  291. break;
  292. // Some user defined code. Call the overriden function and report status.
  293. //========================================================================
  294. default:
  295. ReportStatusToSCMgr(
  296. ssStatus.dwCurrentState, // current state
  297. NO_ERROR, // exit code
  298. 1, // checkpoint
  299. DEFAULT_WAIT_HINT); // wait hint
  300. return ERROR_CALL_NOT_IMPLEMENTED;
  301. }
  302. return NO_ERROR;
  303. }