windows service的C++封装实现
windows系统服务入口的封装类,service是基类,service_manager是管理类。支持UNICODE,可以多服务封装在一个程序里面,过程当然都是自动的。拥有自动防错系统,在服务异常退出的时候会去关闭服务,而不是开着服务直接没了进程。写一个类,继承service,然后在哪里出一个实例,就可以了。service中有很多虚函数,可以重载了监听对应事件(我应该写的比较明白吧)。get_service_name,返回UNICODE的字符串指针,定义服务名称。注意是纯虚函数,必须实现。get_dependence,也是返回UNICODE的字符指针。指明这个服务依赖什么服务。get_service_type返回服务类型,其实也就是是否可以交互。get_contral_accepts,支持的信号(例如是否可以暂停),默认可以暂停。on_start开始时候调用的函数,下同。
使用方法
#include
#include "service.h"
class test_service : public service{
public:
virtual LPTSTRget_service_name ();
virtual DWORD on_start (DWORD argc, LPTSTR * argv);
virtual DWORD on_stop ();
virtual DWORD on_shutdown ();
};
LPTSTR test_service::get_service_name ()
{
return _T ("test_service");
}
DWORD test_service::on_start (DWORD argc, LPTSTR * argv)
{
return service::on_start (argc, argv);
}
DWORD test_service::on_stop ()
{
return service::on_stop ();
}
DWORD test_service::on_shutdown ()
{
return service::on_shutdown ();
}
int _tmain (int argc, _TCHAR * argv[])
{
test_service ts;
if (argc == 1)
service_manager::start ();
else if (!_tcscmp (argv[1], _T ("install")))
service_manager::install_services (NULL, false);
else if (!_tcscmp (argv[1], _T ("remove")))
service_manager::remove_services (NULL);
return 0;
}
------------service.h-------------------
#include
using namespace std;
#include
#pragma comment(lib, "psapi")
typedef basic_string < TCHAR > tstring;
#ifndef _SERVICE_H_
#define _SERVICE_H_
class service {
public:
service ();
~service ();
virtual LPTSTRget_service_name () = 0;
virtual LPTSTRget_dependence ();
virtual DWORD get_service_type ();
virtual DWORD get_contral_accepts ();
virtual DWORD on_start (DWORD argc, LPTSTR * argv);
virtual DWORD on_stop ();
virtual DWORD on_interrogate ();
virtual DWORD on_pause ();
virtual DWORD on_continue ();
virtual DWORD on_shutdown ();
voidpre_start (SERVICE_STATUS_HANDLE hServiceStatus,
DWORD argc, LPTSTR * argv);
BOOL SetServiceStatus (DWORD dwState);
protected:
SERVICE_STATUS_HANDLE hServiceStatus;
SERVICE_STATUS ServiceStatus;
};
class service_manager {
public:
service_manager ();
~service_manager ();
DWORDregister_service (service * s);
DWORDunregister_service (service * s);
LPSERVICE_TABLE_ENTRYget_service_entries ();
service *get_service (LPCTSTR lpName);
static service_manager *get_service_manager();
static intinstall_services (LPCTSTR lpServiceName, bool
autostart);
static intremove_services (LPCTSTR lpServiceName);
static intstart();
static void WINAPIservice_start (DWORD argc, LPTSTR * argv);
static DWORD WINAPIctrl_handler (DWORD dwControl, DWORD
dwEventType,
LPVOID lpEventData, LPVOID lpContext);
static TCHAR *service_status_name[];
protected:
static service_manager *this_for_static;
vector < service * >service_list;
};
#endif //_SERVICE_H_
----------------------------------------
------------service.cpp-----------------
// service.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#define PRINTERROR(x) _tprintf (_T ("%s failed, errorcode 0x%0.8X\n"),(x), GetLastError ())
service_manager *service_manager::this_for_static = NULL;
TCHAR *service_manager::service_status_name[] = {
_T ("SERVICE_UNKNOWN"),
_T ("SERVICE_STOPPED"),
_T ("SERVICE_START_PENDING"),
_T ("SERVICE_STOP_PENDING"),
_T ("SERVICE_RUNNING"),
_T ("SERVICE_CONTINUE_PENDING"),
_T ("SERVICE_PAUSE_PENDING"),
_T ("SERVICE_PAUSED")
};
service::service ()
{
if (service_manager::get_service_manager () == NULL)
new service_manager ();
service_manager::get_service_manager ()->register_service
(this);
}
service::~service ()
{
if (service_manager::get_service_manager () == NULL)
return;
service_manager::get_service_manager ()->unregister_service(this);
}
LPTSTR service::get_dependence ()
{
return NULL;
}
DWORD service::get_service_type ()
{
return 0;
}
DWORD service::get_contral_accepts ()
{
return SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN |
SERVICE_ACCEPT_STOP;
}
DWORD service::on_start (DWORD argc, LPTSTR * argv)
{
return SERVICE_RUNNING;
}
DWORD service::on_stop ()
{
return SERVICE_STOPPED;
}
DWORD service::on_interrogate ()
{
return SERVICE_RUNNING;
}
DWORD service::on_pause ()
{
return SERVICE_PAUSED;
}
DWORD service::on_continue ()
{
return SERVICE_RUNNING;
}
DWORD service::on_shutdown ()
{
return SERVICE_STOPPED;
}
void service::pre_start (SERVICE_STATUS_HANDLE hServiceStatus,
DWORD argc, LPTSTR * argv)
{
this->hServiceStatus = hServiceStatus;
ServiceStatus.dwServiceType = SERVICE_WIN32;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted = 0;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 10000;
SetServiceStatus (0);
ServiceStatus.dwCurrentState = on_start (argc, argv);
if (ServiceStatus.dwCurrentState == SERVICE_STOPPED)
ServiceStatus.dwWin32ExitCode = ServiceStatus.dwCurrentState;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
ServiceStatus.dwControlsAccepted = get_contral_accepts ();
SetServiceStatus (0);
return;
}
BOOL service::SetServiceStatus (DWORD dwState)
{
TCHAR lpOutString[0x400];
if (dwState != 0)
ServiceStatus.dwCurrentState = dwState;
if (ServiceStatus.dwCurrentState > 7)
return 0;
BOOL rslt =::SetServiceStatus (hServiceStatus, &ServiceStatus);
if (rslt)
_stprintf (lpOutString,
_T ("%s set service status %s successed.\n"),
get_service_name (),
service_manager::service_status_name[ServiceStatus.
dwCurrentState]);
else
_stprintf (lpOutString,
_T
("%s set service status %s failed, errorcode 0x%0.8X\n"),
get_service_name (),
service_manager::service_status_name[ServiceStatus.
dwCurrentState],
GetLastError ());
OutputDebugString ((LPCTSTR) lpOutString);
return rslt;
}
service_manager::service_manager ()
{
if (this_for_static != NULL)
return;
this_for_static = this;
}
service_manager::\~service_manager ()
{
this_for_static = NULL;
}
DWORD service_manager::register_service (service * s)
{
vector < service * >::iterator iter;
iter = service_list.begin ();
for (; iter != service_list.end (); iter++)
if (*iter == s)
return 1;
service_list.push_back (s);
return 0;
}
DWORD service_manager::unregister_service (service * s)
{
vector < service * >::iterator iter;
iter = service_list.begin ();
for (; iter != service_list.end (); iter++)
if (*iter == s) {
service_list.erase (iter);
return 0;
}
return -1;
}
LPSERVICE_TABLE_ENTRY service_manager::get_service_entries ()
{
UINT i;
LPSERVICE_TABLE_ENTRY lte = NULL;
lte = new SERVICE_TABLE_ENTRY[service_list.size () + 1];
for (i = 0; i < service_list.size (); i++) {
lte[i].lpServiceName = service_list[i]->get_service_name
();
lte[i].lpServiceProc = (LPSERVICE_MAIN_FUNCTION) service_start;
}
lte[i].lpServiceName = NULL;
lte[i].lpServiceProc = NULL;
return lte;
}
service *service_manager::get_service (LPCTSTR lpName)
{
for (UINT i = 0; i < service_list.size (); i++)
if (!_tcscmp (service_list[i]->get_service_name (), lpName))
return service_list[i];
return NULL;
}
int service_manager::install_services (LPCTSTR lpServiceName, bool
autostart)
{
UINT i;
int rslt = 0;
DWORD service_type;
TCHAR binary_path[0x400];
SC_HANDLE hSCManager = NULL, hService = NULL;
service *pservice;
if (lpServiceName == NULL) {
for (i = 0; i < this_for_static->service_list.size (); i++)
install_services (this_for_static->service_list[i]->
get_service_name (), autostart);
return 0;
}
pservice = this_for_static->get_service (lpServiceName);
if (pservice == NULL) {
_tprintf (_T ("get_service %s failed, don't have this service\n"),
lpServiceName);
return -1;
}
if (!GetModuleFileNameEx (GetCurrentProcess (), NULL, binary_path,
0x400)) {
PRINTERROR (_T ("GetModuleFileNameEx"));
return -1;
}
if (this_for_static->service_list.size () < 2)
service_type = SERVICE_WIN32_OWN_PROCESS;
else
service_type = SERVICE_WIN32_SHARE_PROCESS;
__try {
hSCManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCManager == NULL) {
rslt = -1;
__leave;
}
hService = CreateService (hSCManager, lpServiceName, lpServiceName,
SC_MANAGER_ALL_ACCESS,
pservice->
get_service_type () | service_type,
(autostart ? SERVICE_AUTO_START :
SERVICE_DEMAND_START),
SERVICE_ERROR_NORMAL, binary_path, NULL,
NULL, pservice->get_dependence (), NULL,
NULL);
if (hService == NULL) {
rslt = -2;
__leave;
}
}
__finally {
if (hService != NULL)
CloseServiceHandle (hService);
if (hSCManager != NULL)
CloseServiceHandle (hSCManager);
if (rslt == 0)
_tprintf (_T ("install_services %s successed\n"), lpServiceName);
if (rslt == -1)
PRINTERROR (_T ("OpenSCManager"));
if (rslt == -2)
PRINTERROR (_T ("CreateService"));
}
return rslt;
}
int service_manager::remove_services (LPCTSTR lpServiceName)
{
int rslt = 0;
UINT i;
SC_HANDLE hSCManager, hService;
service *pservice;
if (lpServiceName == NULL) {
for (i = 0; i < this_for_static->service_list.size (); i++)
remove_services (this_for_static->service_list[i]->
get_service_name ());
return 0;
}
pservice = this_for_static->get_service (lpServiceName);
if (pservice == NULL) {
_tprintf (_T ("get_service failed, don't have this service\n"));
return -1;
}
__try {
hSCManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCManager == NULL) {
rslt = -1;
__leave;
}
hService =
OpenService (hSCManager, lpServiceName, SC_MANAGER_ALL_ACCESS);
if (hService == NULL) {
rslt = -2;
__leave;
}
if (!DeleteService (hService)) {
rslt = -3;
__leave;
}
}
__finally {
if (hService != NULL)
CloseServiceHandle (hService);
if (hSCManager != NULL)
CloseServiceHandle (hSCManager);
if (rslt == 0)
_tprintf (_T ("remove_services %s successed\n"), lpServiceName);
if (rslt == -1)
PRINTERROR (_T ("OpenSCManager"));
if (rslt == -2)
PRINTERROR (_T ("OpenService"));
if (rslt == -3)
PRINTERROR (_T ("DeleteService"));
}
return rslt;
}
int service_manager::start ()
{
if (!StartServiceCtrlDispatcher
(this_for_static->get_service_entries ()))
OutputDebugString (_T ("StartServiceCtrlDispatcher failed\n"));
return 0;
}
void WINAPI service_manager::service_start (DWORD argc, LPTSTR *
argv)
{
SERVICE_STATUS_HANDLE hServiceStatus;
service *pservice = this_for_static->get_service
(argv[0]);
if (pservice == NULL) {
OutputDebugString (_T
("get_service failed, don't have this service\n"));
return;
}
hServiceStatus =
RegisterServiceCtrlHandlerEx (argv[0], ctrl_handler, (LPVOID)
pservice);
if (hServiceStatus == NULL) {
OutputDebugString (_T ("RegisterServiceCtrlHandlerEx return NULL\n"));
return;
}
__try {
pservice->pre_start (hServiceStatus, argc, argv);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
pservice->SetServiceStatus (SERVICE_STOPPED);
}
return;
}
DWORD WINAPI service_manager::ctrl_handler (DWORD dwControl,
DWORD dwEventType,
LPVOID lpEventData,
LPVOID lpContext)
{
DWORD status;
service *pservice = (service *) lpContext;
SetLastError (NO_ERROR);
__try {
switch (dwControl) {
case SERVICE_CONTROL_STOP:
status = pservice->on_stop ();
break;
case SERVICE_CONTROL_SHUTDOWN:
status = pservice->on_shutdown ();
break;
case SERVICE_CONTROL_PAUSE:
status = pservice->on_pause ();
break;
case SERVICE_CONTROL_INTERROGATE:
status = pservice->on_interrogate ();
break;
case SERVICE_CONTROL_CONTINUE:
status = pservice->on_continue ();
break;
default:
return GetLastError ();
}
pservice->SetServiceStatus (status);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
pservice->SetServiceStatus (SERVICE_STOPPED);
}
return GetLastError ();
}
service_manager *service_manager::get_service_manager ()
{
return this_for_static;
}
----------------------------------------
之所有list没有写成map是因为在某个服务处理过程中可能需要用到服务的名称。写成map就需要反向查询,也不是很方便。register_service中会查询这个服务是否已经注册过,注意不能用服务名对比的方法。这也是我才发现的一个问题,C++在基类的构造函数中的时候,虚函数指针是指向基类虚函数表的。在某个service子类构造的时候,其基类(service)构造函数会自动调用register_service方法注册自身。如果在register_service用取得服务名的方法,此时虚函数指针指向了基类的虚函数表。也就是说,我们会调用到一个纯虚函数入口,从而产生C++错误。所以必须手工来匹配指针,大家忍耐忍耐。