Back to the WFC main page
CServiceControlManager
$Revision: 41 $
Description
This class handles playing with NT's Service Control Manager (SCM).
The SCM manages the starting/stopping/installing/removing/etc. of services.
Data Members
None.
Methods
void Close( void )
-
Closes your session with the SCM.
BOOL Continue( LPCTSTR service_name )
-
You give this function the name of a paused service. It will
tell the named service to continue.
BOOL EnableInteractiveServices( BOOL enable_interactive_services = TRUE )
-
This function returns TRUE if the setting was set, FALSE if there was a problem.
Calling EnableInteractiveServices() with
enable_interactive_services
set to FALSE will prevent any service from interacting with the desktop/user.
BOOL EnumerateStatus( DWORD state = SERVICE_ACTIVE, type = SERVICE_WIN32 )
-
This function allows you to enumerate services that have a particular status.
The
state
parameter may be one of:
- SERVICE_ACTIVE
- SERVICE_INACTIVE
- SERVICE_STATE_ALL
The type
parameter may be one of:
- SERVICE_WIN32
- SERVICE_DRIVER
BOOL GetConfiguration( LPCTSTR service_name, CServiceConfiguration& configuration )
-
This function retrieves useful information about how a service is configured.
BOOL GetDependencies( LPCTSTR service_name, CStringArray& dependencies )
-
Fills
dependencies
with the names of services that must be running before
the service_name
service can run.
DWORD GetErrorCode( void ) const
-
Retrieves the error code. Call this function to find out why any other class member returned FALSE.
SC_HANDLE GetHandle( void ) const
-
Returns the encapsulated SC_HANDLE.
Use this method if you want to call the Win32 API directly
(i.e. you don't want to use WFC).
BOOL GetKeyName( LPCTSTR display_name, CString& key_name )
-
Retrieves a service's internal name (real name) from the user-friendly name.
BOOL GetNext( CServiceNameAndStatus& status )
-
This function is called to retrieve the next name and status (CServiceNameAndStatus)
being enumerated via EnumerateStatus. It will return FALSE
when the last enumerated service has been retrieved.
BOOL Install( LPCTSTR service_name, LPCTSTR friendly_name, LPCTSTR name_of_executable_file )
-
This function will install a new service.
BOOL IsDatabaseLocked( CString& who_locked_it, CTimeSpan& how_long_it_has_been_locked )
-
If IsDatabaseLocked() returns TRUE, the database is locked,
who_locked_it
will be filled with the name of the user who locked it, how_long_it_has_been_locked
will be filled with how long that user has had the database locked. If
IsDatabaseLocked() returns FALSE, who_locked_it
will be
empty and how_long_it_has_been_locked
will be zero.
BOOL LockDatabase( void )
-
Locks the service control database. Only one process can lock the database at
any given time. You cannot start a service when the database is locked.The lock
prevents the service control manager from starting a service while it is
being reconfigured.
BOOL Open( DWORD what_to_open = SC_MANAGER_ALL_ACCESS,
LPCTSTR database_name = NULL,
LPCTSTR machine_name = NULL )
-
Opens a connection to the SCM on a machine.
BOOL Pause( LPCTSTR service_name )
-
Pauses the named service.
BOOL Remove( LPCTSTR service_name )
-
Un-installs a service. WARNING! This does a lot
of stuff for you. One of the things it will screw up is the Event Log. It removes the source of messages so you will no longer be
able to read entries in the log that the removed service made.
SetConfiguration( LPCTSTR service_name,
DWORD when_to_start = SERVICE_NO_CHANGE,
DWORD type_of_service = SERVICE_NO_CHANGE,
DWORD error_control = SERVICE_NO_CHANGE,
LPCTSTR name_of_executable_file = NULL,
LPCTSTR load_order_group = NULL,
LPCTSTR dependencies = NULL,
LPCTSTR start_name = NULL,
LPCTSTR password = NULL,
LPCTSTR display_name = NULL )
-
Changes a service's configuration. You can change
when a service is to start, type, name of the executable file, etc.
BOOL Start( LPCTSTR service_name, DWORD service_argc = 0, LPCTSTR *service_argv = NULL )
-
Starts a service by name. You supply the startup parameters.
BOOL Stop( LPCTSTR service_name )
-
Stops a service by name.
BOOL UnlockDatabase( void )
-
Unlocks the service control database.
Example
#include <wfc.h>
#include "messages.h"
#pragma hdrstop
#if defined( _DEBUG )
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
DWORD WINAPI worker_thread( LPVOID pointer_to_parent_CService_class );
VOID set_default_parameters( void );
int __cdecl _tmain( int number_of_command_line_arguments, LPCTSTR command_line_arguments[] )
{
WFCTRACEINIT( TEXT( "_tmain()" ) );
if ( number_of_command_line_arguments == 1 )
{
CService service( worker_thread );
service.Initialize( TEXT( "WatchDog" ) );
return( EXIT_SUCCESS );
}
if ( number_of_command_line_arguments == 2 )
{
if ( _tcsicmp( command_line_arguments[ 1 ], TEXT( "install" ) ) == 0 )
{
CServiceControlManager service_control_manager;
service_control_manager.Open();
if ( service_control_manager.Install( TEXT( "WatchDog" ),
TEXT( "WatchDog" ),
TEXT( "%SystemRoot%\\System32\\WatchDog.exe" ) ) == FALSE )
{
_tprintf( TEXT( "Install failed, please see Application Log for details\n" ) );
}
set_default_parameters();
return( EXIT_SUCCESS );
}
else if ( _tcsicmp( command_line_arguments[ 1 ], TEXT( "remove" ) ) == 0 )
{
CServiceControlManager service_control_manager;
service_control_manager.Open();
if ( service_control_manager.Remove( TEXT( "WatchDog" ) ) == FALSE )
{
_tprintf( TEXT( "Removing failed, please see Application Log for details\n" ) );
}
return( EXIT_SUCCESS );
}
else if ( _tcsicmp( command_line_arguments[ 1 ], TEXT( "run" ) ) == 0 )
{
worker_thread( (LPVOID) 1 );
return( EXIT_SUCCESS );
}
else
{
_tprintf( TEXT( "Samuel R. Blackburn, WFC Sample Application\nUsage: %s [install|remove]\n" ), command_line_arguments[ 0 ] );
}
}
else
{
_tprintf( TEXT( "Samuel R. Blackburn, WFC Sample Application\nUsage: %s [install|remove]\n" ), command_line_arguments[ 0 ] );
}
return( EXIT_SUCCESS );
}
DWORD WINAPI worker_thread( LPVOID )
{
WFCTRACEINIT( TEXT( "worker_thread()" ) );
{
CEventLog log( TEXT( "WatchDog" ) );
log.Report( CEventLog::eventInformation, 0, MSG_WATCHDOG_SERVICE_STARTED );
}
CStringArray names_of_services_to_keep_alive;
DWORD number_of_seconds_to_sleep = 0;
CString machine_name( TEXT( "" ) );
BOOL return_value = TRUE;
{
CRegistry registry;
if ( registry.Connect( CRegistry::keyLocalMachine ) == FALSE )
{
return( 0 );
}
CString key_name( TEXT( "SYSTEM\\CurrentControlSet\\Services\\WatchDog\\Parameters" ) );
if ( registry.Open( key_name ) == FALSE )
{
return( 0 );
}
registry.GetValue( TEXT( "Services" ), names_of_services_to_keep_alive );
registry.GetValue( TEXT( "NumberOfSecondsBetweenChecks" ), number_of_seconds_to_sleep );
registry.GetValue( TEXT( "MachineName" ), machine_name );
}
DWORD sleep_time = 1000 * number_of_seconds_to_sleep;
if ( sleep_time < 2000 )
{
// Minimum sleep time is 2 seconds, this give the OS time to do other things
sleep_time = 2000;
}
int number_of_services_to_keep_alive = names_of_services_to_keep_alive.GetSize();
CServiceControlManager service_control_manager;
/*
** Sleep for one minute, this is in case we are starting during boot-up. We want
** to give the service control manager time to start all necessary services before
** we begin restarting stopped services.
*/
Sleep( 60 );
do
{
if ( machine_name.IsEmpty() )
{
return_value = service_control_manager.Open( GENERIC_READ, NULL, (LPCTSTR) NULL );
}
else
{
return_value = service_control_manager.Open( GENERIC_READ, NULL, machine_name );
}
if ( return_value != FALSE )
{
if ( service_control_manager.EnumerateStatus( SERVICE_INACTIVE ) != FALSE )
{
CStringArray stopped_services;
CServiceNameAndStatus status;
while( service_control_manager.GetNext( status ) != FALSE )
{
stopped_services.Add( status.lpServiceName );
}
// Now that we have the service names, we need to see which services need to be started
int number_of_stopped_services = stopped_services.GetSize();
int alive_index = 0;
int stopped_index = 0;
while( alive_index < number_of_services_to_keep_alive )
{
stopped_index = 0;
while( stopped_index < number_of_stopped_services )
{
if ( names_of_services_to_keep_alive[ alive_index ].CompareNoCase( stopped_services[ stopped_index ] ) == 0 )
{
// We found one that died, let's start it
service_control_manager.Start( names_of_services_to_keep_alive[ alive_index ] );
// We restarted a service, time to record the event
LPCTSTR string_array[ 1 ];
string_array[ 0 ] = (LPCTSTR) names_of_services_to_keep_alive[ alive_index ];
CEventLog event_log( TEXT( "WatchDog" ) );
event_log.Report( CEventLog::eventInformation,
0,
MSG_WATCHDOG_RESTARTING_SERVICE,
1,
(LPCTSTR *) string_array );
// pop out of the loop
stopped_index = number_of_stopped_services;
}
stopped_index++;
}
alive_index++;
}
}
}
service_control_manager.Close();
Sleep( sleep_time );
}
while( 1 );
return( 0 );
}
void set_default_parameters( void )
{
WFCTRACEINIT( TEXT( "set_default_parameters()" ) );
CRegistry registry;
if ( registry.Connect( CRegistry::keyLocalMachine ) != FALSE )
{
if ( registry.Create( TEXT( "SYSTEM\\CurrentControlSet\\Services\\WatchDog\\Parameters" ) != FALSE ) )
{
DWORD default_sleep_time = 60;
if ( registry.SetValue( TEXT( "NumberOfSecondsBetweenChecks" ), default_sleep_time ) == FALSE )
{
LPVOID message_buffer = (LPVOID) NULL;
::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
registry.GetErrorCode(),
MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ),
(LPTSTR) &message_buffer,
0,
NULL );
LPCTSTR string_array[ 2 ];
string_array[ 0 ] = TEXT( "SYSTEM\\CurrentControlSet\\Services\\WatchDog\\Parameters\\NumberOfSecondsBetweenChecks" );
string_array[ 1 ] = (LPCTSTR) message_buffer;
CEventLog event_log( TEXT( "WatchDog" ) );
event_log.Report( CEventLog::eventError,
0,
MSG_CANT_SET_REGISTRY_ENTRY,
2,
(LPCTSTR *) string_array );
if ( message_buffer != NULL )
{
::LocalFree( message_buffer );
}
}
CStringArray strings;
strings.RemoveAll();
strings.Add( TEXT( "" ) );
if ( registry.SetValue( TEXT( "Services" ), strings ) == FALSE )
{
LPVOID message_buffer = (LPVOID) NULL;
::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
registry.GetErrorCode(),
MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ),
(LPTSTR) &message_buffer,
0,
NULL );
LPCTSTR string_array[ 2 ];
string_array[ 0 ] = TEXT( "SYSTEM\\CurrentControlSet\\Services\\WatchDog\\Parameters\\Services" );
string_array[ 1 ] = (LPCTSTR) message_buffer;
CEventLog event_log( TEXT( "WatchDog" ) );
event_log.Report( CEventLog::eventError, 0, MSG_CANT_SET_REGISTRY_ENTRY, 2, (LPCTSTR *) string_array );
if ( message_buffer != NULL )
{
::LocalFree( message_buffer );
}
}
}
else
{
LPVOID message_buffer = (LPVOID) NULL;
::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
registry.GetErrorCode(),
MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ),
(LPTSTR) &message_buffer,
0,
NULL );
LPCTSTR string_array[ 2 ];
string_array[ 0 ] = TEXT( "SYSTEM\\CurrentControlSet\\Services\\WatchDog\\Parameters" );
string_array[ 1 ] = (LPCTSTR) message_buffer;
CEventLog event_log( TEXT( "WatchDog" ) );
event_log.Report( CEventLog::eventError, 0, MSG_CANT_CREATE_REGISTRY_KEY, 2, (LPCTSTR *) string_array );
if ( message_buffer != NULL )
{
::LocalFree( message_buffer );
}
}
}
else
{
LPVOID message_buffer = (LPVOID) NULL;
::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
registry.GetErrorCode(),
MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ),
(LPTSTR) &message_buffer,
0,
NULL );
LPCTSTR string_array[ 2 ];
string_array[ 0 ] = TEXT( "keyLocalMachine" );
string_array[ 1 ] = (LPCTSTR) message_buffer;
CEventLog event_log( TEXT( "WatchDog" ) );
event_log.Report( CEventLog::eventError, 0, MSG_CANT_CONNECT_TO_REGISTRY, 2, (LPCTSTR *) string_array );
if ( message_buffer != NULL )
{
::LocalFree( message_buffer );
}
}
}
API's Used
CServiceControlManager encapsulates the following API's:
- ChangeServiceConfig
- CloseServiceHandle
- ControlService
- CreateService
- DeleteService
- EnumDependentServices
- EnumServicesStatus
- FormatMessage
- GetLastError
- GetServiceDisplayName
- GetServiceKeyName
- LocalFree
- LockServiceDatabase
- OpenSCManager
- OpenService
- QueryServiceConfig
- QueryServiceLockStatus
- Sleep
- StartService
- UnlockServiceDatabase
Copyright, 2000, Samuel R. Blackburn
$Workfile: csvcmgr.cpp $
$Modtime: 1/17/00 9:22a $