Annotation of mstools/samples/service/simple.c, revision 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.