Channels ▼
RSS

A Wrapper Class for NT Services


August 1998/A Wrapper Class for NT Services/Listing 2

Listing 2: Implementation file for NTService class

#include <windows.h>
#include "ntservice.h"

NTService::NTService( const char *name, 
    LPSERVICE_MAIN_FUNCTION funp_srvmain, 
    LPHANDLER_FUNCTION funp_ctrl)
{
    //== first initialize data members from the args
    //== set function pointers for later use
    mfpSrvMain = funp_srvmain;
    mfpSrvControl = funp_ctrl;

    //== copy the service name - if needed add UNICODE support here
    memset( m_name, 0, sizeof(m_name) );
    strncpy( m_name, name, sizeof(m_name)-1);

    //== clear the status flags
    m_isStarted = false;
    m_isPaused = false;

    //== clear the dispatch table
    memset( &mDispatchTable[0], 0, sizeof( mDispatchTable ) );

    //== clear the SERVICE_STATUS data structure
    memset( &mStat, 0, sizeof( SERVICE_STATUS ));
    mh_Stat = 0;

    //== Now initialize SERVICE_STATUS here so we can 
    //== call SetAcceptedControls() before Startup() or
    //== override in constructor of child class.
    mStat.dwServiceType         = SERVICE_WIN32; 
    mStat.dwCurrentState        = SERVICE_START_PENDING; 
    mStat.dwControlsAccepted    = SERVICE_ACCEPT_STOP 
                                | SERVICE_ACCEPT_PAUSE_CONTINUE
                                | SERVICE_ACCEPT_SHUTDOWN; 
}

NTService::~NTService( void )
{
}

DWORD NTService::Startup( void )
{
    //== initialize the dispatch table
    mDispatchTable[0].lpServiceName = m_name;     //== Note: these 
    mDispatchTable[0].lpServiceProc = mfpSrvMain; //   are pointers

    //== starts the service 
    if( !StartServiceCtrlDispatcher( mDispatchTable )){
        m_err = ::GetLastError();
        return m_err;
    }

    return NO_ERROR;
}

int NTService::Service( DWORD argc, LPTSTR* argv )
{
    mh_Stat = RegisterServiceCtrlHandler( TEXT( m_name ), 
                  mfpSrvControl );
    if( (SERVICE_STATUS_HANDLE)0 == mh_Stat )
    {
        m_err = ::GetLastError();
        return m_err;
    }
    
    if( Init( argc, argv ) != NO_ERROR )
    {
        ChangeStatus( SERVICE_STOPPED );
        return m_err;
    }
    
    ChangeStatus( SERVICE_RUNNING );
    return Run();
}

void NTService::Control( DWORD opcode )
{
    switch( opcode )
    {
    case SERVICE_CONTROL_PAUSE:
        ChangeStatus( SERVICE_PAUSE_PENDING );
        if( OnPause() == NO_ERROR )
        {
            m_isPaused = true;
            ChangeStatus( SERVICE_PAUSED );
        }
        break;

    case SERVICE_CONTROL_CONTINUE:
        ChangeStatus( SERVICE_CONTINUE_PENDING );
        if( OnContinue() == NO_ERROR )
        {
            m_isPaused = false;
            ChangeStatus( SERVICE_RUNNING );
        }
        break;

    case SERVICE_CONTROL_STOP:
        ChangeStatus( SERVICE_STOP_PENDING );
        OnStop();
        ChangeStatus( SERVICE_STOPPED );
        break;

    case SERVICE_CONTROL_SHUTDOWN:
        ChangeStatus( SERVICE_STOP_PENDING );
        OnShutdown();
        ChangeStatus( SERVICE_STOPPED );
        break;

    case SERVICE_CONTROL_INTERROGATE:
        OnInquire();
        SetServiceStatus( mh_Stat, &mStat );
        break;

    default:
        OnUserControl( opcode );
        SetServiceStatus( mh_Stat, &mStat );
        break;
    };
    return;
}


bool NTService::Install( void )
{
    //== check to see if we are already installled
    if( IsInstalled() )
        return true;

    //== get the service manager handle
    SC_HANDLE schSCMgr = 
        OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
    if( schSCMgr == NULL )
    {
        m_err = ::GetLastError();
        return false;
    }

    //== get the full path of the executable
    char szFilePath[_MAX_PATH];
    ::GetModuleFileName(NULL, szFilePath, sizeof(szFilePath));


    //== install the service
    SC_HANDLE schSrv = CreateService(
        schSCMgr,
        m_name,
        m_name,
        SERVICE_ALL_ACCESS,
        SERVICE_WIN32_OWN_PROCESS,
        SERVICE_DEMAND_START,
        SERVICE_ERROR_NORMAL,
        szFilePath,
        NULL,
        NULL,
        NULL,
        NULL,
        NULL
    );

    bool bRetval = true;
    if( schSrv == NULL )
    {
        m_err = ::GetLastError();
        bRetval = false;
    }
    else
        InstallAid(); //== overload to add registry entries 
                      //   if needed
    
    //== All done, so pick up our toys and go home!
    CloseServiceHandle( schSrv );
    CloseServiceHandle( schSCMgr );
    return bRetval;
}

bool NTService::UnInstall( void )
{
    if( !IsInstalled() )
        return true;

    //== get the service manager handle
    SC_HANDLE schSCMgr = 
        OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
    if( schSCMgr == NULL )
    {
        m_err = ::GetLastError();
        return false;
    }

    //== Get the service handle
    SC_HANDLE schSrv = OpenService( schSCMgr, m_name, DELETE );
    if( schSrv == NULL )
    {
        m_err = ::GetLastError();
        CloseServiceHandle( schSCMgr );
        return false;
    }

    //== Now delete the service
    bool bRetval = true;
    if( !DeleteService( schSrv ) )
    {
        bRetval = false;
        m_err = ::GetLastError();
    }

    //== do any application specific cleanup
    UnInstallAid();

    //== Put away toys and go home!
    CloseServiceHandle( schSrv );
    CloseServiceHandle( schSCMgr );
    return bRetval;
}

DWORD    NTService::GetLastError( void )
{
    return m_err;
}

/*=================================================================
bool NTService::IsInstalled()

Purpose: Returns true if the service has already been installed.
=================================================================*/
bool NTService::IsInstalled( void )
{
    bool bResult = false;

    // Open the Service Control Manager
    SC_HANDLE hSCM = 
        ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (hSCM) 
    {
        // Try to open the service
        SC_HANDLE hService = 
            ::OpenService(hSCM, m_name, SERVICE_QUERY_CONFIG);
        if (hService) 
        {
            bResult = true;
            ::CloseServiceHandle(hService);
        }
        ::CloseServiceHandle(hSCM);
    }
    
    return bResult;
}

void NTService::SetAcceptedControls( DWORD controls )
{
    mStat.dwControlsAccepted = controls;
}

void NTService::ChangeStatus( DWORD state, DWORD checkpoint, 
         DWORD waithint )
{
    mStat.dwCurrentState  = state;
    mStat.dwCheckPoint    = checkpoint;
    mStat.dwWaitHint      = waithint;
    
    SetServiceStatus( mh_Stat, &mStat );
}

/*=================================================================
    Stubs
=================================================================*/
DWORD 
NTService::Init( DWORD argc, LPTSTR* argv ) { return NO_ERROR; }

void  NTService::InstallAid( void ) {}
void  NTService::UnInstallAid( void ) {}

DWORD NTService::OnPause( void ) { return NO_ERROR; }
DWORD NTService::OnContinue( void ) { return NO_ERROR; }

void  NTService::OnStop( void ) {}
void  NTService::OnShutdown( void ) { OnStop(); }

void  NTService::OnInquire( void ) {}
void  NTService::OnUserControl( DWORD ) {}
//End of File

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video