Creating a dummy windows service in C

13 Jan 2015

I have a load balanced web application that is hosted in a managed datacenter in another state. Because the data center is managed by a third party I am not allowed to have direct access to the load balancer for SLA purposes but I still need an ability to pull a server from the load balancer pool at will. As a work-around I want to create a Windows service that the load balancer can monitor and as long as the service is running the server should remain in the pool, if service is stopped the load balancer should pull that server from the pool and route users to a server still considered operational. The trick to this is, the service essentially does nothing but run and is something I can manually start and stop at my own discretion.

Having never created a Windows service I had to do a quite a bit of research to determine the proper way to get this going. In the end I decided on using C as the language for the service, using this article as my main source of information about accessing the Windows API. All this service does is start, then loop a sleep pause every 5 minutes and that’s it, very simple and serves the purpose.

#include <windows.h>
#include <stdio.h>

#define LOGFILE "C:\\Temp\\sleepstatus.txt"

SERVICE_STATUS ServiceStatus; 
SERVICE_STATUS_HANDLE hStatus; 
 
void  ServiceMain(int argc, char** argv); 
void  ControlHandler(DWORD request); 
int InitService();

int WriteToLog(char* str)
{
	FILE* log;
	log = fopen(LOGFILE, "a+");
	if (log == NULL)
		return -1;
	fprintf(log, "%s\n", str);
	fclose(log);
	return 0;
}

void main() 
{ 
    SERVICE_TABLE_ENTRY ServiceTable[2];
    ServiceTable[0].lpServiceName = "SleepService";
    ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;

    ServiceTable[1].lpServiceName = NULL;
    ServiceTable[1].lpServiceProc = NULL;
    // Start the control dispatcher thread for our service
    StartServiceCtrlDispatcher(ServiceTable);  
}

void ServiceMain(int argc, char** argv) 
{ 
    int error; 
 
    ServiceStatus.dwServiceType        = SERVICE_WIN32; 
    ServiceStatus.dwCurrentState       = SERVICE_START_PENDING; 
    ServiceStatus.dwControlsAccepted   = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
    ServiceStatus.dwWin32ExitCode      = 0; 
    ServiceStatus.dwServiceSpecificExitCode = 0; 
    ServiceStatus.dwCheckPoint         = 0; 
    ServiceStatus.dwWaitHint           = 0; 
 
    hStatus = RegisterServiceCtrlHandler(
		"SleepService", 
		(LPHANDLER_FUNCTION)ControlHandler); 
    if (hStatus == (SERVICE_STATUS_HANDLE)0) 
    { 
        // Registering Control Handler failed
        return; 
    }  
    // Initialize Service 
    error = InitService(); 
    if (error) 
    {
		// Initialization failed
        ServiceStatus.dwCurrentState       = SERVICE_STOPPED; 
        ServiceStatus.dwWin32ExitCode      = -1; 
        SetServiceStatus(hStatus, &ServiceStatus); 
        return; 
    } 
    // We report the running status to SCM. 
    ServiceStatus.dwCurrentState = SERVICE_RUNNING; 
    SetServiceStatus (hStatus, &ServiceStatus);
 
    // The worker loop of a service
    while (ServiceStatus.dwCurrentState == SERVICE_RUNNING)
	{
		int result;
    
	    /* Do nothing but loop once every 5 minutes */
		while(1)
		{
			sleep(300);			
		}
		
	}
    return; 
}
 
// Service initialization
int InitService() 
{ 
    int result;
    result = WriteToLog("Monitoring started.");
    return(result); 
} 


// Control handler function
void ControlHandler(DWORD request) 
{ 
    switch(request) 
    { 
        case SERVICE_CONTROL_STOP: 
             WriteToLog("Monitoring stopped.");

            ServiceStatus.dwWin32ExitCode = 0; 
            ServiceStatus.dwCurrentState  = SERVICE_STOPPED; 
            SetServiceStatus (hStatus, &ServiceStatus);
            return; 
 
        case SERVICE_CONTROL_SHUTDOWN: 
            WriteToLog("Monitoring stopped.");

            ServiceStatus.dwWin32ExitCode = 0; 
            ServiceStatus.dwCurrentState  = SERVICE_STOPPED; 
            SetServiceStatus (hStatus, &ServiceStatus);
            return; 
        
        default:
            break;
    }  
    
    // Report current status
    SetServiceStatus (hStatus,  &ServiceStatus);
 
    return; 
} 	

Now that the C file has been created, I compile this into an EXE using MinGW:

C:\MinGW\bin\gcc sleepservice.c -o sleepservice.exe

At this point I create the C:\Temp\ folder on the server in question and copy the EXE to the newly created directory. To create the service on the server, open a command prompt and enter the following.

C:\sc create SleepService binPath= "C:\Temp\sleepservice.exe" DisplayName= "SleepService " start= auto
[SC] CreateService SUCCESS

At this point you are done, you should be able to see your newly created Windows service and can start it and stop it at will. When started you should see a process called sleepservice.exe running in the Windows Task Manager.

New Windows Service