|
|
1.1 root 1:
2: /******************************************************************************\
3: * This is a part of the Microsoft Source Code Samples.
4: * Copyright (C) 1993 Microsoft Corporation.
5: * All rights reserved.
6: * This source code is only intended as a supplement to
7: * Microsoft Development Tools and/or WinHelp documentation.
8: * See these sources for detailed information regarding the
9: * Microsoft samples programs.
10: \******************************************************************************/
11:
12: ///////////////////////////////////////////////////////
13: //
14: // Service.c --
15: // main program for Service sample.
16: //
17: // This service simply opens a named pipe
18: // (called \\.\pipe\simple), and reads from it.
19: // It then mangles the data passed in and writes
20: // the result back out to the pipe.
21: //
22: // The simple service will respond to the basic
23: // service controller functions, i.e. Start,
24: // Stop, and Pause.
25: //
26:
27: #include <windows.h>
28: #include <stdio.h>
29: #include <stdlib.h>
30: #include <process.h>
31:
32: // this event is signalled when the
33: // worker thread ends
34: //
35: HANDLE hServDoneEvent = NULL;
36: SERVICE_STATUS ssStatus; // current status of the service
37:
38: SERVICE_STATUS_HANDLE sshStatusHandle;
39: DWORD dwGlobalErr;
40: DWORD TID = 0;
41: HANDLE threadHandle = NULL;
42: HANDLE pipeHandle;
43:
44:
45: // declare the service threads:
46: //
47: VOID service_main(DWORD dwArgc, LPTSTR *lpszArgv);
48: VOID service_ctrl(DWORD dwCtrlCode);
49: BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
50: DWORD dwWin32ExitCode,
51: DWORD dwCheckPoint,
52: DWORD dwWaitHint);
53: VOID StopSampleService(LPTSTR lpszMsg);
54: VOID die(char *reason);
55: VOID worker_thread(VOID *notUsed);
56: VOID StopSimpleService(LPTSTR lpszMsg);
57:
58:
59:
60: // main() --
61: // all main does is call StartServiceCtrlDispatcher
62: // to register the main service thread. When the
63: // API returns, the service has stopped, so exit.
64: //
65: VOID
66: main()
67: {
68: SERVICE_TABLE_ENTRY dispatchTable[] = {
69: { TEXT("SimpleService"), (LPSERVICE_MAIN_FUNCTION)service_main },
70: { NULL, NULL }
71: };
72:
73: if (!StartServiceCtrlDispatcher(dispatchTable)) {
74: StopSimpleService("StartServiceCtrlDispatcher failed.");
75: }
76: }
77:
78:
79:
80: // service_main() --
81: // this function takes care of actually starting the service,
82: // informing the service controller at each step along the way.
83: // After launching the worker thread, it waits on the event
84: // that the worker thread will signal at its termination.
85: //
86: VOID
87: service_main(DWORD dwArgc, LPTSTR *lpszArgv)
88: {
89: DWORD dwWait;
90: PSECURITY_DESCRIPTOR pSD;
91: SECURITY_ATTRIBUTES sa;
92:
93: // register our service control handler:
94: //
95: sshStatusHandle = RegisterServiceCtrlHandler(
96: TEXT("SimpleService"),
97: service_ctrl);
98:
99: if (!sshStatusHandle)
100: goto cleanup;
101:
102: // SERVICE_STATUS members that don't change in example
103: //
104: ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
105: ssStatus.dwServiceSpecificExitCode = 0;
106:
107:
108: // report the status to Service Control Manager.
109: //
110: if (!ReportStatusToSCMgr(
111: SERVICE_START_PENDING, // service state
112: NO_ERROR, // exit code
113: 1, // checkpoint
114: 3000)) // wait hint
115: goto cleanup;
116:
117: // create the event object. The control handler function signals
118: // this event when it receives the "stop" control code.
119: //
120: hServDoneEvent = CreateEvent(
121: NULL, // no security attributes
122: TRUE, // manual reset event
123: FALSE, // not-signalled
124: NULL); // no name
125:
126: if (hServDoneEvent == (HANDLE)NULL)
127: goto cleanup;
128:
129: // report the status to the service control manager.
130: //
131: if (!ReportStatusToSCMgr(
132: SERVICE_START_PENDING, // service state
133: NO_ERROR, // exit code
134: 2, // checkpoint
135: 3000)) // wait hint
136: goto cleanup;
137:
138: // create a security descriptor that allows anyone to write to
139: // the pipe...
140: //
141: pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,
142: SECURITY_DESCRIPTOR_MIN_LENGTH);
143:
144: if (pSD == NULL) {
145: StopSimpleService("LocalAlloc pSD failed");
146: return;
147: }
148:
149: if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) {
150: StopSimpleService("InitializeSecurityDescriptor failed");
151: LocalFree((HLOCAL)pSD);
152: return;
153: }
154:
155: // add a NULL disc. ACL to the security descriptor.
156: //
157: if (!SetSecurityDescriptorDacl(pSD, TRUE, (PACL) NULL, FALSE)) {
158: StopSimpleService("SetSecurityDescriptorDacl failed");
159: LocalFree((HLOCAL)pSD);
160: return;
161: }
162:
163: sa.nLength = sizeof(sa);
164: sa.lpSecurityDescriptor = pSD;
165: sa.bInheritHandle = TRUE; // why not...
166:
167: // open our named pipe...
168: //
169: pipeHandle = CreateNamedPipe(
170: "\\\\.\\pipe\\simple", // name of pipe
171: PIPE_ACCESS_DUPLEX, // pipe open mode
172: PIPE_TYPE_MESSAGE |
173: PIPE_READMODE_MESSAGE |
174: PIPE_WAIT, // pipe IO type
175: 1, // number of instances
176: 0, // size of outbuf (0 == allocate as necessary)
177: 0, // size of inbuf
178: 1000, // default time-out value
179: &sa); // security attributes
180:
181: if (!pipeHandle) {
182: StopSimpleService("CreateNamedPipe");
183: LocalFree((HLOCAL)pSD);
184: return;
185: }
186:
187: // start the thread that performs the work of the service.
188: //
189: threadHandle = (HANDLE)_beginthread(
190: worker_thread,
191: 4096, // stack size
192: NULL); // argument to thread
193:
194: if (!threadHandle)
195: goto cleanup;
196:
197: // report the status to the service control manager.
198: //
199: if (!ReportStatusToSCMgr(
200: SERVICE_RUNNING, // service state
201: NO_ERROR, // exit code
202: 0, // checkpoint
203: 0)) // wait hint
204: goto cleanup;
205:
206: // wait indefinitely until hServDoneEvent is signaled.
207: //
208: dwWait = WaitForSingleObject(
209: hServDoneEvent, // event object
210: INFINITE); // wait indefinitely
211:
212: cleanup:
213:
214: if (hServDoneEvent != NULL)
215: CloseHandle(hServDoneEvent);
216:
217:
218: // try to report the stopped status to the service control manager.
219: //
220: if (sshStatusHandle != 0)
221: (VOID)ReportStatusToSCMgr(
222: SERVICE_STOPPED,
223: dwGlobalErr,
224: 0,
225: 0);
226:
227: // When SERVICE MAIN FUNCTION returns in a single service
228: // process, the StartServiceCtrlDispatcher function in
229: // the main thread returns, terminating the process.
230: //
231: return;
232: }
233:
234:
235:
236: // service_ctrl() --
237: // this function is called by the Service Controller whenever
238: // someone calls ControlService in reference to our service.
239: //
240: VOID
241: service_ctrl(DWORD dwCtrlCode)
242: {
243: DWORD dwState = SERVICE_RUNNING;
244:
245: // Handle the requested control code.
246: //
247: switch(dwCtrlCode) {
248:
249: // Pause the service if it is running.
250: //
251: case SERVICE_CONTROL_PAUSE:
252:
253: if (ssStatus.dwCurrentState == SERVICE_RUNNING) {
254: SuspendThread(threadHandle);
255: dwState = SERVICE_PAUSED;
256: }
257: break;
258:
259: // Resume the paused service.
260: //
261: case SERVICE_CONTROL_CONTINUE:
262:
263: if (ssStatus.dwCurrentState == SERVICE_PAUSED) {
264: ResumeThread(threadHandle);
265: dwState = SERVICE_RUNNING;
266: }
267: break;
268:
269: // Stop the service.
270: //
271: case SERVICE_CONTROL_STOP:
272:
273: dwState = SERVICE_STOP_PENDING;
274:
275: // Report the status, specifying the checkpoint and waithint,
276: // before setting the termination event.
277: //
278: ReportStatusToSCMgr(
279: SERVICE_STOP_PENDING, // current state
280: NO_ERROR, // exit code
281: 1, // checkpoint
282: 3000); // waithint
283:
284: SetEvent(hServDoneEvent);
285: return;
286:
287: // Update the service status.
288: //
289: case SERVICE_CONTROL_INTERROGATE:
290: break;
291:
292: // invalid control code
293: //
294: default:
295: break;
296:
297: }
298:
299: // send a status response.
300: //
301: ReportStatusToSCMgr(dwState, NO_ERROR, 0, 0);
302: }
303:
304:
305:
306: // worker_thread() --
307: // this function does the actual nuts and bolts work that
308: // the service requires. It will also Pause or Stop when
309: // asked by the service_ctrl function.
310: //
311: VOID
312: worker_thread(VOID *notUsed)
313: {
314: char inbuf[80];
315: char outbuf[80];
316: BOOL ret;
317: DWORD bytesRead;
318: DWORD bytesWritten;
319:
320: // okay, our pipe has been creating, let's enter the simple
321: // processing loop...
322: //
323: while (1) {
324:
325: // wait for a connection...
326: //
327: ConnectNamedPipe(pipeHandle, NULL);
328:
329: // grab whatever's coming through the pipe...
330: //
331: ret = ReadFile(
332: pipeHandle, // file to read from
333: inbuf, // address of input buffer
334: sizeof(inbuf), // number of bytes to read
335: &bytesRead, // number of bytes read
336: NULL); // overlapped stuff, not needed
337:
338: if (!ret)
339: // pipe's broken... go back and reconnect
340: //
341: continue;
342:
343: // munge the string
344: //
345: sprintf(outbuf, "Hello! [%s]", inbuf);
346:
347: // send it back out...
348: //
349: ret = WriteFile(
350: pipeHandle, // file to write to
351: outbuf, // address of output buffer
352: sizeof(outbuf), // number of bytes to write
353: &bytesWritten, // number of bytes written
354: NULL); // overlapped stuff, not needed
355:
356: if (!ret)
357: // pipe's broken... go back and reconnect
358: //
359: continue;
360:
361: // drop the connection...
362: //
363: DisconnectNamedPipe(pipeHandle);
364: }
365: }
366:
367:
368:
369: // utility functions...
370:
371:
372:
373: // ReportStatusToSCMgr() --
374: // This function is called by the ServMainFunc() and
375: // ServCtrlHandler() functions to update the service's status
376: // to the service control manager.
377: //
378: BOOL
379: ReportStatusToSCMgr(DWORD dwCurrentState,
380: DWORD dwWin32ExitCode,
381: DWORD dwCheckPoint,
382: DWORD dwWaitHint)
383: {
384: BOOL fResult;
385:
386: // Disable control requests until the service is started.
387: //
388: if (dwCurrentState == SERVICE_START_PENDING)
389: ssStatus.dwControlsAccepted = 0;
390: else
391: ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
392: SERVICE_ACCEPT_PAUSE_CONTINUE;
393:
394: // These SERVICE_STATUS members are set from parameters.
395: //
396: ssStatus.dwCurrentState = dwCurrentState;
397: ssStatus.dwWin32ExitCode = dwWin32ExitCode;
398: ssStatus.dwCheckPoint = dwCheckPoint;
399:
400: ssStatus.dwWaitHint = dwWaitHint;
401:
402: // Report the status of the service to the service control manager.
403: //
404: if (!(fResult = SetServiceStatus(
405: sshStatusHandle, // service reference handle
406: &ssStatus))) { // SERVICE_STATUS structure
407:
408: // If an error occurs, stop the service.
409: //
410: StopSimpleService("SetServiceStatus");
411: }
412: return fResult;
413: }
414:
415:
416:
417: // The StopSimpleService function can be used by any thread to report an
418: // error, or stop the service.
419: //
420: VOID
421: StopSimpleService(LPTSTR lpszMsg)
422: {
423: CHAR chMsg[256];
424: HANDLE hEventSource;
425: LPTSTR lpszStrings[2];
426:
427: dwGlobalErr = GetLastError();
428:
429: // Use event logging to log the error.
430: //
431: hEventSource = RegisterEventSource(NULL,
432: TEXT("SimpleService"));
433:
434: sprintf(chMsg, "SimpleService error: %d", dwGlobalErr);
435: lpszStrings[0] = chMsg;
436: lpszStrings[1] = lpszMsg;
437:
438: if (hEventSource != NULL) {
439: ReportEvent(hEventSource, // handle of event source
440: EVENTLOG_ERROR_TYPE, // event type
441: 0, // event category
442: 0, // event ID
443: NULL, // current user's SID
444: 2, // strings in lpszStrings
445: 0, // no bytes of raw data
446: lpszStrings, // array of error strings
447: NULL); // no raw data
448:
449: (VOID) DeregisterEventSource(hEventSource);
450: }
451:
452: // Set a termination event to stop SERVICE MAIN FUNCTION.
453: //
454: SetEvent(hServDoneEvent);
455: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.