Writing a Service is nothing but a piece of cake walk, lest the knowledge of C++ (AND/OR)Win32. The
only problem about NT Services is understanding the basic service architecture and going forward.
This article assumes that the reader has a basic knowledge of C++ and/or Win32 and worked on VC++
IDE.
A NT Service is a program that conforms to the rules of an NT Service Control Manager or
SCM. The SCM maintains a database of NT Services and controls them.
A Service needs two important functions namely a Service Main
function and a Service Control Handler function.
There is another article in this site, dealing with Enumerating
the NT Services installed in a Windows NT machine.
ServiceMain:
This function does two important tasks.
1. Initialize the service variables.
2. Register the Service Control handler function.
Remember this function is not the same as our main function, which is the entry point of
a C/C++ program.
Service Control Handler:
Whenever there is a change in the status of the service, this
function gets called with the appropriate control code. This
is also, where we can control the program's status.
The following program is a complete source code of a Win32
NT Service program.
To run this program,
- In VC++, Create a new Win32 Console Application.
- In the type of Application Wizard, choose "An Empty
Project".
- In the Menu, Project --> Add to Project --> New,
Choose a C++ File.
- Name the C++ file.
- Copy the following source code.
- Compile the application.
- If you want to install the service, type the following
in command prompt.
"ProgramName.exe install"
A message appears saying "CodeSourceService Installed
Successfully".
- If you want to remove it, type the following in command
prompt. "ProgramName.exe remove"
#include <stdio.h>
#include <windows.h>
#include <tchar.h>
TCHAR* gszServiceName = TEXT("CoderSourceService");
SERVICE_STATUS serviceStatus;
SERVICE_STATUS_HANDLE serviceStatusHandle = 0;
HANDLE ServiceControlEvent = 0;
FILE *g_Handle; //Global File Handle
char gszFilePath[] = "C:\\SourceCoderServiceOutput.txt";
void WINAPI ServiceControlHandler( DWORD controlCode )
{
switch ( controlCode )
{
case SERVICE_CONTROL_INTERROGATE:
break;
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus( serviceStatusHandle, &serviceStatus );
SetEvent( ServiceControlEvent );
return;
case SERVICE_CONTROL_PAUSE:
break;
case SERVICE_CONTROL_CONTINUE:
break;
default:
if ( controlCode >= 128 && controlCode <= 255 )
// user defined control code
break;
else
// unrecognised control code
break;
}
SetServiceStatus( serviceStatusHandle, &serviceStatus );
}
void WINAPI ServiceMain( DWORD /*argc*/, TCHAR* /*argv*/[] )
{
// initialise service status
serviceStatus.dwServiceType = SERVICE_WIN32;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwWin32ExitCode = NO_ERROR;
serviceStatus.dwServiceSpecificExitCode = NO_ERROR;
serviceStatus.dwCheckPoint = 0;
serviceStatus.dwWaitHint = 0;
serviceStatusHandle = RegisterServiceCtrlHandler( gszServiceName,
ServiceControlHandler );
if ( serviceStatusHandle )
{
// service is starting
serviceStatus.dwCurrentState = SERVICE_START_PENDING;
SetServiceStatus( serviceStatusHandle, &serviceStatus );
// Create the Controlling Event here
ServiceControlEvent = CreateEvent( 0, FALSE, FALSE, 0 );
// Service running
serviceStatus.dwControlsAccepted |= (SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_SHUTDOWN);
serviceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus( serviceStatusHandle, &serviceStatus );
fprintf(g_Handle,"CoderSource Service Created this file\n");
fflush(g_Handle);
WaitForSingleObject( ServiceControlEvent, INFINITE );
// service was stopped
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus( serviceStatusHandle, &serviceStatus );
// do cleanup here
fclose(g_Handle);
CloseHandle( ServiceControlEvent );
ServiceControlEvent = 0;
// service is now stopped
serviceStatus.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_SHUTDOWN);
serviceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus( serviceStatusHandle, &serviceStatus );
}
}
void RunService()
{
SERVICE_TABLE_ENTRY serviceTable[] =
{
{ gszServiceName, ServiceMain },
{ 0, 0 }
};
StartServiceCtrlDispatcher( serviceTable );
}
void InstallService()
{
SC_HANDLE serviceControlManager = OpenSCManager( 0, 0,
SC_MANAGER_CREATE_SERVICE );
if ( serviceControlManager )
{
char path[ _MAX_PATH + 1 ];
if ( GetModuleFileName( 0, path, sizeof(path)/sizeof(path[0]) ) > 0 )
{
SC_HANDLE service = CreateService( serviceControlManager,
gszServiceName, gszServiceName,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_IGNORE, path,
0, 0, 0, 0, 0 );
if ( service )
{
CloseServiceHandle( service );
printf("CoderSourceService Installed Successfully\n");
}
else
{
if(GetLastError() == ERROR_SERVICE_EXISTS)
printf("CoderSourceService Already Exists.\n");
else
printf("CoderSourceService Was not Installed
Successfully. Error Code %d\n", GetLastError());
}
}
CloseServiceHandle( serviceControlManager );
}
}
void UninstallService()
{
SC_HANDLE serviceControlManager = OpenSCManager( 0, 0,
SC_MANAGER_CONNECT );
if ( serviceControlManager )
{
SC_HANDLE service = OpenService( serviceControlManager,
gszServiceName, SERVICE_QUERY_STATUS | DELETE );
if ( service )
{
SERVICE_STATUS serviceStatus;
if ( QueryServiceStatus( service, &serviceStatus ) )
{
if ( serviceStatus.dwCurrentState == SERVICE_STOPPED )
{
if(DeleteService( service ))
printf("CoderSourceService Removed
Successfully\n");
else
{
DWORD dwError;
dwError = GetLastError();
if(dwError == ERROR_ACCESS_DENIED)
printf("Access Denied While trying to Remove
CoderSourceService \n");
else if(dwError == ERROR_INVALID_HANDLE)
printf("Handle invalid while trying to Remove
CoderSourceService \n");
else if(dwError == ERROR_SERVICE_MARKED_FOR_DELETE)
printf("CoderSourceService already marked
for deletion\n");
}
}
else
{
printf("CoderSourceService is still Running.\n");
}
}
CloseServiceHandle( service );
}
CloseServiceHandle( serviceControlManager );
}
}
int _tmain( int argc, TCHAR* argv[] )
{
if ( argc > 1 && lstrcmpi( argv[1], TEXT("install") ) == 0 )
{
InstallService();
}
else if ( argc > 1 && lstrcmpi( argv[1], TEXT("remove") ) == 0 )
{
UninstallService();
}
else
{
if((g_Handle = fopen(gszFilePath, "w")) != NULL)
RunService();
else
exit(1);
}
return 0;
}
This Service Creates a Temporary output file "C:\\SourceCoderServiceOutput.txt".It
also writes a one line output and waits for the Service
commands. Among this seemingly bulky set of code, you might
also have to learn about two more functions. CreateService
- This function creates the NT service and installs it in the
SCM database. DeleteService - This function is the one
which removes the NT Service from the NT SCM database. Both
these functions are explained with regard to NT Service to
some extent. You can dig out for some more data about NT
Service (s) from MSDN
or from some books.