BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Windows Programming
.NET 1.1+

Creating a Windows Service

Windows services are background processes that usually have no direct interaction with the user interface. This article explains how to create a windows service with an example that monitors the file system for changes using a FileSystemWatcher object.

Creating the Project

Windows Service IconTo begin, we need to create a project in Visual Studio using the Windows Service template. Start Visual Studio and specify that you wish to create a new project. Select this Windows Server option and name the project "FileMonitorService".

Once the new project is created, you will see that it contains a class named "Service1". This contains the basic functionality of the service. If you double-click the file you will see a design window. In a similar manner to when creating Windows forms applications, you can drag components from the toolbox into this designer and use them with your service.

To view the code in the Service1 class click the "click here to switch to code view" link on the designer's surface or right-click the file in the Solution Explorer and choose "View Code". You will see that the class file contains some methods. The code will vary according to the version of Visual Studio being used. However, it will include the following members:

  • Constructor. A constructor will be defined and will call to InitializeComponent. This is required to enable components added using the designer.
  • OnStart. This is called when the service is started, either manually via the MMC or automatically when the operating system is loaded.
  • OnStop. This method is called when the service is stopped.

Note that the class inherits from ServiceBase, which contains the methods required to correctly operate a Windows service.

Service1 is not a good name. Rename the class file from "Service1.cs" to "Monitor.cs" and change the class definition to match the following. NB: If the current definition includes the "partial" keyword, leave this in place and just change the name of the class.

public class Monitor : ServiceBase

Depending upon the version of Visual Studio that you are using, the base class may have been fully qualified before we changed it. So that the service still compiles, ensure the following using directive is present:

using System.ServiceProcess;

The service will still not compile at this point, as the name of the constructor is incorrect. Modify the declaration of the constructor as follows and then compile the service.

public Monitor()

NB: You may find that the code fails to compile because there is a reference to the Service1 class in the Main method. If so, simply change the name from "Service1" to "Monitor" and try compiling again.

ServicesToRun = new ServiceBase[] { new Monitor() };

Initialising the Service

Any initialisation that is required would usually be added in the constructor, following the call to InitializeComponent. In our example service, we need to check that an event source exists for logging events. As the service may execute under an account with limited privileges, it may not be possible to create the event source within the service. Additionally, on some operating systems it is not possible to create an event source unless the program is running as an administrator.

A typical solution is to create a separate program that creates the event source and run this as an administrator before the service is used. This is explained in the article, "Logging Messages in Event Logs". If you do not wish to read that article now, simply create a new console application, add the following code to the Main method and run the program once.

string eventSource = "File Monitor Service";
System.Diagnostics.EventLog.CreateEventSource(eventSource, "Application");

NB: If you are using Microsoft Vista or a more recent operating system, you will need to compile the program and run it as an administrator.

Logging Events

Each time an event happens within the service, we will log a message in the event log. This logging will occur when the service is started, stopped, paused or resumed and when the FileSystemWatcher object captures a file change event. To simplify the code, we will create one method to logs events. First, ensure that the following using directive appears at the top of the code in Monitor.cs:

using System.Diagnostics;

Now add the following method to the Monitor class. This accepts a message and adds it to the event log using the event source created earlier.

void LogEvent(string message)
{
    string eventSource = "File Monitor Service";
    EventLog.WriteEntry(eventSource, message);
}

Adding the OnStart Method

When a service is started, the OnStart method is called. This is where we will initialise a FileSystemWatcher object. The code for this has been explained in the article, "Detecting File Changes with FileSystemWatcher". As the FileSystemWatcher object must exist beyond the scope of the OnStart method, we will begin by declaring it as a class-level variable. Add the following declaration within the class but outside of any method definition:

private FileSystemWatcher _watcher;

You may also need to add an extra using directive to the code to provide access to the FileSystemWatcher class:

using System.IO;

We can now initialise the FileSystemWatcher in the OnStart method. On completion of this step, we will also log an event. Modify the OnStart method as follows to create the object, attach its events and begin monitoring.

protected override void OnStart(string[] args)
{
    _watcher = new FileSystemWatcher();
    _watcher.Path = @"c:\watched";

    _watcher.Changed += new FileSystemEventHandler(LogFileSystemChanges);
    _watcher.Created += new FileSystemEventHandler(LogFileSystemChanges);
    _watcher.Deleted += new FileSystemEventHandler(LogFileSystemChanges);
    _watcher.Renamed += new RenamedEventHandler(LogFileSystemRenaming);
    _watcher.Error += new ErrorEventHandler(LogBufferError);
    _watcher.EnableRaisingEvents = true;

    LogEvent("Monitoring Started");
}

NB: Note that the Path property of the _watcher object is set to "c:\watched". This is the folder that will be monitored. If you wish to use this folder, create it now. If not, change the Path to that of an alternative folder to monitor.

10 September 2008