Introduction

In this article we will see how to create a Windows service through Visual Basic .NET. We will analyze the procedure to install the created service, both in the test-related context and in production. At the end of the article, we will develop a very rudimentary service which performs a file versioning on a certain directory. The project may be expanded and/or modified according to the real needs of the reader, being a basic example on which develop additional solutions.

What is a service?

The term 'service' means, under Windows, a program (or, more generally, any executable process) whose performance tends to remain transparent to the user and independent from external direct interaction. Typically, the service is used to add functionality to the context on which is executed. In the "service" definition falls, to make an example, any protection module from antivirus real-time programs. Services are programs written specifically to perform repetitive tasks to which the user's attention may be limited, or even absent.

Windows obviously has a number of standard services, which manages various basic functionality, but does not prevent to enrich the array of these processes with additional modules useful for the user. What we will achieve in this article is precisely to create an always running task which will perform a precise work.

Accessing services list

To access and managing the installed services list, we can count on different methods, more or less standardized between OS versions. The reader will surely know the "Services" snap-in from Control Panel (which is also reachable using "Manage computer", being services.msc a snap-in of the Microsoft Management Console utility) Another possibility comes from the DOS command NET START and - for the command line lovers - from the sc.exe program, which allows a non-graphical interaction with our services. 
In those lines we won't analyze further those tools, sending the reader to their respective manuals.

Create a service with Visual Studio

Preliminary operations

As mentioned in the introduction, we will create a simple service that will have the task of monitoring a particular folder, saving a copy of the files in that folder when they change.

Open Visual Studio and - creating a new Visual Basic - we select the Classic Desktop template » Windows Service. In our example, the project name will be VersioningSvc.



Visual Studio will prepare the solution using the selected template, creating a service module named Service1.vb. We want assigning a different name to our service, and - since this string is referenced in several places in the code - we'll use the utility Quick change (Ctrl + H), as shown in the following picture:



Let's rename the Service1.vb file as VersioningSvc.vb.
By entering then into the source of the latter, we will see how two events have been set up, or OnStart and OnStop. Those are, quite simply, the events that will manage the start-up and stop phases of the service itself.

Protected Overrides Sub OnStart(ByVal args() As String)
    ' Add code here to start your service. This method should set things
    ' in motion so your service can do its work.
End Sub
 
Protected Overrides Sub OnStop()
    ' Add code here to perform any tear-down necessary to stop your service.
End Sub

OnStart() became our program entry-point. We will develop our versioning service starting from this event.

Implementing application logic

Beyond what has been seen, there are no particular differences between the development of any desktop application and a service. In this second case, we'll probably be more oriented to automation (while other types of programs will be based in part on the interaction of user), but the tools available to us are the same as always. To develop our versioning service, we will rely on the FileSystemWatcher class.

FileSystemWatcher is a class that provides monitoring tools for directory and files contained in them. Through some events, it lets you control the type of operations performed on documents, such as creating, editing, deleting, etc. In our case, given a certain folder, we want to monitor only the changes that take place on the files. The logic that we will adopt is simple: from a certain folder, when a file contained in it is changed, we will make a copy of the same file in a dedicated subdirectory, adding the timestamp of the event to the file name. Regarind the FileSystemWatcher that we'll create, we will thus manage the Changes event only.

Our class (and, in fact, the whole of the service code) becomes thus the following:

Imports System.IO
 
Public Class VersioningSvc
    Const wPath As String = "C:\temp\"
    Const wExte As String = ".txt"
 
    Dim WithEvents fsw As FileSystemWatcher
 
    Protected Overrides Sub OnStart(ByVal args() As String)
        fsw = New FileSystemWatcher(wPath, "*" & wExte)
        fsw.NotifyFilter = NotifyFilters.LastWrite
        fsw.EnableRaisingEvents = True
    End Sub
 
    Protected Overrides Sub OnStop()
        MyBase.OnStop()
    End Sub
 
    Private Sub fsw_Changed(sender As Object, e As FileSystemEventArgs) Handles fsw.Changed
        Try
            Dim fI As New FileInfo(e.FullPath)
            If Not (fI.Exists) Then Exit Sub
 
            Dim vPath As String = wPath & "\.versions\"
 
            Dim fO As New FileInfo(vPath & e.Name)
            If Not (fO.Exists) Then
                Dim dI As New DirectoryInfo(vPath)
                If Not (dI.Exists) Then dI.Create()
            End If
 
            fI.CopyTo(vPath & fI.Name & "_" & Now.ToString("yyyyMMdd_HHmmss"))
        Catch ex As Exception
        End Try
    End Sub
End Class

To summarize the operation, we note how, in the class opening, the path to be monitored and the file type to look for are defined. During OnStart event, we will initialize the FileSystemWatcher object to make it monitor file changes, using as criteria the last write time of the files themselves. Lastly, setting the EnableRaisingEvent to True will make the monitoring to start.

As a result, every time a file is modified in the folder in charge, it invokes the Changed method. As you will note, it execute few simple operations and controls. First, it check that the file is really exiseant. If that condition is satisfied, starting from the source path we will create a subdirectory named "\.version\", copying in it our modified file, with a name that will contain the timestamp of the operation.

In this way, the "\.versions\" folder will contain every change that took place into our directory, allowing us to manage a usable chronologic history of our files.

Setup services installers

To insert our service among those managed through the system snap-in, we must add to our solution an installer, through which we will be able to install our service in Windows. Right-click on the Design window of the service class, then select the menù option «Add Installer»



Two objects will be created, i.e. ServiceInstaller1 and ServiceProcessInstaller1. Those object will allow us to define some important detail informations and setting for our service, such as the name to show into the services list, the service description, but also the startup type and the user under which our service will be run.

In the next image, we see how the DisplayName and Description ServiceInstaller1 object have been defined, and how his startup is set to "Automatic." ServiceProcessInstaller1 object has been named the Local System Account properties with value, so that the service has a rather high level of execution privileges.



After this phase, we can proceed to the compilation of the solution, which will produce - as usual - an executable file to be used, however, in conjunction with the installutil.exe utility to perform the actual installation of the service.

Before running the build operations, make sure that - in the project - the startup object is our class.



Installing a service

Let's run the Developer Command Prompt for Visual Studio: just type this string into the Windows search box to make sure that is proposed. To ensure the successful installation, you should run the Command Prompt as administrator.



Then type the following command, where the string <PERCORSO_ESEGUIBILE> will obviously be replaced with the path on disk where to find the exe recently compiled.

C:\WINDOWS\system32>installutil <PERCORSO_ESEGUIBILE>



A series of on-screen information will show us whether the installation succeeded and any critical messages to be explored.
In our case, as you can see, the procedure is successful. Now we need to test the actual functionality of the application.

Running a test

We perform services.msc (or accessing it by Computer Management » Services), and we try our service, which initially will be inactive.
Notice in the screenshot to follow as the name and description match what you typed in relation to the properties ServiceInstaller1 object.



Press "Start": from now on, the operations performed in the specified folder will be monitored. We can see the start-up phase and functionality of the same in the video demonstration below.

Demonstrative video




Uninstalling a service


To uninstall our service, we must run again the Developer Command Prompt to execute installutil.exe, this time using - apart from the service path - the disinstallation flag /u.

C:\WINDOWS\system32>installutil /u <PERCORSO_ESEGUIBILE>

Conclusion

We have considered here the development of a simple service, with the purpose of showing the various phases between the development itself and the installation. There are no particular limits to the tasks a developer can implement using that kind of logic, and the reader is thus invited to better what we have seen, to deepen his knowledge about the topic, coming to create complete solutions suitable for the personal and working needs. 

Source code

The source code used in the article is freely downloadable at: https://code.msdn.microsoft.com/Creare-un-servizio-di-428d0141

Other languages


This article is also available in the flowing localizations: