WIN32服务程序(Service)VC++封装

在VC++6.0下,写WIN32的服务程序虽然不难,但是要完整实现整个服务还是比较麻烦,每次都需要完成必要的步骤,比如,服务的安装,服务控制的挂接等等操作,其实这些操作完成可以把它框架化,在应用端只需要实现特定的业务相关的应用即可。网上也有很多这方面的例子。由此,自己修改了别人写的一些代码,做成了两个C++类,完成WIN32服务的框架代码。应用端只需要简单地从RNService继承特定的实现类以及实现服务程序中两个回调函数ServiceMain和ServiceCtrl,这两个C函数只需要调用应用端实现的类中的ServiceMain和ServiceCtrl即可,因为相关的实现逻辑已经在框架代码中完成。这样做的目的是使应用程序可以一次启动多个ServiceMain,具体的代码如下,如果您已经对其进行了完善,请发一份给我,谢谢!

/****************************************************
**  Copyright (C) 2008 - 2009
** 功    能: WIN32服务工具类库,完成一般服务常用的操作
    诸如安装服务,移出服务等。

  ** 文件名称:  RNService.h
  ** 文件基类: 
  ** 扩 展 名: .h
  ** 创建日期: 2008-03-01
  ** 作    者: Rohna.w
*****************************************************/

#ifndef _RNSERVICE_ONCE_
#define _RNSERVICE_ONCE_

#include "Windows.h"
#include "TCHAR.h"

class RNSCTool
{
public:
 enum SCFlag{SCF_BOTH=1,SCF_MANAGER};

 RNSCTool()
 {
  schService = NULL;
  schSCManager = NULL;
 }

 ~RNSCTool()
 {
  Close();
 }

 void Close()
 {
  if(NULL != schService)
  {
   CloseServiceHandle(schService);
  }

  if(NULL != schSCManager)
  {
   CloseServiceHandle(schSCManager);
  }

  schService = NULL;
  schSCManager = NULL;
 }

 BOOL IsValid()
 {
  if(NULL == schService) return FALSE;
  return TRUE;
 }

 BOOL Open(LPTSTR lpSrvName,SCFlag _sFlag=SCF_BOTH)
 {
  Close();
  // 打开服务管理数据库
  schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS/*要求所有的访问权*/);
  if(NULL == schSCManager)
  {
   return FALSE;
  }

  if(SCF_MANAGER == _sFlag)
  {
   return TRUE;
  }

  // 获取服务程序句柄
  schService = OpenService(
   schSCManager,       // 服务管理数据库句柄
   TEXT(lpSrvName), // 服务名
   SERVICE_ALL_ACCESS  // 响应所有的访问请求
   );

  if(NULL == schService)
  {
   Close();
   return FALSE;
  }

  return TRUE;
 }

 BOOL QuerySrvStatus(LPSERVICE_STATUS status)
 {
  if(NULL == schService) return FALSE;

  return QueryServiceStatus(schService,status);
 }

 BOOL DelService()
 {
  if(NULL == schService) return FALSE;

  return DeleteService(schService);
 }

 BOOL RunService()
 {
  if(NULL == schService) return FALSE;
  return ::StartService(schService,NULL,NULL);
 }

 BOOL CtrlService(LPSERVICE_STATUS status,DWORD dwCtrlFlag=SERVICE_CONTROL_STOP)
 {
  if(NULL == schService) return FALSE;
  return ::ControlService(schService,dwCtrlFlag,status);
 }

 SC_HANDLE schService;
 SC_HANDLE schSCManager;
};

#include <vector>
using namespace std;

typedef struct tagSrvTableEntry
{
 TCHAR     tSrvName[_MAX_PATH];
 LPSERVICE_MAIN_FUNCTION lpSrvFunc;
}SRVTABENTRY;

class RNSrvTools
{
public:
 RNSrvTools();

 enum SVRTYPE{SVR_AUTO=1,SVR_DEMAND=2,SVR_START=4};
 
 static void AddToMessageLog(LPTSTR lpSvrName,LPTSTR lpszMsg,int type=0);
 static BOOL Start(LPTSTR lpSvrName);
 static BOOL Stop(LPTSTR lpSvrName);
 static BOOL Remove(LPTSTR lpSvrName);
 static BOOL IsRuning(LPTSTR lpSvrName);
 static BOOL IsExist(LPTSTR lpSvrName);
 static BOOL Install(int _svType,LPTSTR lpSvrName,LPTSTR lpAppName,LPTSTR lpSvrPath);

 static BOOL AddService(LPSTR lpSrvName,LPSERVICE_MAIN_FUNCTION lpSrvFunc);
 static BOOL SrvDispatcher(LPTSTR lpAppName=0);
 static void ClearService();

 static vector<SRVTABENTRY> _srvs;
};

/****************************************************
**  Copyright (C) 2008 - 2009
** 功    能: WIN32服务实现类库,此类封装了WIN32服务的实现,
    应用程序只需要从此类派生,实现特定的功能,然后
    安装启动服务即可。

  ** 文件名称:  RNService.h
  ** 文件基类: 
  ** 扩 展 名: .h
  ** 创建日期: 2008-03-01
  ** 作    者: Rohna.w
*****************************************************/
class RNService
{
public:
 RNService();
 enum SVRTYPE{SVR_AUTO=1,SVR_DEMAND=2,SVR_START=4};
 
 void SetTheServiceStatus(DWORD dwCurrentState,DWORD dwWin32ExitCode,DWORD dwCheckPoint,DWORD dwWaitHint);
 
 BOOL ReportStatusToSCMgr(DWORD dwCurrentState,DWORD dwWin32ExitCode,DWORD dwWaitHint);
 void ServiceCtrl(DWORD dwCtrlCode);
 void ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv,LPHANDLER_FUNCTION lpHandlerProc);
 
 void SetSrvName(LPTSTR lpSvrName,LPTSTR lpAppName);
 LPTSTR GetSvrName();
 LPTSTR GetAppName();

 // 下面的功能由具体的应用实现
 virtual void ServiceStop();
 virtual void ServicePause();
 virtual void ServiceContinue();
 virtual void Run(DWORD dwArgc, LPTSTR *lpszArgv);
private:
 TCHAR tSvrName[256];
 TCHAR tAppName[256];
 SERVICE_STATUS   ssStatus;
 SERVICE_STATUS_HANDLE sshStatusHandle;
};

#endif

下面是CPP文件:

// RNService.cpp

#include "StdAfx.h"
#include "RNService.h"
#include "stdio.h"

vector<SRVTABENTRY> RNSrvTools::_srvs;

RNSrvTools::RNSrvTools()
{
}

BOOL RNSrvTools::AddService(LPSTR lpSrvName,LPSERVICE_MAIN_FUNCTION lpSrvFunc)
{
 SRVTABENTRY srvEntry;
 _tcsncpy(srvEntry.tSrvName,lpSrvName,sizeof(srvEntry.tSrvName)-1);
 srvEntry.lpSrvFunc = lpSrvFunc;

 _srvs.push_back(srvEntry);

 return TRUE;
}

BOOL RNSrvTools::SrvDispatcher(LPTSTR lpAppName)
{
 if(_srvs.size() == 0) return FALSE;

 SERVICE_TABLE_ENTRY* dispatchTable = new SERVICE_TABLE_ENTRY[_srvs.size()+1];

 for(int i=0;i<_srvs.size();++i)
 {
  dispatchTable[i].lpServiceName = _srvs[i].tSrvName;
  dispatchTable[i].lpServiceProc = _srvs[i].lpSrvFunc;
 }

 dispatchTable[_srvs.size()].lpServiceName = NULL;
 dispatchTable[_srvs.size()].lpServiceProc = NULL;

 BOOL bSucc = ::StartServiceCtrlDispatcher(dispatchTable);

 delete [] dispatchTable;

 if(NULL != lpAppName)
 {
  if(FALSE != bSucc)
  {
   AddToMessageLog(lpAppName,TEXT("StartServiceCtrlDispatcher failed."));
  }
  else
  {
   AddToMessageLog(lpAppName,TEXT("StartServiceCtrlDispatcher OK."));
  }
 }

 return bSucc;
}

void RNSrvTools::ClearService()
{
 _srvs.clear();
}

void RNSrvTools::AddToMessageLog(LPTSTR lpSvrName,LPTSTR lpszMsg,int type)   
{   
 TCHAR   szMsg[256] = {0};   
 HANDLE  hEventSource = NULL;   
 LPTSTR  lpszStrings[2] = {0};   
 DWORD  dwErr = GetLastError();  

 hEventSource = RegisterEventSource(NULL,TEXT(lpSvrName));   
 _stprintf(szMsg,TEXT("%s error: %d"),TEXT(lpSvrName),dwErr);   
 lpszStrings[0] = szMsg;
 lpszStrings[1] = lpszMsg;

 if(hEventSource != NULL)  
 {   
  if(type)   
  {
   ReportEvent(hEventSource,  //   handle   of   event   source
    EVENTLOG_ERROR_TYPE,  //   event   type
    0,       //   event   category
    0,       //   event   ID
    NULL,      //   current   user's   SID
    2,       //   strings   in   lpszStrings   
    0,       //   no   bytes   of   raw   data
    (const char**)lpszStrings, //   array   of   error   strings
    NULL);      //   no   raw   data
  }
  else   
  {
   ReportEvent(hEventSource,  //   handle   of   event   source
    EVENTLOG_INFORMATION_TYPE, //   event   type
    0,       //   event   category
    0,       //   event   ID   
    NULL,      //   current   user's   SID
    2,       //   strings   in   lpszStrings   
    0,       //   no   bytes   of   raw   data
    (const char**)lpszStrings, //   array   of   error   strings   
    NULL);      //   no   raw   data
  }

  (void)DeregisterEventSource(hEventSource);   
 }   
}

BOOL RNSrvTools::Start(LPTSTR lpSvrName)
{
 RNSCTool rcTool;
 if(FALSE == rcTool.Open(lpSvrName)) return FALSE;

    // 获得服务的状态
    SERVICE_STATUS status;
 if(FALSE == rcTool.QuerySrvStatus(&status)) return FALSE;

    // 如果处于停止状态则启动服务
 if(status.dwCurrentState == SERVICE_STOPPED)
 {
  // 启动服务
  if(rcTool.RunService() != FALSE)
  {
   // 等待服务启动
   while(rcTool.QuerySrvStatus(&status) != FALSE)
   {
    ::Sleep(status.dwWaitHint);
    if(status.dwCurrentState == SERVICE_RUNNING)
    {
     break;
    }
   }
  }
 }

 return TRUE;
}

BOOL RNSrvTools::Stop(LPTSTR lpSvrName)
{
 RNSCTool rcTool;
 if(FALSE == rcTool.Open(lpSvrName)) return FALSE;

    // 获得服务的状态
    SERVICE_STATUS status;
 if(FALSE == rcTool.QuerySrvStatus(&status)) return FALSE;

    if(status.dwCurrentState == SERVICE_RUNNING)
 {
  // 停止服务
  if(rcTool.CtrlService(&status) != FALSE)
  {
   // 等待服务停止
   while(rcTool.QuerySrvStatus(&status) != FALSE)
   {
    ::Sleep( status.dwWaitHint);
    if(status.dwCurrentState == SERVICE_STOPPED)
    {
     break;
    }
   }
  }
 }

 return TRUE;
}

BOOL RNSrvTools::IsRuning(LPTSTR lpSvrName)
{
 RNSCTool rcTool;
 if(FALSE == rcTool.Open(lpSvrName)) return FALSE;

    // 获得服务的状态
    SERVICE_STATUS status;
 if(FALSE == rcTool.QuerySrvStatus(&status)) return FALSE;

 if(status.dwCurrentState == SERVICE_RUNNING)
 {
  return TRUE;
 }

 return FALSE;
}

BOOL RNSrvTools::IsExist(LPTSTR lpSvrName)
{
 RNSCTool rcTool;
 if(FALSE == rcTool.Open(lpSvrName)) return FALSE;
 
 return TRUE;
}

BOOL RNSrvTools::Remove(LPTSTR lpSvrName)
{
 RNSCTool rcTool;
 if(FALSE == rcTool.Open(lpSvrName)) return FALSE;

 SERVICE_STATUS status;

 if(rcTool.CtrlService(&status) != FALSE)
 {
  Sleep(1000);
  while(FALSE != rcTool.QuerySrvStatus(&status))
  {
   if(SERVICE_STOP_PENDING != status.dwCurrentState) 
   {
    break;
   }
   Sleep(1000);
  }

  if(SERVICE_STOPPED == status.dwCurrentState)
  {
   // 成功停止服务
  }
  else
  {
   // 停止服务失败
  }
 }

 return rcTool.DelService();
}

BOOL RNSrvTools::Install(int _svType,LPTSTR lpSvrName,LPTSTR lpAppName,LPTSTR lpSvrPath)
{
 RNSCTool rcTool;
 if(FALSE == rcTool.Open(lpSvrName,RNSCTool::SCF_MANAGER)) return FALSE;

 TCHAR szSrvPath[512] = {0};

 // 获取当前程序文件路径
 if(NULL == lpSvrPath)
 {
  ::GetModuleFileName(NULL,szSrvPath,510);
 }
 else
 {
  _tcsncpy(szSrvPath,lpSvrPath,510);
 }

 DWORD dwStartType = SERVICE_DEMAND_START;
 if(SVR_AUTO == (_svType & SVR_AUTO))
 {
  dwStartType = SERVICE_AUTO_START;
 }

 // 登记服务程序
 rcTool.schService = CreateService(
  rcTool.schSCManager,  // 服务管理数据库句柄
  TEXT(lpSvrName),   // 服务名
  TEXT(lpAppName),   // 用于显示服务的标识
  SERVICE_ALL_ACCESS,   // 响应所有的访问请求
  SERVICE_WIN32_OWN_PROCESS, // 服务类型
  dwStartType,    // 启动类型SERVICE_DEMAND_START
  SERVICE_ERROR_NORMAL,  // 错误控制类型
  szSrvPath,     // 服务程序磁盘文件的路径
  NULL,      // 服务不属于任何组
  NULL,      // 没有tag标识符
  NULL,      // 启动服务所依赖的服务或服务组,这里仅仅是一个空字符串
  NULL,      // LocalSystem 帐号
  NULL);
 
 if(FALSE == rcTool.IsValid()) return FALSE;

 if(SVR_START == (_svType & SVR_START))
 {
  Sleep(1000);
  // 启动服务
  if(rcTool.RunService() != FALSE)
  {
   SERVICE_STATUS status;    
   // 等待服务启动
   while(FALSE != rcTool.QuerySrvStatus(&status))
   {
    ::Sleep(status.dwWaitHint);
    if(status.dwCurrentState == SERVICE_RUNNING)
    {
     break;
    }
   }
  }
 }

 return TRUE;
}

/
// RNService

RNService::RNService()
{
 sshStatusHandle = NULL;
 _tcsset(tSvrName,0);
 _tcsset(tAppName,0);
 ZeroMemory(&ssStatus,sizeof(ssStatus));
}

void RNService::SetSrvName(LPTSTR lpSvrName,LPTSTR lpAppName)
{
 if(NULL != lpSvrName)
 {
  _tcsncpy(tSvrName,lpSvrName,sizeof(tSvrName)-1);
 }

 if(NULL != lpAppName)
 {
  _tcsncpy(tAppName,lpAppName,sizeof(tAppName)-1);
 }
}

LPTSTR RNService::GetSvrName()
{
 return tSvrName;
}

LPTSTR RNService::GetAppName()
{
 return tAppName;
}

void RNService::SetTheServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode,
       DWORD dwCheckPoint,   DWORD dwWaitHint)
{
 if(NULL == sshStatusHandle) return;
 
 SERVICE_STATUS ss;
 
 if(dwCurrentState == SERVICE_START_PENDING)
 {
  ss.dwControlsAccepted = 0;
 }
 else
 { 
  ss.dwControlsAccepted = SERVICE_ACCEPT_STOP|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(sshStatusHandle,&ss))
 {
  //_tprintf(TEXT("SetServiceStatus"));
 }
}

// 设置当前服务状态并将状态信息回送到服务控制管理器
BOOL RNService::ReportStatusToSCMgr(DWORD dwCurrentState,DWORD dwWin32ExitCode,DWORD dwWaitHint)
{
 static DWORD dwCheckPoint = 1;
 BOOL fResult = TRUE;

 if(dwCurrentState == SERVICE_START_PENDING)
 {
  ssStatus.dwControlsAccepted = 0;
 }
 else
 {
  ssStatus.dwControlsAccepted=SERVICE_ACCEPT_STOP;
 }

 //设置状态信息
 ssStatus.dwCurrentState=dwCurrentState;
 ssStatus.dwWin32ExitCode=dwWin32ExitCode;
 ssStatus.dwWaitHint=dwWaitHint;
 if((dwCurrentState == SERVICE_RUNNING) || 
  (dwCurrentState == SERVICE_STOPPED))
 {
  ssStatus.dwCheckPoint = 0;
 }
 else
 {
  ssStatus.dwCheckPoint = dwCheckPoint++;
 }

 //将状态信息回送到服务控制管理器
 if(!(fResult = SetServiceStatus(sshStatusHandle,&ssStatus)))
 {
  RNSrvTools::AddToMessageLog(tSvrName,TEXT("SetServiceStatus")); //向NT事//件管理器报告出错消息
 }

 return fResult;
}

void RNService::ServiceStop()
{
}

void RNService::ServicePause()
{
}

void RNService::ServiceContinue()
{
}

//控制处理程序函数
void RNService::ServiceCtrl(DWORD dwCtrlCode)
{
 //处理控制请求码
 switch(dwCtrlCode)
 {
  // 先更新服务状态为 SERVICDE_STOP_PENDING,再停止服务。
  case SERVICE_CONTROL_STOP:
   ReportStatusToSCMgr(SERVICE_STOP_PENDING,NO_ERROR,200);
   ServiceStop();
   SetTheServiceStatus(SERVICE_STOPPED,GetLastError(),0,0);
   break;

  // 暂停服务
  case SERVICE_CONTROL_PAUSE:
   ReportStatusToSCMgr(SERVICE_STOP_PENDING,NO_ERROR,200);
   ServicePause();
   ssStatus.dwCurrentState = SERVICE_PAUSED;
   break;

  // 继续服务
  case SERVICE_CONTROL_CONTINUE:
   ReportStatusToSCMgr(SERVICE_STOP_PENDING,NO_ERROR,200);
   ServiceContinue();
   ssStatus.dwCurrentState = SERVICE_RUNNING;
   break;

  // 更新服务状态
  case SERVICE_CONTROL_INTERROGATE:
   break;

  // 无效控制码
  default:
   break;
 }

 ReportStatusToSCMgr(ssStatus.dwCurrentState,NO_ERROR,0);
}

void RNService::Run(DWORD dwArgc, LPTSTR *lpszArgv)
{
}

void RNService::ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv,LPHANDLER_FUNCTION lpHandlerProc)
{
 ssStatus.dwCurrentState = SERVICE_START_PENDING;
 ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; // 控制服务

 // 注册服务控制处理函数
 sshStatusHandle = RegisterServiceCtrlHandler(TEXT(tSvrName),lpHandlerProc);
 
 // 如果注册失败
 if(NULL == sshStatusHandle)
 {
  return;
 }

 SetServiceStatus(sshStatusHandle, &ssStatus);
 ssStatus.dwWin32ExitCode = S_OK;
 ssStatus.dwCheckPoint = 0;
 ssStatus.dwWaitHint = 0;
 ssStatus.dwCurrentState = SERVICE_RUNNING;
 SetServiceStatus(sshStatusHandle, &ssStatus);

 //初始化 SERVICE_STATUS 结构中的成员
 ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
 ssStatus.dwServiceSpecificExitCode = 0;
 
 // 更新服务状态
 if(!ReportStatusToSCMgr(
  SERVICE_START_PENDING, // 服务状态,The service is starting.
  NO_ERROR,    // 退出码         
  3000))                  // 等待时间
 {
  //更新服务状态失败
  return;
 }

 Run(dwArgc,lpszArgv);
}

本人邮箱:rohna.w@163.com ,欢迎多多交流!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值