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.

391 lines
10 KiB

  1. /*++
  2. Module Name:
  3. template.c
  4. Abstract:
  5. This is a template for a service.
  6. Author:
  7. Environment:
  8. User Mode -Win32
  9. Revision History:
  10. --*/
  11. //
  12. // Includes
  13. //
  14. #include <windows.h>
  15. #include <stdio.h>
  16. //
  17. // Globals
  18. //
  19. SERVICE_STATUS MyServiceStatus;
  20. SERVICE_STATUS_HANDLE MyServiceStatusHandle;
  21. //
  22. // Function Prototypes
  23. //
  24. VOID
  25. MyServiceStart (
  26. DWORD argc,
  27. LPTSTR *argv
  28. );
  29. VOID
  30. MyServiceCtrlHandler (
  31. IN DWORD opcode
  32. );
  33. DWORD
  34. MyServiceInitialization(
  35. DWORD argc,
  36. LPTSTR *argv,
  37. DWORD *specificError
  38. );
  39. VOID
  40. SvcDebugOut(
  41. LPSTR String,
  42. DWORD Status
  43. );
  44. /****************************************************************************/
  45. VOID __cdecl
  46. main(void)
  47. /*++
  48. Routine Description:
  49. This is the main routine for the service process. If serveral services
  50. share the same process, then the names of those services are
  51. simply added to the DispatchTable.
  52. This thread calls StartServiceCtrlDispatcher which connects to the
  53. service controller and then waits in a loop for control requests.
  54. When all the services in the service process have terminated, the
  55. service controller will send a control request to the dispatcher
  56. telling it to shut down. This thread with then return from the
  57. StartServiceCtrlDispatcher call so that the process can terminate.
  58. Arguments:
  59. Return Value:
  60. --*/
  61. {
  62. SERVICE_TABLE_ENTRY DispatchTable[] = {
  63. { TEXT("MyService"), MyServiceStart },
  64. { NULL, NULL }
  65. };
  66. if (!StartServiceCtrlDispatcher( DispatchTable)) {
  67. SvcDebugOut(" [MY_SERVICE] StartServiceCtrlDispatcher error = %d\n",
  68. GetLastError());
  69. }
  70. }
  71. /****************************************************************************/
  72. void
  73. MyServiceStart (
  74. DWORD argc,
  75. LPTSTR *argv
  76. )
  77. /*++
  78. Routine Description:
  79. This is the entry point for the service. When the control dispatcher
  80. is told to start a service, it creates a thread that will begin
  81. executing at this point. The function has access to command line
  82. arguments in the same manner as a main() routine.
  83. Arguments:
  84. argc - Number of arguments being passed to the service. This count will
  85. always be at least one.
  86. argv - A pointer to an array of string pointers. The first string pointer
  87. (argv[0]) always points to the service name.
  88. Return Value:
  89. --*/
  90. {
  91. DWORD status;
  92. DWORD specificError;
  93. //
  94. // Fill in this service's status structure.
  95. // Note, this service says it accepts PAUSE_CONTINUE.
  96. // However, it doesn't do anything interesting when told to
  97. // pause except return the SERVICE_PAUSED status. This is here
  98. // only for the sake of filling out the template. Pause is
  99. // meaningless for many services. If it doesn't add value,
  100. // don't attempt to support PAUSE_CONTINUE.
  101. //
  102. MyServiceStatus.dwServiceType = SERVICE_WIN32;
  103. MyServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  104. MyServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  105. SERVICE_ACCEPT_PAUSE_CONTINUE;
  106. MyServiceStatus.dwWin32ExitCode = 0;
  107. MyServiceStatus.dwServiceSpecificExitCode = 0;
  108. MyServiceStatus.dwCheckPoint = 0;
  109. MyServiceStatus.dwWaitHint = 0;
  110. //
  111. // Register the Control Handler routine.
  112. //
  113. MyServiceStatusHandle = RegisterServiceCtrlHandler(
  114. TEXT("MyService"),
  115. MyServiceCtrlHandler);
  116. if (MyServiceStatusHandle == (SERVICE_STATUS_HANDLE)0) {
  117. SvcDebugOut(" [MY_SERVICE] RegisterServiceCtrlHandler failed %d\n",
  118. GetLastError());
  119. return;
  120. }
  121. ////////////////////////////////////////////////////////////////
  122. //
  123. // This is where the service initialization code goes.
  124. // If initialization takes a long time, the code is expected to
  125. // call SetServiceStatus periodically in order to send out
  126. // wait hints indicating that progress is being made.
  127. //
  128. //
  129. status = MyServiceInitialization(argc,argv, &specificError);
  130. if (status != NO_ERROR) {
  131. MyServiceStatus.dwCurrentState = SERVICE_STOPPED;
  132. MyServiceStatus.dwCheckPoint = 0;
  133. MyServiceStatus.dwWaitHint = 0;
  134. MyServiceStatus.dwWin32ExitCode = status;
  135. MyServiceStatus.dwServiceSpecificExitCode = specificError;
  136. SetServiceStatus (MyServiceStatusHandle, &MyServiceStatus);
  137. return;
  138. }
  139. //
  140. //
  141. ////////////////////////////////////////////////////////////////
  142. //
  143. // Return the status to indicate we are done with intialization.
  144. //
  145. MyServiceStatus.dwCurrentState = SERVICE_RUNNING;
  146. MyServiceStatus.dwCheckPoint = 0;
  147. MyServiceStatus.dwWaitHint = 0;
  148. if (!SetServiceStatus (MyServiceStatusHandle, &MyServiceStatus)) {
  149. status = GetLastError();
  150. SvcDebugOut(" [MY_SERVICE] SetServiceStatus error %ld\n",status);
  151. }
  152. //===============================================================
  153. // This is where the service does its work. Since this service
  154. // doesn't do anything, this function will return.
  155. //
  156. // A real service should use this thread to do whatever work it
  157. // was designed to do. If it doesn't require a thread to do
  158. // any work, then it should return to the caller. It's
  159. // important to return, rather than call ExitThread. Returning
  160. // allows for cleanup of the memory allocated for the arguments.
  161. // A service that only services RPC requests doesn't need this
  162. // thread.
  163. //
  164. //
  165. //===============================================================
  166. SvcDebugOut(" [MY_SERVICE] Returning the Main Thread \n",0);
  167. return;
  168. }
  169. /****************************************************************************/
  170. VOID
  171. MyServiceCtrlHandler (
  172. IN DWORD Opcode
  173. )
  174. /*++
  175. Routine Description:
  176. This function executes in the context of the Control Dispatcher's
  177. thread. Therefore, it it not desirable to perform time-consuming
  178. operations in this function.
  179. If an operation such as a stop is going to take a long time, then
  180. this routine should send the STOP_PENDING status, and then
  181. signal the other service thread(s) that a stop is in progress.
  182. Then it should return so that the Control Dispatcher can service
  183. more requests. One of the other service threads is then responsible
  184. for sending further wait hints, and the final SERVICE_STOPPED.
  185. Arguments:
  186. Opcode - This is the control opcode that indicates what action the service
  187. should take.
  188. Return Value:
  189. none
  190. --*/
  191. {
  192. DWORD status;
  193. //
  194. // Find and operate on the request.
  195. //
  196. switch(Opcode) {
  197. case SERVICE_CONTROL_PAUSE:
  198. //==========================================================
  199. //
  200. // Do whatever it takes to pause here. Then set the status.
  201. // NOTE : Many services don't support pause. If Pause isn't
  202. // supported, then this opcode should never be received.
  203. // However, in case it is, it is appropriate to fall out of
  204. // this switch and return status.
  205. //
  206. //==========================================================
  207. MyServiceStatus.dwCurrentState = SERVICE_PAUSED;
  208. break;
  209. case SERVICE_CONTROL_CONTINUE:
  210. //=============================================================
  211. //
  212. // Do whatever it takes to continue here. Then set the status.
  213. // (See note for PAUSE).
  214. //
  215. //=============================================================
  216. MyServiceStatus.dwCurrentState = SERVICE_RUNNING;
  217. break;
  218. case SERVICE_CONTROL_STOP:
  219. //=============================================================
  220. //
  221. // Do whatever it takes to stop here. Then set the status.
  222. //
  223. // If stopping takes a long time and a SERVICE_STOP_PENDING
  224. // status is necessary, then this thread should notify or
  225. // create another thread to handle the shutdown. In that case
  226. // this thread should send a SERVICE_STOP_PENDING and
  227. // then return.
  228. //
  229. //=============================================================
  230. MyServiceStatus.dwWin32ExitCode = 0;
  231. MyServiceStatus.dwCurrentState = SERVICE_STOPPED;
  232. MyServiceStatus.dwCheckPoint = 0;
  233. MyServiceStatus.dwWaitHint = 0;
  234. if (!SetServiceStatus (MyServiceStatusHandle, &MyServiceStatus)) {
  235. status = GetLastError();
  236. SvcDebugOut(" [MY_SERVICE] SetServiceStatus error %ld\n",status);
  237. }
  238. SvcDebugOut(" [MY_SERVICE] Leaving MyService \n",0);
  239. return;
  240. case SERVICE_CONTROL_INTERROGATE:
  241. //=============================================================
  242. //
  243. // All that needs to be done in this case is to send the
  244. // current status.
  245. //
  246. //=============================================================
  247. break;
  248. default:
  249. SvcDebugOut(" [MY_SERVICE] Unrecognized opcode %ld\n", Opcode);
  250. }
  251. //
  252. // Send a status response.
  253. //
  254. if (!SetServiceStatus (MyServiceStatusHandle, &MyServiceStatus)) {
  255. status = GetLastError();
  256. SvcDebugOut(" [MY_SERVICE] SetServiceStatus error %ld\n",status);
  257. }
  258. return;
  259. }
  260. DWORD
  261. MyServiceInitialization(
  262. DWORD argc,
  263. LPTSTR *argv,
  264. DWORD *specificError
  265. )
  266. {
  267. argv;
  268. argc;
  269. specificError;
  270. return(0);
  271. }
  272. VOID
  273. SvcDebugOut(
  274. LPSTR String,
  275. DWORD Status
  276. )
  277. /*++
  278. Routine Description:
  279. Prints debug information to the debugger.
  280. Arguments:
  281. String - A single string that can contain one formatted output character.
  282. Status - a value that will be used as the formatted character.
  283. Return Value:
  284. none.
  285. --*/
  286. {
  287. CHAR Buffer[1024];
  288. if (strlen(String) < 1000) {
  289. sprintf(Buffer,String,Status);
  290. OutputDebugStringA(Buffer);
  291. }
  292. }