Creating a Multithreaded Service

博客给出示例代码,展示了简单服务如何生成工作线程、响应服务控制管理器(SCM)、通知线程退出、向SCM通报服务状态和进度,以及报告服务已停止。还介绍了安装服务的方法,可将其构建为控制台应用程序,使用平台SDK中的SC实用工具,通过控制面板的服务控制实用工具启动和停止服务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值