You are on page 1of 4

How to write a Windows Service by Jarmo Muukka

Home
MultiDesktop Manager
Programming
Windows Service
CV
Technology
News
Mutex Oy
About Me

What is a Windows Service?

A service is a process which does not require user to log on. Service starts when system boots up, it is started
from Services applet or when other application starts it.

Service can have command line or graphical user interface, but I don't recommend to use it. If you need a user
interface to the service, write a separate application and choose which communication technique to use. I suggest
sockets because it allows you to operate service from anywhere in the internet. If you choose e.g. file mapping,
you are restricted to run GUI in the same computer where the service is running. If you choose e.g. named pipes,
you are restricted to run GUI in some machine in local area network (LAN).

By the way, you can write service and GUI into a single application. You just need a way to decide which code to
execute when process is started. Process can make the decision itself by checking SIDs of the process.

Services are supported by Windows NT/2000/XP/2003/Vista/2008. Windows 95 series does not support services.

Security

Usually a service is executed in the account of Local System. Service can execute code which requires e.g.
SE_TCB_NAME privilege like LogonUser. Service cannot use operating system features that require user to logon
such as HKEY_CURRENT_USER registry key and some local area network functions.

Service can be allowed to interact with desktop when Local System account is chosen.

Service can be executed in the specified user's account.

How to write a service?

A service process can contain one or multiple services. Service is usually a console application.

Sample Service

I have written a very short service called "Beeper Service". Its only task is to beep every 5 seconds. Because it
does only this, this sample explains only "how to write a service". Nothing else. Next I'll describe its parts.

This example is in C which is compiled with C++ compiler.

Running a service

First, you setup a table of services (SERVICE_TABLE_ENTRY) and call StartServiceCtrlDispatcher which does not
return until all services in the process have terminated. SERVICE_TABLE_ENTRY requires a name of the service
and a function for the service. Every service requires a separate function. You can give any valid name for the
function. For SERVICE_WIN32_OWN_PROCESS it's usually ServiceMain. Here's the code:

void RunService()
{
SERVICE_TABLE_ENTRY serviceTable[] =
{
{ serviceName, ServiceMain },
{ 0, 0 }
};

StartServiceCtrlDispatcher( serviceTable );
}

ServiceMain
Service control manager requests a main thread (that is the thread which is executing StartServiceCtrlDispatcher)
to create a thread for the service. So, in service process there are always at least two threads running. A main
thread and one thread for each running service. Of course, a service may create more threads when needed.

Service needs SERVICE_STATUS structure. It is needed when service tells its status to service control manager. I
think that the best place to initialise SERVICE_STATUS is in the beginning of ServiceMain.

After that ServiceMain should call the RegisterServiceCtrlHandler function to specify a ServiceControlHandler
function to handle control requests. Each service require a separate control handler function. You can give any
valid name for the function.

Next, ServiceMain have to call SetServiceStatus function to send status information to the service control
manager. Usually service tells that it's starting with SERVICE_START_PENDING. Then it initialises every needed
things. When this is done, it accepts control requests SERVICE_ACCEPT_STOP and SERVICE_ACCEPT_SHUTDOWN
and sets its current state to SERVICE_RUNNING and tells all this to service control manager with call to
SetServiceStatus.

Now service control manager knows that service is up and running. Service should be running until stopped or
paused.

How to know when to stop the service?

For this you need a way to control stopping. Service control manager calls ServiceControlHandler with control
code SERVICE_CONTROL_STOP when it is requested to stop service.

I have always done it with event with name stopServiceEvent. I usually wait events with WaitForMultipleObjects.
In this example I use WaitForSingleObject. When stopServiceEvent is signaled, the service is stopped.

Now, the service is stopping, so tell current status SERVICE_STOP_PENDING to service control manager. Do
cleanup and finally stop accepting control requests SERVICE_ACCEPT_STOP and SERVICE_ACCEPT_SHUTDOWN
and set service's current state to SERVICE_STOPPED and tell this to service control manager with call to
SetServiceStatus. Service is now terminated.

Here is the code:

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 );

do
{
Beep( 1000, 100 );
}
while ( WaitForSingleObject( stopServiceEvent, 5000 ) == WAIT_TIMEOUT );

// 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 );
}
}

ServiceControlHandler

Service control manager calls this function in the context of a main thread of service process when it or some
other wants to control service.

If control code is SERVICE_CONTROL_STOP, service is requested to stop. First, report status


SERVICE_STOP_PENDING to service control manager with SetServiceStatus. Then, make service to stop. It's
easiest with SetEvent.

For SERVICE_CONTROL_SHUTDOWN you can do the same things as for SERVICE_CONTROL_STOP.

For every other control codes it's wise to report service's current status. Here's the code:

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( 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 );


}

Debugging a service

Debugging a service is easy, if you know how to do it.

Running service program from development tool or from console does not work. StartServiceCtrlDispatcher fails
because service control manager is not waiting for calls. If you start service as a real service, you cannot debug it.

My way to debug a service consists of following things:


examine the execution context of the process
set console control handler
create and run service in separate thread (simulate service)

By examining the execution context, process can determine is it running as a service. If not, console mode is used
and thread is created for service. In console mode Ctrl-C and other handlers are set and the code that stops a
service is the same as in the real service.

You cannot debug everything in this way because security context is not same as when process is executed as a
service. For example LogonUser will fail in console mode while it works in service mode.

I haven't written a sample of this yet. I have it in my C++ class library. I'll try to find the time to add it to this
sample.

Installing a service

Before you can start service, you have to install it. First, open service control manager on target computer with
OpenSCManager. Then create service with CreateService. You have to decide a service name and a display name
you use. Service name is the name you use to reference to your service.

Uninstalling a service

See the source code.

Source code

Source code is in here.

What's missing?

I know more things about services than I wrote in here. If you didn't understand something or want to learn more,
please ask by sending e-mail to jarmo@muukka.net.

References

When I was writing this page I used search engine to find articles about services and to my surprise I found one
sample by CommSoft which is called "BeeperService".

Copyright © Jarmo Muukka 2001-2015. All rights reserved.

You might also like