Advertisment

Creating Windows Services Using C#

author-image
PCQ Bureau
New Update

We use services on computers, whether we know it or not. Look at the

anti-virus icon, printer status monitor and Windows firewall landing in the

system tray-many of these are services. A 'service' is a program, which

works essentially in the background and may or may not interact with the user.

Some of the services monitor the system security; some monitor hardware devices;

others (called network services) wait for connections from other machines and

serve their requests.

Advertisment

Network services are set up on a particular IP address and port number. No

two services can be set up on the same IP address and port combination. The

combination of IP address and port number is termed a 'socket'. A service

can also use one of many protocols (namely TCP/IP, UDP, etc) to communicate. In

this article, we shall be talking about TCP sockets only.

Direct Hit!
Applies To:

.NET programmers



USP: Explains creating services for Win XP/Server 2003 using
C#



Primary Link: www.msdn.microsoft.com/net


Google Keywords: .NET SDK, C#

How services work



Services do not require the user to explicitly start the service each time the
computer boots, nor do they wait for the user to kill them when the system shuts

down. They are managed by the OS. The list of services available on a system can

be viewed from the Microsoft Services Management Console Administrative

Tools>Services.

Advertisment

A program has to fulfill two requirements to qualify as a service. The first

job is the creation of a local registry entry for itself at the location HKLM\

SYSTEM\CurrentControlSet\Services. It has to create a sub-key with the name of

service, full path the executable ('ImagePath' sub-key), an optional brief

description and a start-up mode ('start' sub-key, values 2, 3 and 4 signify

Automatic, Manual and Disabled respectively).

In our example, once a client connects to

our service, it is sent a random number before the connection is closed

Coding a service



Note that .NET provides the System.ServiceProcess namespace, which has a base
class 'ServiceBase'. Any service built in .NET needs to extend this base

class and override a few methods that start, stop and manage the service

instance.

Advertisment

Above all, the 'Main' method of this extended class should invoke the

static Run method of ServiceBase with an instance of the service class (Similar

to the Application.Run method for Windows forms). 

This article demonstrates the coding, installation and testing of a random

number server using C# language. The source code for the same can be accessed at

forums.pcquest.com under the Developer section. 

RandomServer class 



Our random server is implemented in a file named RandomServer.cs. It contains
RandomServer class, which extends ServiceBase. The constructor sets the AutoLog

property True, which permits the server to enjoy automatic logging of events

(without requiring us to code the EventLog control ourselves). The name of the

server service is set up using the ServiceName property. The CanPauseAndContinue

property tells Windows that the server can be temporarily requested to remain

idle (but not stopped), in order to relax the system from overload or permit

some maintenance work.

Advertisment

The RandomServer overrides the methods OnStart, OnStop, OnShutDown, OnPause

and OnContinue. These overridden methods provide the link between the code we

create and the Windows service management architecture. There is one more method

called OnCustomCommand, which permits handling of custom signals using command

numbers. Since we do not plan anything beyond the standard actions described

above, this method is simply ignored.

Our RandomNumberServer service is registered in the Windows registry and we can control it from the Services console

Our server logic is implemented in a separate thread called serverThread,

which runs the method Serve(). Both serverThread and Serve are our own methods.

The Serve() method creates a TCP server socket using the TcpListener class on

port number 4444 of the loopback adapter (IP 127.0.0.1). The server starts

listening, enters a while loop, accepts connections as they arrive, sends out a

random number, logs the IP address and port number of the client and closes the

socket.

Advertisment

The server itself is started as a separate thread, since the OnStart method

has to return within 30 secs. Otherwise, Windows assumes that the service failed

to start. Pause operation is implemented using a Boolean variable serverPaused.

If the value in this variable is True, the server sleeps for 10 ms at a time

till this is set to False again by calling the OnContinue method.

//RandomServer.cs



using System.Threading;


using System.Net;


using System.Net.Sockets;


using System.ServiceProcess;


using System;



public class RandomServer : ServiceBase



{


TcpListener server = null;


Thread serverThread = null;


bool serverPaused = false;


public RandomServer() {


AutoLog=CanPauseAndContinue = CanShutdown = true;


this.ServiceName = "RandomNumberServer";


}


protected override void OnStart(string<> arg) {


serverThread = new Thread(new ThreadStart(Serve));


serverThread.Start();


}


protected override void OnStop() {server.Stop(); server = null;}


protected override void OnShutdown() {OnStop();}


protected override void OnPause() {serverPaused = true;}


protected override void OnContinue() {serverPaused = false;}


protected override void OnCustomCommand(int cmd) {}


private void Serve() {


server = new TcpListener(IPAddress.Loopback, 4444);


server.Start();


System.Random r = new System.Random();


while(server != null) {


try {


if(serverPaused) {Thread.Sleep(10); continue;}


Socket s = server.AcceptSocket();


EventLog.WriteEntry("Accepted "+((IPEndPoint)s.RemoteEndPoint));


string ran = ""+r.NextDouble();


byte<> b = System.Text.Encoding.ASCII.GetBytes(ran);


s.Send(b, b.Length, 0);


EventLog.WriteEntry("Served "+((IPEndPoint)s.RemoteEndPoint));


s.Close();


}


catch(System.Exception ex) {


System.Console.WriteLine(ex.Message);


}


}


}


public static void Main() {


erviceBase.Run(new RandomServer());


}


}







































Advertisment
The service automatically logs events to the Windows Event log, captured here using an event listener

Installer for RandomServer



RandomServer cannot run as a normal program. It needs to be installed with
proper registry entries so that Windows can detect and run the program. The .NET

framework provides ServiceProcessInstaller and ServiceInstaller classes within

System.ServiceProcess assembly to do this. The type of service account is set in

ServiceProcessInstaller.

The enumeration called Service-Account contains possible types (LocalService,

NetworkService, LocalSystem or User).

Advertisment

Then, the name of service, a brief description and startup type (defined in

the enumeration ServiceStartMode) are set.

The start mode options can be Automatic, Manual or Disabled. The properties

filled up here are reflected in the registry entries. The installation logic is

collected in a file called RandomServerInstaller.cs.

//RandomServerInstaller.cs



using System.ServiceProcess;





public class RandomServerInstaller : System.Configuration.Install.Installer


{


public RandomServerInstaller() {


ServiceProcessInstaller spi = new ServiceProcessInstaller();


ServiceInstaller si = new ServiceInstaller();


spi.Account = ServiceAccount.NetworkService;


si.ServiceName = "RandomNumberServer";


si.Description = "Random Number Generation Service on port No. 4444";


si.StartType = ServiceStartMode.Automatic;


Installers.AddRange( new System.Configuration.Install.Installer<> {spi, si});


}


}












Compile and run



We can manage the installation and running of this service using the Visual
Studio 2005 IDE itself. Otherwise, if you have just the .NET SDK installed, you

can use the 'csc' command to compile our C# service and manage installation

and removal using the 'installutil'



command.

To minimize the size of coding, creation of a separate client is avoided and

telnet client is used. Random number can be obtained from our server by issuing

the command telnet localhost 4444 either in the command prompt or through

Start->Run. For testing the service from other hosts on a network, localhost

in the command should be replaced by appropriate host name or IP address.

We can take a look at the logs generated by our service from the Windows

Event Viewer (you can open this by going to the Administrative Tools).

V Nagaradjane

Advertisment