Declaration of VAR

and some other stuff

How to create a Windows service

2017-02-06 10:22:24 +0100

2017-02-06 10:22:24 +0100 | Comments

Let’s create a Windows service - the thing that will run at the background and do stuff. For example, our service will write phrase “ololo” into Event Log.

OSWindows 10 x64
langC#
framework.NET Framework 4.6
IDEVisual Studio 2015

Creating service

Open Visual Studio and create new Windows Service project:

I named it SillyService.

The project starts with opened Service1.cs. Rename it to Service.cs. Actually, it does not matter, but looks better.

This file can be opened from Solution Explorer in 2 modes:

  1. Just double click on it and you will get a Design mode. That’s how it’s opened now;
  2. Or right-click on it and choose View Code - you will get the code of the file.

But now we need Design-mode. Click with right button on any free space of the edit area (it’s all free, because we haven’t added anything yet) and choose Properties. Edit them like this (just change the ServiceName):

Now find the sliding Toolbox on the left and drag the EventLog element from there into edit area of Service.cs opened in Design mode:

Click on it and choose Properties. Edit them like this:

From all my experiments I got that Log and Source should have different names (and be different from the name of service itself). So, I added _log and _source suffixes accordingly.

Ok, that’s done. Now right-click somewhere at free space of the edit area of Service.cs (still in Design mode) and choose Add Installer:

A new document will appear in a separate tab containing two elements: serviceProcessInstaller and serviceInstaller, both also available in two modes (Design and View Code). Edit Properties for both elements like this:

It’s about giving proper names, description and choosing the right authority level (LocalSystem).

Now let’s create some settings for the service. Right-click on project and choose Properties:

Go to Settings tab and click on the only label there (This project does not contain…). The settings file will be created, and it will be displayed as a table. We will create an int parameter there - timerInterval - which will store a value for timer (how often our service should perform some action):

Save everything and open Service.cs in View Code mode (right-click on the file in Solution Explorer). We will implement some actual stuff that our service will do, which is to write a text string to the Events Log every 10 seconds:

using System.Diagnostics;
using System.Reflection;
using System.ServiceProcess;
using System.Text;

namespace SillyService
{
    public partial class Service : ServiceBase
    {
        /// <summary>
        /// Main timer
        /// </summary>
        private System.Timers.Timer timer2nextUpdate;
        /// <summary>
        /// Timer interval in seconds
        /// </summary>
        private int timerInterval = Properties.Settings.Default.timerInterval;
        // here you can see how this value is being pulled out from Settings

        public Service()
        {
            InitializeComponent();
            
            // create new Source if it doesn't exist
            EventSourceCreationData escd = new EventSourceCreationData(eventLog.Source, eventLog.Log);
            // eventLog instance was created in Service.cs in Design mode, as you remember
            if (!EventLog.SourceExists(eventLog.Source))
            {
                EventLog.CreateEventSource(escd);
            }
        }

        protected override void OnStart(string[] args)
        {
            // using System.Text;
            StringBuilder greet = new StringBuilder()
                .Append("SillyService has been started.\n\n")
                .Append(string.Format("Timer interval (in seconds): {0}\n", timerInterval))
                // using System.Reflection;
                .Append(string.Format("Path to the executable: {0}", Assembly.GetExecutingAssembly().Location));
            write2log(greet.ToString(), EventLogEntryType.Information);

            // timer settings
            this.timer2nextUpdate = new System.Timers.Timer(timerInterval * 1000);
            this.timer2nextUpdate.AutoReset = true;
            this.timer2nextUpdate.Elapsed
                // what timer's event will do
                += new System.Timers.ElapsedEventHandler(this.timer2nextUpdate_tick);
            this.timer2nextUpdate.Start();
        }

        protected override void OnStop()
        {
            write2log("SillyService has been stopped", EventLogEntryType.Information);
        }

        /// <summary>
        /// Writing to log
        /// </summary>
        /// <param name="message">message text</param>
        /// <param name="type">type of the event</param>
        private void write2log(string message, EventLogEntryType type)
        {
            try { eventLog.WriteEntry(message, type); } catch { }
        }

        /// <summary>
        /// timer's event
        /// </summary>
        private void timer2nextUpdate_tick(object sender, System.Timers.ElapsedEventArgs e)
        {
            write2log("ololo", EventLogEntryType.Information);
        }
    }
}

Build the project.

Installing and launching the service

Now you have 2 files in the path\to\SillyService\bin\Debug directory:

  • SillyService.exe - executable of the service;
  • SillyService.exe.config - settings-file for the service.

There are actually more files there, but you don’t need them. Copy these 2 into some new directory, like C:\services\SillyService\. By the way, later you might want to use Release build rather then Debug.

Make sure, that Services and Event Viewer applications are closed.

Open command line with administrator rights (or, if you don’t want to deal with command line, use my application), find InstallUtil.exe path (mine was here: C:\Windows\Microsoft.NET\Framework\v4.0.30319\) and execute the following:

C:\Windows\Microsoft.NET\Framework\v4.0.30319>InstallUtil.exe c:\services\SillyService.exe

You’ll get something like this:

Sorry for Russian text on the screenshots (some UI on my Windows is in Russian), but there is nothing important there anyway.

Now you can start the service from Services (services.msc). Just in case, run Services with administrator rights:

After the start of the service you can open Event Viewer to see your service’s log there:

So, service is running, it will start automatically each time you reboot your computer and it will write a line of text to the Event Log every 10 seconds.

Possible problems

Service might not start and give you some error about not answering. Most probably, that is related to Source/Log stuff:

  • Check if you’ve set Local System in the Account field of serviceProcessInstaller Properties;
  • Perhaps, you ignored my notice about naming Log and Source;
  • Some other access problems. Try to set administrator’s credentials at Log On tab of service Properties in Services.

If you would like to uninstall service, use the same command, but just add /u key:

C:\Windows\Microsoft.NET\Framework\v4.0.30319>InstallUtil.exe /u c:\services\SillyService.exe

Sources

The source code of described SillyService is available here.