在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
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
};
/****************************************************
** 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
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 ,欢迎多多交流!