Creating a Multithreaded Service

来源:互联网 发布:日本行知学园熟官网 编辑:程序博客网 时间:2024/04/30 03:59

Creating a Multithreaded Service

The following sample code demonstrates how a simple service can spawn worker threads, respond to the SCM, notify the threads to exit, keep the SCM notified of the state and progress of the service, and report to the SCM that the service is stopped. To install the service, build it as a console application and use the SC utility included with the Platform SDK. Use the Service Control utility in the Control Panel to start and stop the service.

#include <windows.h>#include <tchar.h>#include <stdio.h>HANDLE  hStopEvent;HANDLE hThreads[3] = {NULL,NULL,NULL};LPTSTR  lpszServiceName;SERVICE_STATUS_HANDLE   ssh;DWORD WINAPI ThreadProc(LPVOID lpParameter);void  WINAPI  Service_Main(DWORD dwArgc, LPTSTR *lpszArgv);void  WINAPI  Service_Ctrl(DWORD dwCtrlCode);void  ErrorStopService(LPTSTR lpszAPI);void  SetTheServiceStatus(DWORD dwCurrentState,DWORD dwWin32ExitCode,                          DWORD dwCheckPoint,  DWORD dwWaitHint);// Entry point for service. Calls StartServiceCtrlDispatcher// and then blocks until the ServiceMain function returns.void _tmain(int argc, TCHAR *argv[]){   SERVICE_TABLE_ENTRY ste[] =      {{TEXT(""),(LPSERVICE_MAIN_FUNCTION)Service_Main}, {NULL,NULL}};   OutputDebugString(TEXT("Entered service code/n"));   if (!StartServiceCtrlDispatcher(ste))   {      TCHAR error[256];      wsprintf(error,         TEXT("Error code for StartServiceCtrlDispatcher: %u./n"),         GetLastError());      OutputDebugString(error);   }   else      OutputDebugString(TEXT("StartServiceCtrlDispatcher OK/n"));}// Called by the service control manager after the call to // StartServiceCtrlDispatcher.void WINAPI Service_Main(DWORD dwArgc, LPTSTR *lpszArgv){   DWORD ThreadId;   DWORD t;   DWORD dwWaitRes;   // Obtain the name of the service.   lpszServiceName = lpszArgv[0];   // Register the service ctrl handler.   ssh = RegisterServiceCtrlHandler(lpszServiceName,           (LPHANDLER_FUNCTION)Service_Ctrl);   // Create the event to signal the service to stop.   hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);   if (hStopEvent == NULL)      ErrorStopService(TEXT("CreateEvent"));   //   // Insert one-time work that you want to complete before starting.   //   for (t=0;t<3;t++)   {      hThreads[t] = CreateThread(NULL,0,ThreadProc,                                (LPVOID)t,0,&ThreadId);      if (hThreads[t] == INVALID_HANDLE_VALUE)         ErrorStopService(TEXT("CreateThread"));   }   // The service has started.   SetTheServiceStatus(SERVICE_RUNNING, 0, 0, 0);   OutputDebugString(TEXT("SetTheServiceStatus, SERVICE_RUNNING/n"));   //   // Main loop for the service.   //    while(WaitForSingleObject(hStopEvent, 1000) != WAIT_OBJECT_0)   {/***************************************************************/    // Main loop for service./***************************************************************/    }   // Wait for threads to exit.   for (t=1;TRUE;t++)   {      if ((dwWaitRes = WaitForMultipleObjects(3,hThreads,TRUE,1000))           == WAIT_OBJECT_0)         break;      else if((dwWaitRes == WAIT_FAILED)||(dwWaitRes==WAIT_ABANDONED))         ErrorStopService(TEXT("WaitForMultipleObjects"));      else         SetTheServiceStatus(SERVICE_STOP_PENDING, 0, t, 3000);   }   // Close the event handle and the thread handle.   if (!CloseHandle(hStopEvent))      ErrorStopService(TEXT("CloseHandle"));   if (!CloseHandle(hThreads[0]))      ErrorStopService(TEXT("CloseHandle"));   if (!CloseHandle(hThreads[1]))      ErrorStopService(TEXT("CloseHandle"));   if (!CloseHandle(hThreads[2]))      ErrorStopService(TEXT("CloseHandle"));   // Stop the service.   OutputDebugString(TEXT("SetTheServiceStatus, SERVICE_STOPPED/n"));   SetTheServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0);}// Handles control signals from the service control manager.void WINAPI Service_Ctrl(DWORD dwCtrlCode){   DWORD dwState = SERVICE_RUNNING;   switch(dwCtrlCode)   {      case SERVICE_CONTROL_STOP:         dwState = SERVICE_STOP_PENDING;         break;      case SERVICE_CONTROL_SHUTDOWN:         dwState = SERVICE_STOP_PENDING;         break;      case SERVICE_CONTROL_INTERROGATE:         break;      default:         break;   }   // Set the status of the service.   SetTheServiceStatus(dwState, NO_ERROR, 0, 0);   OutputDebugString(       TEXT("SetTheServiceStatus, Service_Ctrl function/n"));   // Tell service_main thread to stop.   if ((dwCtrlCode == SERVICE_CONTROL_STOP) ||       (dwCtrlCode == SERVICE_CONTROL_SHUTDOWN))   {      if (!SetEvent(hStopEvent))         ErrorStopService(TEXT("SetEvent"));      else         OutputDebugString(TEXT("Signal service_main thread/n"));   }}// Thread procedure for all three worker threads.DWORD WINAPI ThreadProc(LPVOID lpParameter){   INT nThreadNum = (INT)lpParameter;   TCHAR szOutput[25];   while(WaitForSingleObject(hStopEvent, 1000) != WAIT_OBJECT_0)   {   // Just to have something to do, it will beep every second.      Sleep(1000);      wsprintf(szOutput,TEXT("/nThread %d says Beep/n"),nThreadNum);      OutputDebugString(szOutput); //Send visual to debugger.   }   return 0;}//  Wraps SetServiceStatus.void SetTheServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode,                         DWORD dwCheckPoint,   DWORD dwWaitHint){   SERVICE_STATUS ss;  // Current status of the service.   // Disable control requests until the service is started.   if (dwCurrentState == SERVICE_START_PENDING)      ss.dwControlsAccepted = 0;   else      ss.dwControlsAccepted =         SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN;         // Other flags include SERVICE_ACCEPT_PAUSE_CONTINUE         // and SERVICE_ACCEPT_SHUTDOWN.   // Initialize ss structure.   ss.dwServiceType             = SERVICE_WIN32_OWN_PROCESS;   ss.dwServiceSpecificExitCode = 0;   ss.dwCurrentState            = dwCurrentState;   ss.dwWin32ExitCode           = dwWin32ExitCode;   ss.dwCheckPoint              = dwCheckPoint;   ss.dwWaitHint                = dwWaitHint;   // Send status of the service to the Service Controller.   if (!SetServiceStatus(ssh, &ss))      ErrorStopService(TEXT("SetServiceStatus"));}//  Handle API errors or other problems by ending the service and//  displaying an error message to the debugger.void ErrorStopService(LPTSTR lpszAPI){   INT t;   TCHAR   buffer[256]  = TEXT("");   TCHAR   error[1024]  = TEXT("");   LPVOID lpvMessageBuffer;   DWORD  dwWaitRes;   wsprintf(buffer,TEXT("API = %s, "), lpszAPI);   lstrcat(error, buffer);   ZeroMemory(buffer, sizeof(buffer));   wsprintf(buffer,TEXT("error code = %d, "), GetLastError());   lstrcat(error, buffer);   // Obtain the error string.   FormatMessage(      FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,      NULL, GetLastError(),      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),      (LPTSTR)&lpvMessageBuffer, 0, NULL);   ZeroMemory((LPVOID)buffer, (DWORD)sizeof(buffer));   wsprintf(buffer,TEXT("message = %s"), (TCHAR *)lpvMessageBuffer);   lstrcat(error, buffer);   // Free the buffer allocated by the system.   LocalFree(lpvMessageBuffer);   // Write the error string to the debugger.   OutputDebugString(error);   // If you have threads running, tell them to stop. Something went   // wrong, and you need to stop them so you can inform the SCM.   SetEvent(hStopEvent);   // Wait for the threads to stop.   for (t=1;TRUE;t++)   {      if ((dwWaitRes = WaitForMultipleObjects(3,hThreads,TRUE,1000))           == WAIT_OBJECT_0)         break;      else if ((dwWaitRes == WAIT_FAILED)||               (dwWaitRes == WAIT_ABANDONED))         break; // Our wait failed      else      {         SetTheServiceStatus(SERVICE_STOP_PENDING, 0, t, 3000);      }   }   // Stop the service.   SetTheServiceStatus(SERVICE_STOPPED, GetLastError(), 0, 0);}
原创粉丝点击