|
|
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.