Annotation of mstools/samples/service/simple.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.