Click here to Skip to main content
15,898,222 members
Articles / Programming Languages / C++

A Self Contained NT Service Class: No Derivations Required

Rate me:
Please Sign up or sign in to vote.
4.66/5 (17 votes)
8 Aug 2007CPOL8 min read 44.8K   1.2K   34  
A class to create a NT service with a few lines of code
#include "nt_service.h"

using namespace win;

//-----------------------------------------------------------------------------
// meyer's singletom implementation
//-----------------------------------------------------------------------------
nt_service& nt_service::instance(	const char_ * const name_ , std::ostream * const log_ )									
{
	m_name = name_;
	m_log  = log_;

	static  nt_service obj; 
	return  obj;
}
//-----------------------------------------------------------------------------
void nt_service::register_service_main( LPSERVICE_MAIN_FUNCTION service_main_ )
{
	m_user_service_main = service_main_;
}
//-----------------------------------------------------------------------------
void nt_service::register_control_handler( NTSERVICE_CONTROL			ctrl_,
										   NTSERVICE_CALLBACK_FUNCTION	ctrl_handler_ )
{
	if ( ctrl_handler_ )
	{
		m_callback_map[ ctrl_ ] = ctrl_handler_;
		m_accepted_controls << convert_control_to_accept( ctrl_ );
	}
}
//-----------------------------------------------------------------------------
void nt_service::register_init_function( NTSERVICE_CALLBACK_FUNCTION  init_fcn_ )
{
	m_service_init_fcn = init_fcn_;
}
//-----------------------------------------------------------------------------
void nt_service::accept_control( NTSERVICE_ACCEPT control_ )
{
	m_accepted_controls << control_;	
}
//-----------------------------------------------------------------------------
void nt_service::start()
{
	SERVICE_TABLE_ENTRY service_table[2];
    
	service_table[0].lpServiceName = const_cast<char_*>( m_name );
	service_table[0].lpServiceProc = & nt_service_main;
	service_table[1].lpServiceName = 0;
    service_table[1].lpServiceProc = 0;

	StartServiceCtrlDispatcher(service_table);
}
//-----------------------------------------------------------------------------
void nt_service::stop( DWORD exit_code_ )
{
	if ( m_handle )
	{
		m_status.dwCurrentState  = SERVICE_STOPPED;
		m_status.dwWin32ExitCode = exit_code_; 
		SetServiceStatus ( m_handle, & m_status );
	}
}
//-----------------------------------------------------------------------------
NTSERVICE_ACCEPT nt_service::convert_control_to_accept( NTSERVICE_CONTROL control_ )
{
	switch( control_ )
	{
		case SERVICE_CONTROL_STOP:
			return SERVICE_ACCEPT_STOP;

		case SERVICE_CONTROL_PAUSE:
		case SERVICE_CONTROL_CONTINUE:
			return SERVICE_ACCEPT_PAUSE_CONTINUE;

		case SERVICE_CONTROL_SHUTDOWN:
			return SERVICE_ACCEPT_SHUTDOWN;

		case SERVICE_CONTROL_PARAMCHANGE:
			return SERVICE_ACCEPT_PARAMCHANGE;

		case SERVICE_CONTROL_NETBINDADD:
		case SERVICE_CONTROL_NETBINDREMOVE:
		case SERVICE_CONTROL_NETBINDENABLE:
		case SERVICE_CONTROL_NETBINDDISABLE:
			return SERVICE_ACCEPT_NETBINDCHANGE;

		case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
			return SERVICE_ACCEPT_HARDWAREPROFILECHANGE;

		case SERVICE_CONTROL_POWEREVENT:
			return SERVICE_ACCEPT_POWEREVENT;

		case SERVICE_CONTROL_SESSIONCHANGE:
			return SERVICE_ACCEPT_SESSIONCHANGE;	

		case SERVICE_CONTROL_INTERROGATE:
		case SERVICE_CONTROL_DEVICEEVENT:
		default:
			return NTSERVICE_ACCEPT( 0 );

	}
}
//-----------------------------------------------------------------------------
VOID WINAPI nt_service::service_control_handler( NTSERVICE_CONTROL control_ )
{
	if ( m_callback_map.find( control_ ) != m_callback_map.end() )
	{
		m_callback_map[ control_ ]();
	}

	switch( control_ ) 
    { 
        case SERVICE_CONTROL_STOP: 
            m_status.dwCurrentState  = SERVICE_STOPPED; 
            break;
        case SERVICE_CONTROL_SHUTDOWN: 
            m_status.dwCurrentState  = SERVICE_STOPPED; 
            break;
		case SERVICE_CONTROL_PAUSE:
			m_status.dwCurrentState  = SERVICE_PAUSED; 
        default:
			m_status.dwCurrentState  = SERVICE_RUNNING; 
            break;
	}
	m_status.dwWin32ExitCode = 0; 
    SetServiceStatus ( m_handle, & m_status );
}
//-----------------------------------------------------------------------------
VOID WINAPI nt_service::nt_service_main( DWORD argc_, char_* argv_[] )
{
	m_status.dwServiceType        = SERVICE_WIN32; 
    m_status.dwCurrentState       = SERVICE_START_PENDING; 
	m_status.dwControlsAccepted   = m_accepted_controls.to_dword();
     
    m_handle = RegisterServiceCtrlHandler( m_name, service_control_handler );

    if ( m_handle == 0 ) 
    { 
		if ( m_log )*m_log<<"[E] - nt_service: RegisterServiceCtrlHandler failed\n";
		return; 
    }  
    
	if ( m_service_init_fcn )
	{
		try
		{
			m_service_init_fcn();
		}
		catch(...)
		{
			if ( m_log )*m_log<<"[E] - nt_service: m_service_init_fcn failed\n";
			nt_service::stop(-1);
			return;
		}
	}
	    
    // We report the running status to SCM. 
    m_status.dwCurrentState = SERVICE_RUNNING; 
    SetServiceStatus( m_handle, & m_status);
     
    // The worker loop of a service
    while ( m_status.dwCurrentState == SERVICE_RUNNING )
	{
		try
		{
			m_user_service_main( argc_, argv_ );
		}
		catch(...)
		{
			if ( m_log )*m_log<<"[E] - nt_service: in service main\n";
			nt_service::stop( -1 );
		}
	}
    return; 
}
//-----------------------------------------------------------------------------
const char_*						nt_service::m_name					= 0;
SERVICE_STATUS						nt_service::m_status;
SERVICE_STATUS_HANDLE				nt_service::m_handle				= 0;
LPSERVICE_MAIN_FUNCTION				nt_service::m_user_service_main		= 0;
NTSERVICE_CALLBACK_FUNCTION			nt_service::m_service_init_fcn		= 0;
map< NTSERVICE_CONTROL , 
	 NTSERVICE_CALLBACK_FUNCTION >	nt_service::m_callback_map;
bitmask< NTSERVICE_ACCEPT >			nt_service::m_accepted_controls		= 0;
ostream *							nt_service::m_log					= 0;

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Brazil Brazil
I taught myself C and then C ++ at college (I have a degree in Naval Engineering) just for the fun of it, and started creating some simple engineering applications, to replace the ones available to me back then (most were crap at that time, and still are today!)

Even before my Engineering graduation I got a job as a C/C++ programmer. I´ve been working with programming since then, in C/C++ most of the time but also in other languages ​​when needed or fun!

Comments and Discussions