VC++ Service编程(七)创建多线程服务

创建多线程服务

    下面的例子论述了,一个简单的服务怎么样创建工作进程、响应SCM(服务控制管理器)、通知线程退出、不断地向SCM通知当前状态和处理过程、然后向SCM报告服务停止。要安装这个服务,请把它创建成为以给控制台程序,并使用Platform SDK中的SC工具。使用控制面板中的服务控制工具来开启关闭这个服务。

#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 "));
   if (!StartServiceCtrlDispatcher(ste))
   {
      TCHAR error[256];

      wsprintf(error,
         TEXT("Error code for StartServiceCtrlDispatcher: %u. "),
         GetLastError());
      OutputDebugString(error);
   }
   else
      OutputDebugString(TEXT("StartServiceCtrlDispatcher OK "));
}

// 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 "));

   //
   // 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 "));
   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 "));

   // 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 "));
   }
}

// 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(" Thread %d says Beep "),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);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值