CoderSource.net
    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,

  1. In VC++, Create a new Win32 Console Application.
  2. In the type of Application Wizard, choose "An Empty Project".
  3. In the Menu, Project --> Add to Project --> New, Choose a C++ File.
  4. Name the C++ file.
  5. Copy the following source code.
  6. Compile the application.
  7. If you want to install the service, type the following in command prompt.
    "ProgramName.exe install"
    A message appears saying "CodeSourceService Installed Successfully".
  8. 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. 

     
 

More Links from CoderSource.net:

 
Refer to a Friend:

Your Details:

Name:     e-mail:

Friend Details:

Name:    e-mail:    


MENU
Home
MFC 
C++
.Net
WIN32
Programming
Forum
My Articles
Add to Google
Add to My Yahoo!
Welcome to Codersource.Net Login | Register | Faq  

SEARCH
Google
 

NOTES:


Thanks for visiting our CoderSource.net. This site will be improved with more articles. Interested visitors can also submit their articles through the Submit Article link.Your article will also be published after due consideration by the editor. 

© Copyright 2003. All rights on content reserved by CoderSource.net. Contact    About Us