浮萍晓生的开发日志

记录学习的旅程,把握可预见的未来

导航

Windows NTService 后台框架封装

Posted on 2013-12-30 18:18  浮萍晓生  阅读(1168)  评论(0编辑  收藏  举报

  对于后台运行的程序,比如基于C/S架构的服务器、各种监控系统的程序、或者是程序额外的功能需要后台运行来实现,在Windows平台中,服务经常会用到,这种对于需要24×7运行的程序是必备的,至少本人经常需要运用windows服务来搭建后台程序。于是查阅网上的各种资料,发现有不少的参考实例,但是使用起来有各种问题,不少是这些作者或者使用者对Windows NT Service API接口运用的不熟练或者不清楚,导致自己花费很多时间在理解这些错误的实例当中,不过折腾到最后,还是从错误中得到不少教训的。所以为了方便以后能够直接使用,不再做重复的工作,便在工作之余将Windows NT Service API接口进行了二次封装并简单的测试通过,发上来也让大家使用并指正其中的错误。

  当然,有更权威的参考实例。http://msdn.microsoft.com/en-us/library/windows/desktop/bb540476(v=vs.85).aspx

  废话不多说, 先直接贴上代码,希望不要被贱笑了...

 

  NTService.h

#ifndef _NTSERVICE_H_
#define _NTSERVICE_H_

///服务启动类型定义
enum SERVICE_STARTUP_TYPE
{
    //禁用不可启动
    SST_DISABLED=0,

    //随系统启动自动启动
    SST_AUTO_START=1,

    //命令/手动启动
    SST_DEMAND_START=2
};

///服务执行的任务对象
class ServiceTask
{
public:
    ServiceTask(){}
    virtual ~ServiceTask(){}

public:
    ///服务初始化通知
    ///@return 成功返回0, 否则-1
    ///@remark 完成后需及时返回, 不能长时间阻塞
    virtual int OnInit(int argc, char **argv){return 0;}

    ///服务启动通知
    ///@remark 服务启动阻塞执行此过程, 直至服务停止/关闭
    virtual void OnStart(){}

    ///服务停止通知
    ///@remark OnStart结束返回, 服务变为停止状态
    virtual void OnStop(){}

    ///服务暂停通知
    ///@remark OnStart暂停执行, 服务变为暂停状态
    virtual void OnPause(){}

    ///被暂停的服务恢复通知
    ///@remark OnStart恢复执行, 服务变为恢复状态
    virtual void OnContinue(){}

    ///服务被强制关闭通知
    ///@remark 通常是OS关闭时发生
    virtual void OnShutdown(){}
};

class NTServiceImpl;

///服务接口控制对象
class NTService
{
public:
    ///@param name服务名称
    ///@param canstop是否可停止
    ///@param canshutdown是否可关闭
    ///@param canpausecontinue是否可暂停继续
    NTService(const char *name,
        bool canstop=true,
        bool canshutdown=true,
        bool canpausecontinue=false);

    ~NTService();

public:
    ///检查服务是否安装
    bool IsInstalled();

    ///安装服务
    ///@param display_name服务显示的名称
    ///@param type服务启动类型
    ///@return 成功返回0, 否则-1
    int Install(const char *display_name, SERVICE_STARTUP_TYPE type);

    ///卸载服务
    ///@return 成功返回0, 否则-1
    int UnInstall();

    ///设置服务启动类型
    ///@return 成功返回0, 否则-1
    int SetStartupType(SERVICE_STARTUP_TYPE type);

    ///更新服务描述信息
    ///@return 成功返回0, 否则-1
    int UpdateDesc(const char *desc);

    ///启动服务
    ///@return 成功返回0, 否则-1
    ///@param argc启动参数个数
    ///@param argv启动参数列表
    int Start(int argc=0, const char **argv=0);

    ///停止服务
    ///@return 成功返回0, 否则-1
    int Stop();

    ///获取服务当前状态
    ///@return 成功返回状态值, 否则-1
    int GetCurrentStatus();

public:
    ///系统启动服务调用
    ///@remark 不可主动调用
    int Run(ServiceTask &service);

private:
    NTServiceImpl *m_impl;
};

#endif//_NTSERVICE_H_

 

  NTServiceImpl.h

  

#ifndef _NTSERVICE_IMPL_H_
#define _NTSERVICE_IMPL_H_
#include "NTService.h"
#include <Windows.h>
#include <string>

class NTServiceImpl
{
public:
    NTServiceImpl(const char *name,
        bool canstop, 
        bool canshutdown, 
        bool canpausecontinue);

    ~NTServiceImpl();

public:
    bool IsInstalled();
    int Install(const char *display_name, SERVICE_STARTUP_TYPE type);
    int UnInstall();
    int SetStartupType(SERVICE_STARTUP_TYPE type);
    int UpdateDesc(const char *desc);
    int Start(int argc, const char **argv);
    int Stop();
    int GetCurrentStatus();

    int Run(ServiceTask &service);

private:
    std::string m_name;
    bool m_canstop;
    bool m_canshutdown;
    bool m_canpausecontinue;
};

class NTServiceManager
{
private:
    NTServiceManager();
    ~NTServiceManager();

public:
    static bool IsInstalled(const char *name);
    static int Install(const char *name, const char *display_name, SERVICE_STARTUP_TYPE type);
    static int UnInstall(const char *name);
    static int SetStartupType(const char *name, SERVICE_STARTUP_TYPE type);
    static int UpdateDesc(const char *name, const char *desc);
    static int Start(const char *name, int argc, const char **argv);
    static int Stop(const char *name);
    static int GetCurrentStatus(const char *name);

private:
    static int GetRealStartupType(SERVICE_STARTUP_TYPE type);
};

class NTServiceHandler
{
private:
    NTServiceHandler(const std::string &name,
        bool canstop,
        bool canshutdown,
        bool canpausecontinue,
        ServiceTask &service);

    ~NTServiceHandler();

public:
    static void CreateInstance(const std::string &name,
        bool canstop,
        bool canshutdown,
        bool canpausecontinue,
        ServiceTask &service)
    {
        DestroyInstance();
        m_this =new NTServiceHandler(name, canstop, canshutdown, canpausecontinue, service);
    }
    static NTServiceHandler *GetInstance()
    {
        return m_this;
    }
    static void DestroyInstance()
    {
        if (m_this)
        {
            delete m_this;
            m_this = 0;
        }
    }

public:
    int Run();

private:
    static void ServiceMainHandler(DWORD argc, LPSTR *argv);
    static void ServiceCtrlHandler(DWORD ctrl);

private:
    void NTS_Start(DWORD argc, LPSTR *argv);
    void NTS_Stop();
    void NTS_Pause();
    void NTS_Continue();
    void NTS_Shutdown();

    void SetServiceStatus(DWORD dwCurrentState,
        DWORD dwWin32ExitCode=NO_ERROR,
        DWORD dwWaitHint=0);

    int OnInit(int argc, char **argv);
    void OnStart();
    void OnStop();
    void OnPause();
    void OnContinue();
    void OnShutdown();
    
private:
    std::string m_name;
    ServiceTask &m_service;

    SERVICE_STATUS m_status;
    SERVICE_STATUS_HANDLE m_status_handle;
    
    static NTServiceHandler *m_this;
};

NTServiceHandler *NTServiceHandler::m_this = 0;

#endif//_NTSERVICE_IMPL_H_
View Code

 

  NTServiceImpl.cpp

#include "NTServiceImpl.h"
#include <assert.h>

NTService::NTService(const char *name,
    bool canstop, 
    bool canshutdown, 
    bool canpausecontinue)
{
    m_impl = new NTServiceImpl(name, canstop, canshutdown, canpausecontinue);
}
NTService::~NTService()
{
    if (m_impl)
    {
        delete m_impl;
        m_impl = 0;
    }
}
bool NTService::IsInstalled()
{
    return m_impl->IsInstalled();
}
int NTService::Install(const char *display_name, SERVICE_STARTUP_TYPE type)
{
    return m_impl->Install(display_name, type);
}
int NTService::UnInstall()
{
    return m_impl->UnInstall();
}
int NTService::SetStartupType(SERVICE_STARTUP_TYPE type)
{
    return m_impl->SetStartupType(type);
}
int NTService::UpdateDesc(const char *desc)
{
    return m_impl->UpdateDesc(desc);
}
int NTService::Start(int argc, const char **argv)
{
    return m_impl->Start(argc, argv);    
}
int NTService::Stop()
{
    return m_impl->Stop();    
}
int NTService::GetCurrentStatus()
{
    return m_impl->GetCurrentStatus();
}
int NTService:: Run(ServiceTask &service)
{
    return m_impl->Run(service);
}

NTServiceImpl::NTServiceImpl(const char *name,
    bool canstop, 
    bool canshutdown, 
    bool canpausecontinue)
    : m_name(name)
{
    m_canstop = canstop;
    m_canshutdown = canshutdown;
    m_canpausecontinue = canpausecontinue;
}

NTServiceImpl::~NTServiceImpl()
{
}

bool NTServiceImpl::IsInstalled()
{
    return NTServiceManager::IsInstalled(m_name.c_str());
}

int NTServiceImpl::Install(const char *display_name, SERVICE_STARTUP_TYPE type)
{
    return NTServiceManager::Install(m_name.c_str(), display_name, type);
}

int NTServiceImpl::UnInstall()
{
    return NTServiceManager::UnInstall(m_name.c_str());
}

int NTServiceImpl::Start(int argc, const char **argv)
{
    return NTServiceManager::Start(m_name.c_str(), argc, argv);
}

int NTServiceImpl::Stop()
{
    return NTServiceManager::Stop(m_name.c_str());
}

int NTServiceImpl::SetStartupType(SERVICE_STARTUP_TYPE type)
{
    return NTServiceManager::SetStartupType(m_name.c_str(), type);
}

int NTServiceImpl::UpdateDesc(const char *desc)
{
    return NTServiceManager::UpdateDesc(m_name.c_str(), desc);
}

int NTServiceImpl::GetCurrentStatus()
{
    return NTServiceManager::GetCurrentStatus(m_name.c_str());
}

int NTServiceImpl::Run(ServiceTask &service)
{
    NTServiceHandler::CreateInstance(m_name, m_canstop, m_canshutdown, m_canpausecontinue, service);
    NTServiceHandler *handler = NTServiceHandler::GetInstance();
    return handler ? handler->Run() : -1;
}

bool NTServiceManager::IsInstalled(const char *name)
{
    assert(name);

    bool result = false;
    SC_HANDLE scmanager = 0;
    SC_HANDLE service = 0;

    scmanager = ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
    if (!scmanager)
    {
        goto __Cleanup;
    }

    service = ::OpenService(scmanager, name, SERVICE_QUERY_STATUS);

__Cleanup:
    if (service)
    {
        result = true;
        ::CloseServiceHandle(service);
    }
    if (scmanager)
    {
        ::CloseServiceHandle(scmanager);
    }

    return result;
}

int NTServiceManager::Install(const char *name, const char *display_name, SERVICE_STARTUP_TYPE type)
{
    assert(name && display_name);

    int result = -1;
    SC_HANDLE scmanager = 0;
    SC_HANDLE service = 0;

    scmanager = ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT|SC_MANAGER_CREATE_SERVICE);
    if (!scmanager)
    {
        goto __Cleanup;
    }

    char file_path[MAX_PATH] = {0};
    ::GetModuleFileName(NULL, file_path, MAX_PATH);

    int startup_type = GetRealStartupType(type);

    service = CreateService( 
        scmanager,                                            // SCM database 
        name,                                                    // name of service 
        display_name,                                        // service name to display 
        SERVICE_ALL_ACCESS,                            // desired access 
        SERVICE_WIN32_OWN_PROCESS,            // service type 
        startup_type,                                            // start type 
        SERVICE_ERROR_NORMAL,                    // error control type 
        file_path,                                                // path to service's binary 
        NULL,                                                    // no load ordering group 
        NULL,                                                    // no tag identifier 
        NULL,                                                    // no dependencies 
        NULL,                                                    // LocalSystem account 
        NULL);                                                    // no password

__Cleanup:
    if (service)
    {
        result = 0;
        ::CloseServiceHandle(service);
    }
    if (scmanager)
    {
        ::CloseServiceHandle(scmanager);
    }

    return result;
}

int NTServiceManager::UnInstall(const char *name)
{
    assert(name);

    int result = -1;
    SC_HANDLE scmanager = 0;
    SC_HANDLE service = 0;
    SERVICE_STATUS status = {0};

    scmanager = ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
    if (!scmanager)
    {
        goto __Cleanup;
    }

    service = ::OpenService(scmanager, name, SERVICE_STOP|SERVICE_QUERY_STATUS|DELETE);
    if (!service)
    {
        goto __Cleanup;
    }

    if (ControlService(service, SERVICE_CONTROL_STOP, &status))
    {
        ::Sleep(1000);

        while (QueryServiceStatus(service, &status))
        {
            if (status.dwCurrentState != SERVICE_STOP_PENDING)
            {
                break;
            }
            else
            {
                Sleep(1000);
            }
        }
    }

    if (DeleteService(service))
    {
        result = 0;
    }

__Cleanup:
    if (service)
    {
        ::CloseServiceHandle(service);
    }
    if (scmanager)
    {
        ::CloseServiceHandle(scmanager);
    }

    return result;
}

int NTServiceManager::SetStartupType(const char *name, SERVICE_STARTUP_TYPE type)
{
    assert(name);

    int result = -1;
    SC_HANDLE scmanager = 0;
    SC_HANDLE service = 0;

    scmanager = ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
    if (!scmanager)
    {
        goto __Cleanup;
    }

    service = ::OpenService(scmanager, name, SERVICE_CHANGE_CONFIG);
    if (!service)
    {
        goto __Cleanup;
    }

    int startup_type = GetRealStartupType(type);

    BOOL csc_result = ChangeServiceConfig( 
        service,                                        // handle of service 
        SERVICE_NO_CHANGE,                // service type: no change 
        startup_type,                                // service start type 
        SERVICE_NO_CHANGE,                // error control: no change 
        NULL,                                        // binary path: no change 
        NULL,                                        // load order group: no change 
        NULL,                                        // tag ID: no change 
        NULL,                                        // dependencies: no change 
        NULL,                                        // account name: no change 
        NULL,                                        // password: no change 
        NULL);                                        // display name: no change

    if (csc_result)
    {
        result = 0;
    }

__Cleanup:
    if (service)
    {
        ::CloseServiceHandle(service);
    }
    if (scmanager)
    {
        ::CloseServiceHandle(scmanager);
    }

    return result;
}

int NTServiceManager::UpdateDesc(const char *name, const char *desc)
{
    assert(name);

    int result = -1;
    SC_HANDLE scmanager = 0;
    SC_HANDLE service = 0;
    SERVICE_DESCRIPTION sd = {0};
    sd.lpDescription = (char *)desc;

    scmanager = ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
    if (!scmanager)
    {
        goto __Cleanup;
    }

    service = ::OpenService(scmanager, name, SERVICE_CHANGE_CONFIG);
    if (!service)
    {
        goto __Cleanup;
    }

    if (ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &sd))
    {
        result = 0;
    }

__Cleanup:
    if (service)
    {
        ::CloseServiceHandle(service);
    }
    if (scmanager)
    {
        ::CloseServiceHandle(scmanager);
    }

    return result;
}

int NTServiceManager::Start(const char *name, int argc, const char **argv)
{
    assert(name);

    int result = -1;
    SC_HANDLE scmanager = 0;
    SC_HANDLE service = 0;
    SERVICE_STATUS status = {0};
    DWORD dwStartTickCount = 0;
    DWORD dwOldCheckPoint = 0;
    DWORD dwWaitTime = 0;

    scmanager = ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
    if (!scmanager)
    {
        goto __Cleanup;
    }

    service = ::OpenService(scmanager, name, SERVICE_ALL_ACCESS);
    if (!service)
    {
        goto __Cleanup;
    }

    if (!QueryServiceStatus(service, &status))
    {
        goto __Cleanup;
    }

    if(status.dwCurrentState!=SERVICE_STOPPED 
        && status.dwCurrentState!=SERVICE_STOP_PENDING)
    {
        goto __Cleanup;
    }

    dwStartTickCount = GetTickCount();
    dwOldCheckPoint = status.dwCheckPoint;
    while (status.dwCurrentState == SERVICE_STOP_PENDING)
    {
        dwWaitTime = status.dwWaitHint / 10;
        if(dwWaitTime < 1000)
        {
            dwWaitTime = 1000;
        }
        else if (dwWaitTime > 10000)
        {
            dwWaitTime = 10000;
        }
        ::Sleep(dwWaitTime);

        if (!QueryServiceStatus(service, &status))
        {
            goto __Cleanup;
        }

        if (status.dwCheckPoint > dwOldCheckPoint)
        {
            dwStartTickCount = GetTickCount();
            dwOldCheckPoint = status.dwCheckPoint;
        }
        else
        {
            if ((GetTickCount()-dwStartTickCount) > status.dwWaitHint)
            {
                goto __Cleanup;
            }
        }
    }

    if (!StartService(service, argc, argv))
    {
        goto __Cleanup;
    }

    if (!QueryServiceStatus(service, &status))
    {
        goto __Cleanup;
    }

    dwStartTickCount = GetTickCount();
    dwOldCheckPoint = status.dwCheckPoint;
    while (status.dwCurrentState == SERVICE_START_PENDING) 
    { 
        dwWaitTime = status.dwWaitHint / 10;
        if(dwWaitTime < 1000)
        {
            dwWaitTime = 1000;
        }
        else if (dwWaitTime > 10000)
        {
            dwWaitTime = 10000;
        }
        ::Sleep(dwWaitTime);

        if (!QueryServiceStatus(service, &status))
        {
            goto __Cleanup;
        }

        if (status.dwCheckPoint > dwOldCheckPoint)
        {
            dwStartTickCount = GetTickCount();
            dwOldCheckPoint = status.dwCheckPoint;
        }
        else
        {
            if ((GetTickCount()-dwStartTickCount) > status.dwWaitHint)
            {
                break;
            }
        }
    } 

__Cleanup:
    if (status.dwCurrentState==SERVICE_RUNNING)
    {
        result = 0;
    }

    if (service)
    {
        ::CloseServiceHandle(service);
    }
    if (scmanager)
    {
        ::CloseServiceHandle(scmanager);
    }

    return result;
}

int NTServiceManager::Stop(const char *name)
{
    assert(name);

    int result = -1;
    SC_HANDLE scmanager = 0;
    SC_HANDLE service = 0;
    SERVICE_STATUS status = {0};
    DWORD dwStartTime = GetTickCount();
    DWORD dwTimeout = 30000;
    DWORD dwWaitTime = 0;
    
    scmanager = ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
    if (!scmanager)
    {
        goto __Cleanup;
    }

    service = ::OpenService(scmanager, name, SERVICE_STOP|SERVICE_QUERY_STATUS);
    if (!service)
    {
        goto __Cleanup;
    }

    if (!QueryServiceStatus(service, &status))
    {
        goto __Cleanup;
    }

    if (status.dwCurrentState == SERVICE_STOPPED)
    {
        goto __Cleanup;
    }

    while (status.dwCurrentState == SERVICE_STOP_PENDING)
    {
        dwWaitTime = status.dwWaitHint / 10;
        if(dwWaitTime < 1000)
        {
            dwWaitTime = 1000;
        }
        else if (dwWaitTime > 10000)
        {
            dwWaitTime = 10000;
        }
        ::Sleep(dwWaitTime);

        if (!QueryServiceStatus(service, &status))
        {
            goto __Cleanup;
        }

        if (status.dwCurrentState == SERVICE_STOPPED)
        {
            goto __Cleanup;
        }

        if ((GetTickCount() - dwStartTime) > dwTimeout)
        {
            goto __Cleanup;
        }
    }

    if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
    {
        goto __Cleanup;
    }

    while (status.dwCurrentState != SERVICE_STOPPED)
    {
        ::Sleep(status.dwWaitHint);

        if (!QueryServiceStatus(service, &status))
        {
            goto __Cleanup;
        }

        if (status.dwCurrentState == SERVICE_STOPPED)        
        {
            goto __Cleanup;
        }

        if ( GetTickCount() - dwStartTime > dwTimeout )
        {
            goto __Cleanup;
        }
    }

__Cleanup:
    if (status.dwCurrentState == SERVICE_STOPPED)
    {
        result = 0;
    }

    if (service)
    {
        ::CloseServiceHandle(service);
    }
    if (scmanager)
    {
        ::CloseServiceHandle(scmanager);
    }

    return result;
}

int NTServiceManager::GetCurrentStatus(const char *name)
{
    assert(name);

    int result = -1;
    SC_HANDLE scmanager = 0;
    SC_HANDLE service = 0;
    SERVICE_STATUS status = {0};

    scmanager = ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
    if (!scmanager)
    {
        goto __Cleanup;
    }

    service = ::OpenService(scmanager, name, SERVICE_QUERY_STATUS);
    if (!service)
    {
        goto __Cleanup;
    }

    if (QueryServiceStatus(service, &status))
    {
        result = status.dwCurrentState;
    }

__Cleanup:
    if (service)
    {
        ::CloseServiceHandle(service);
    }
    if (scmanager)
    {
        ::CloseServiceHandle(scmanager);
    }

    return result;
}

int NTServiceManager::GetRealStartupType(SERVICE_STARTUP_TYPE type)
{
    switch (type)
    {
    case SST_AUTO_START:
        {
            return SERVICE_AUTO_START;
        }
    case SST_DEMAND_START:
        {
            return SERVICE_DEMAND_START;
        }
    case SST_DISABLED:
    default:
        {
            return SERVICE_DISABLED;
        }
    }
}

NTServiceHandler::NTServiceHandler(const std::string &name,
    bool canstop,
    bool canshutdown,
    bool canpausecontinue,
    ServiceTask &service)
    : m_name(name),
    m_service(service)
{
    memset(&m_status, 0, sizeof(SERVICE_STATUS));
    m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    m_status.dwCurrentState = SERVICE_START_PENDING;
    m_status.dwWin32ExitCode = NO_ERROR;
    m_status.dwServiceSpecificExitCode = 0;
    m_status.dwCheckPoint = 0;
    m_status.dwWaitHint = 0;

    if (canstop)
    {
        m_status.dwControlsAccepted |= SERVICE_ACCEPT_STOP;
    }
    if (canshutdown)
    {
        m_status.dwControlsAccepted |= SERVICE_ACCEPT_SHUTDOWN;
    }
    if (canpausecontinue)
    {
        m_status.dwControlsAccepted |= SERVICE_ACCEPT_PAUSE_CONTINUE;
    }

    m_status_handle = 0;
}

NTServiceHandler::~NTServiceHandler()
{
}

int NTServiceHandler::Run()
{
    SERVICE_TABLE_ENTRY st[] =
    {
        {(LPSTR)m_name.c_str(), (LPSERVICE_MAIN_FUNCTION)ServiceMainHandler},
        {NULL, NULL}
    };

    return ::StartServiceCtrlDispatcher(st) ? 0 : -1;
}

void NTServiceHandler::ServiceMainHandler(DWORD argc, LPSTR *argv)
{
    NTServiceHandler *m_this = GetInstance();
    if (m_this)
    {
        m_this->m_status_handle = RegisterServiceCtrlHandler(m_this->m_name.c_str(), (LPHANDLER_FUNCTION)ServiceCtrlHandler);
        if (!m_this->m_status_handle)
        {
            return;
        }

        m_this->NTS_Start(argc, argv);
    }
}

void NTServiceHandler::ServiceCtrlHandler(DWORD ctrl)
{
    NTServiceHandler *m_this = GetInstance();
    if (m_this)
    {
        switch (ctrl)
        { 
        case SERVICE_CONTROL_STOP:
            {
                m_this->NTS_Stop();
            }
            break;
        case SERVICE_CONTROL_PAUSE:
            {
                m_this->NTS_Pause();
            }
            break;
        case SERVICE_CONTROL_CONTINUE:
            {
                m_this->NTS_Continue();
            }
            break;
        case SERVICE_CONTROL_SHUTDOWN:
            {
                m_this->NTS_Shutdown();
            }
            break;
        case SERVICE_CONTROL_INTERROGATE:
        default:
            break;
        }
    }
}

void NTServiceHandler::NTS_Start(DWORD argc, LPSTR *argv)
{
    try
    {
        SetServiceStatus(SERVICE_START_PENDING);
        
        if (OnInit(argc, argv) != 0)
        {
            exit(0);
        }
    
        SetServiceStatus(SERVICE_RUNNING);

        OnStart();

        SetServiceStatus(SERVICE_STOPPED);
    }
    catch (DWORD dwError)
    {
        SetServiceStatus(SERVICE_STOPPED, dwError);
    }
    catch (...)
    {
        SetServiceStatus(SERVICE_STOPPED);
    }
}

void NTServiceHandler::NTS_Stop()
{
    DWORD dwOriginalState = m_status.dwCurrentState;

    try
    {
        SetServiceStatus(SERVICE_STOP_PENDING);

        OnStop();

        SetServiceStatus(SERVICE_STOPPED);
    }
    catch (DWORD dwError)
    {
        dwError = 0;
        SetServiceStatus(dwOriginalState);
    }
    catch (...)
    {
        SetServiceStatus(dwOriginalState);
    }
}

void NTServiceHandler::NTS_Pause()
{
    try
    {
        SetServiceStatus(SERVICE_PAUSE_PENDING);

        OnPause();

        SetServiceStatus(SERVICE_PAUSED);
    }
    catch (DWORD dwError)
    {
        dwError = 0;
        SetServiceStatus(SERVICE_RUNNING);
    }
    catch (...)
    {
        SetServiceStatus(SERVICE_RUNNING);
    }
}

void NTServiceHandler::NTS_Continue()
{
    try
    {
        SetServiceStatus(SERVICE_CONTINUE_PENDING);

        OnContinue();

        SetServiceStatus(SERVICE_RUNNING);
    }
    catch (DWORD dwError)
    {
        dwError = 0;
        SetServiceStatus(SERVICE_PAUSED);
    }
    catch (...)
    {
        SetServiceStatus(SERVICE_PAUSED);
    }
}

void NTServiceHandler::NTS_Shutdown()
{
    try
    {
        OnShutdown();

        SetServiceStatus(SERVICE_STOPPED);
    }
    catch (DWORD dwError)
    {
        dwError = 0;
    }
    catch (...)
    {
    }
}

void NTServiceHandler::SetServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
{
    assert(m_status_handle);

    static DWORD dwCheckPoint = 0;

    m_status.dwCurrentState = dwCurrentState;
    m_status.dwWin32ExitCode = dwWin32ExitCode;
    m_status.dwWaitHint = dwWaitHint;

    if (dwCurrentState==SERVICE_RUNNING
        || dwCurrentState==SERVICE_STOPPED)
    {
        m_status.dwCheckPoint = 0;
    }
    else 
    {
        m_status.dwCheckPoint = ++dwCheckPoint;
    }

    ::SetServiceStatus(m_status_handle, &m_status);
}

int NTServiceHandler::OnInit(int argc, char **argv)
{
    return m_service.OnInit(argc, argv);
}

void NTServiceHandler::OnStart()
{
    m_service.OnStart();
}

void NTServiceHandler::OnStop()
{
    m_service.OnStop();
}

void NTServiceHandler::OnPause()
{
    m_service.OnPause();
}

void NTServiceHandler::OnContinue()
{
    m_service.OnContinue();
}

void NTServiceHandler::OnShutdown()
{
    m_service.OnShutdown();
}
View Code