Shell's Home

Dec 20, 2006 - 6 minute read - Comments

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++错误。所以必须手工来匹配指针,大家忍耐忍耐。

Tags: c windows

出差到宁波 正则表达式解析文本

comments powered by Disqus