Click here to Skip to main content
15,885,546 members
Articles / Programming Languages / C++

Run an executable as a Windows Service

Rate me:
Please Sign up or sign in to vote.
1.65/5 (5 votes)
8 Jul 2008CPOL 20.9K   18   2
Quick way to run an executable as a Windows Service.

Introduction

This is a reference on running an executable as a Windows Service. In the code, the following ideas are provided along with a reference on running an exe from a service:

  1. Writing a Windows Service
  2. Installing a Windows Service
  3. Uninstalling a Windows Service
  4. Debugging a Windows Service

Using the code

The API call used in the service code is very well documented in MSDN. We need to create a project with the code below to start using it.

C++
#include "windows.h"
#include "tchar.h"

#define _MAX_PATH   260

TCHAR* serviceName = ""; 
TCHAR* exePath = "";
STARTUPINFO si;
PROCESS_INFORMATION pi;
SERVICE_STATUS serviceStatus;
SERVICE_STATUS_HANDLE serviceStatusHandle = 0;
HANDLE stopServiceEvent = 0;
DWORD exitCode = -1;

void StartExe()
{
    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    ZeroMemory( &pi, sizeof(pi) );

    // Start the child process. 
    CreateProcess( NULL, // No module name (use command line). 
        exePath, // Command line. 
        NULL,             // Process handle not inheritable. 
        NULL,             // Thread handle not inheritable. 
        FALSE,            // Set handle inheritance to FALSE. 
        0,                // No creation flags. 
        NULL,             // Use parent's environment block. 
        NULL,             // Use parent's starting directory. 
        &si,              // Pointer to STARTUPINFO structure.
        &pi );            // Pointer to PROCESS_INFORMATION structure.
}

void WINAPI ServiceControlHandler( DWORD controlCode )
{
    switch ( controlCode )
    {
        case SERVICE_CONTROL_INTERROGATE:
            break;

        case SERVICE_CONTROL_SHUTDOWN:
        case SERVICE_CONTROL_STOP:

            TerminateProcess(pi.hProcess, 
               GetExitCodeProcess(pi.hProcess,&exitCode));

            serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
            SetServiceStatus( serviceStatusHandle, &serviceStatus );

            SetEvent( stopServiceEvent );
            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( serviceName, 
                                          ServiceControlHandler );

    if ( serviceStatusHandle )
    {
        // service is starting
        serviceStatus.dwCurrentState = SERVICE_START_PENDING;
        SetServiceStatus( serviceStatusHandle, &serviceStatus );

        // do initialisation here
        stopServiceEvent = CreateEvent( 0, FALSE, FALSE, 0 );

        // running
        serviceStatus.dwControlsAccepted |= 
               (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
        serviceStatus.dwCurrentState = SERVICE_RUNNING;
        SetServiceStatus( serviceStatusHandle, &serviceStatus );

        StartExe();
        WaitForSingleObject( stopServiceEvent, INFINITE ); 

        // service was stopped
        serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
        SetServiceStatus( serviceStatusHandle, &serviceStatus );

        // do cleanup here
        CloseHandle( stopServiceEvent );
        stopServiceEvent = 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[] =
    {
        { serviceName, ServiceMain },
        { 0, 0 }
    };

    StartServiceCtrlDispatcher( serviceTable );
}

void InstallService()
{
    SC_HANDLE serviceControlManager = OpenSCManager( 0, 0, SC_MANAGER_CREATE_SERVICE );

    if ( serviceControlManager )
    {
        TCHAR path[ _MAX_PATH + 1 ];
        if ( GetModuleFileName( 0, path, sizeof(path)/sizeof(path[0]) ) > 0 )
        {
            SC_HANDLE service = CreateService( serviceControlManager,
                            serviceName, serviceName,
                            SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
                            SERVICE_AUTO_START, SERVICE_ERROR_IGNORE, path,
                            0, 0, 0, 0, 0 );
            if ( service )
                CloseServiceHandle( service );
        }

        CloseServiceHandle( serviceControlManager );
    }
}

void UninstallService()
{
    SC_HANDLE serviceControlManager = OpenSCManager( 0, 0, SC_MANAGER_CONNECT );

    if ( serviceControlManager )
    {
        SC_HANDLE service = OpenService( serviceControlManager,
            serviceName, SERVICE_QUERY_STATUS | DELETE );
        if ( service )
        {
            SERVICE_STATUS serviceStatus;
            if ( QueryServiceStatus( service, &serviceStatus ) )
            {
                if ( serviceStatus.dwCurrentState == SERVICE_STOPPED )
                    DeleteService( service );
            }

            CloseServiceHandle( service );
        }

        CloseServiceHandle( serviceControlManager );
    }
}

int _tmain( int argc, TCHAR* argv[] )
{

    if ( argc > 2 && lstrcmpi( argv[1], TEXT("install") ) == 0 )
    {
        serviceName = argv[2];
        InstallService();
    }
    else if ( argc > 1 && lstrcmpi( argv[1], TEXT("uninstall") ) == 0 )
    {
        UninstallService();
    }
    else if( argc > 2 && lstrcmpi( argv[1], TEXT("start") ) == 0 )
    {
        exePath = argv[2];
        RunService();
    }
    else
    {
        //show error message
    }

    return 0;
}

For debugging the code, write the below code at the beginning of the _tmain function:

ASM
__asm
{
  int 3
}

This will create a break while running the service.

History

Do contact me for any updates or queries at somenshaw at gmail.com.

License

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


Written By
India India
somenshaw@gmail.com

Comments and Discussions

 
GeneralUse of terminate process Pin
JudyL_MD10-Jul-08 9:49
JudyL_MD10-Jul-08 9:49 
GeneralRe: Use of terminate process Pin
Somen Shaw14-Jul-08 22:23
Somen Shaw14-Jul-08 22:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.