Below is a more or less empty sample from a window service project, you can build in Visual Studio.
The service itsself (created by the VS Project) has events for Start and Stop command, which you use to hook your worker code into:
using System.ServiceProcess;
namespace PerformanceCollectorService
{
public partial class PerformanceCollectorService : ServiceBase
{
private CollectorTask _collectorTask;
public PerformanceCollectorService() {
InitializeComponent();
}
/// <summary>
/// Service start initializes a new worker, and issues a start command
/// </summary>
/// <param name="args"></param>
protected override void OnStart(string[] args) {
_collectorTask = new CollectorTask();
_collectorTask.Start();
}
/// <summary>
/// Service stop issues a stop command to the existing worker
/// </summary>
protected override void OnStop() {
_collectorTask.Stop();
}
}
}
Example of an empty worker, which does not do more then writing event to the eventlog
using System.Diagnostics;
using System.Threading;
namespace PerformanceCollectorService
{
internal class CollectorTask
{
private Timer _timer;
/// <summary>
/// Starting the worker initializes a timer with a specified delay and interval
/// </summary>
public void Start() {
EventLog.WriteEntry("PerformanceCollectorService", "Service Start", EventLogEntryType.Information, 1000);
_timer = new Timer(Callback, null, 6000, 6000);
}
public void Stop() {
EventLog.WriteEntry("PerformanceCollectorService", "Service Stop", EventLogEntryType.Information, 1002);
_timer.Change(-1, -1);
}
private void Callback(object state) {
EventLog.WriteEntry("PerformanceCollectorService", "Service Callback", EventLogEntryType.Information, 1001);
}
}
}
For installation, Advanced Installer is a good option, that offers the option to build either MSI or MSIX packages around a service.
Below is the original Visual Basic document from 2008, Please do not use it, it is just left here for reference from another era
Creating the project and installation procedures
Start Visual Studio, and choose the windows service project type. And empty objects panel appears. Drag any controls you will use onto this panel. Many examples use a timer control, but i choose a different concept for two reasons;
- Timer controls can be problematic in windows services. The default timer control of a forms application is bugged, and will not – or not always fire. Usage of a system.threading timer is another option that works, but is less intuitive for an example.
- You may not want to work with a timed event, and use a continuously running background programm.
This example uses such a model. It uses a global variable to indicate wheter the main loop is running, and another one to indicate if a stop request has been received from the service manager. Using these two variables demonstrates how to communicate between the events and the main programm that has been fired off by the service start into a seperate thread.
Rightclick the panel, and choose “Add Installer”, This will add all the installer objects needed.
On the serviceeprojectinstaller1 object; set the account to Localsystem
Adding the code
By double clicking on the service design panel, you will be able to access the actual code for the service. The complete code is below:
Public Class Service1 Dim v_shutdownsignal As Boolean = False Dim v_mainlooprunning As Boolean = False 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. WriteEvent("WinServicedemo v1.0.1 starting", "WinServiceDemo", EventLogEntryType.Information, "WinServiceDemo") ' --- Fire the main loop of our programm Dim th As New Threading.Thread(AddressOf MainLoop) th.IsBackground = True th.Start() End Sub Protected Overrides Sub OnStop() ' Add code here to perform any tear-down necessary to stop your service. ' --- Signal the main loop to stop v_shutdownsignal = True ' --- Wait for the main loop to signal that is has stopped While v_mainlooprunning = True ' --- Wait for the main loop to die System.Threading.Thread.Sleep(10) WriteEvent("Waiting for the main loop to stop...", "WinServiceDemo", EventLogEntryType.Information, "WinServiceDemo") End While ' --- Now the mainloop has shut down cleanly WriteEvent("WinServicedemo stopping", "WinServiceDemo", EventLogEntryType.Information, "WinServiceDemo") End Sub Public Sub MainLoop() ' --- This is the main loop of our service ' --- Set the global to indicate the stop controller that we are running v_mainlooprunning = True ' --- Run the main programm until we get a signal that the user stopped the service While v_shutdownsignal = False WriteEvent("The minute event fired in the main loop", "WinServiceDemo", EventLogEntryType.Information, "WinServiceDemo") Dim n_delay As Integer While n_delay < 60 And v_shutdownsignal = False ' wait 60 seconds, OR till a shutdown request n_delay = n_delay + 1 System.Threading.Thread.Sleep(1000) End While End While ' --- Signal that we are done v_mainlooprunning = False End Sub Public Function WriteEvent(ByVal sEntry As String, ByVal sAppName As String, ByVal eEventType As EventLogEntryType, ByVal sLogName As String) As Boolean ' --- Write to the eventlog ' Source: http://www.dreamincode.net/code/snippet1122.htm ' If a non existing logfile is specified, it will be created for us Dim oEventLog As New EventLog Try 'Register the Application as an Event Source If Not EventLog.SourceExists(sAppName) Then EventLog.CreateEventSource(sAppName, sLogName) End If 'log the entry oEventLog.Source = sAppName oEventLog.WriteEntry(sEntry, eEventType) Return True Catch Ex As Exception Return False End Try End Function Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) ' --- Write an event every tick to the eventlog WriteEvent("WinServicedemo timer event", "WinServiceDemo", EventLogEntryType.Information, "WinServiceDemo") End Sub End Class
Installing the service
BUILD the project. This will result in the binary being present in the project directory. Move the sercvice executable if you want to another directory where it will be run. Installation of the service is done with the installutil tool. This tool is directly accessible from a Visual Sutdio command prompt, or from the .NET framework directory in your system directory (eg:)
Map van C:\windows\Microsoft.NET\Framework\v2.0.50727 27-07-2008 20:03 28.672 InstallUtil.exe 1 bestand(en) 28.672 bytes
run installutil winservicedemo.exe to install the service -or- run installutil /u winservicedemo.exe to remove the installed service2
Finaly, you should be able to see the service in the control panel’s service overview, and see the logged events.
Keep in mind that while running and installing your service from the project directory is fine during development, you will need to stop the service to be able to build (the executable will be in use after all). You may want to change the name of the base class of the project (service1 in this example), as that is the name that will be used in the application log by windows to log events about your service.
C# Code example
using System; using System.Diagnostics; using System.ServiceProcess; using System.Threading; namespace PopzGuardian { public partial class PopzGuardian : ServiceBase { private bool vStopCmd; // will be used to pass a stop cmd to the background service private bool vIsRunning; // Will be used to pass stop/run status back from the background service public PopzGuardian() { InitializeComponent(); } // OnStart is executed when the service is started, and launches the background thread protected override void OnStart(string[] args) { EventLog.WriteEntry("PopzGuardian starting"); vStopCmd = false; Thread th = new Thread(MainLoop); th.IsBackground = true; th.Start(); } // OnStop is executed when the service is stopped. It passes the stopcommand on to the back // ground service, and waits for it to change it's status from running to stopped. protected override void OnStop() { vStopCmd = true; EventLog.WriteEntry("PopzGuardian is now stopping."); while (vIsRunning == true) { Thread.Sleep(10); } } // This is the main worker thread of the service. protected void MainLoop() { vIsRunning = true; EventLog.WriteEntry("PopzGuardian is now running"); while (vStopCmd == false) { Thread.Sleep(100); // Work goes here } EventLog.WriteEntry("PopzGuardian stopped."); vIsRunning = false; } } }
Install projects
If you have created a setup project to install your service you need to make a slight adjustment to tell it that you actuably want to install a service. Rightclick the project, choose view, and then “custom actions”
Rightclick the custom actions node and “add custom action”
Choose your project output for the custom action
Your project output is now listed in each of the steps
Build the setup project and deploy, the service will now be installed by the installer application.