About six months ago I wrote a tiny bit of code that I called ServiceRunner. I put it up on NuGet and GitHub. but never got around to blogging about it until today. And since I’ve already blogged today about writing a Windows Service, it seemed a good time to share.
Why? Because I had grown tired of wiring up a Windows Service host for one project or another and wanted to reduce it down to the very least amount of code possible all while keeping the project as a standard console app to make debugging as simple and easy as possible.
Here is the easiest path to a working Windows Service:
- Create a .NET console app in Visual Studio.
- Install the NuGet package called ServiceRunner with Install-Package ServiceRunner.
- Add a class that inherits from ServiceRunner.ServiceRunnerInstaller as shown below.
- Add a simple bit of code to your console app’s Main method as shown below.
- Build and debug with the Runner’s runAsConsole constructor parameter set to false.
- When ready to deploy as a service, change that parameter to true. How you do that is up to you.
- Now run the InstallUtil command line installer as installutil c:\yourpath\yourapp.exe -i and your service is installed and ready to run. (If you use a Visual Studio command line, installutil will be in your path. Otherwise you’ll find it in the .NET framework install directory under C:\Windows\Microsoft.NET\Framework{64}\{version}.)
Here’s the code for the required installer class:
using ServiceRunner;
namespace ServiceRunnerDemo
{
/// <summary>
/// This class (name unimportant) must exist in your console app
/// for the installer to be recognized when you run installutil.exe
/// from the Windows\Microsoft.NET\Framework64\v4.0.30319 directory.
/// </summary>
public class MyInstaller : ServiceRunnerInstaller
{
protected override string ServiceName
{
get { return "ServiceRunner"; }
}
protected override string ServiceDescription
{
get { return "Service Runner description"; }
}
protected override string ServiceDisplayName
{
get { return "Service Runner"; }
}
protected override ServiceRunnerStartMode StartMode
{
get { return ServiceRunnerStartMode.Manual; }
}
protected override ServiceRunnerAccount Account
{
get { return ServiceRunnerAccount.LocalSystem; }
}
}
}
And here’s the code for the console app Main method.
using System;
using System.IO;
using ServiceRunner;
namespace ServiceRunnerDemo
{
class Program
{
static void Main(string[] args)
{
var logFile = "c:\\temp\\logit.txt";
var runner = new Runner("MyServiceRunnerDemo", runAsConsole: false);
runner.Run(args,
arguments =>
{
// equivalent of OnStart
File.WriteAllLines(logFile, new string[]
{
string.Format("args count: {0}", arguments.Length)
});
Console.WriteLine("args count: {0}", arguments.Length);
// normally you would launch a worker thread here
// to do whatever your service would do
File.WriteAllLines(logFile, new string[]
{
"start called"
});
Console.WriteLine("start called");
},
() =>
{
// equivalent of OnStop
File.WriteAllLines(logFile, new string[]
{
"stop called"
});
Console.WriteLine("stop called");
});
Console.ReadLine();
}
}
}
As you can see, the code is very simple. Far less to worry about than using the standard Visual Studio project template or trying to manually cobble up the installer and other pieces required. If you get any good use out of it, I would love to hear from you.
Happy Windows Service writing!
Nine months ago I blogged about my curiosity about the D programming language. It is possible that this curiosity is turning into a hobby. Time will tell. Recently I decided to create a Windows Service written in the D programming language. I’ll share my journey to that end here.
When I started I assumed it would be easy to find examples in the open source world from which I could learn. That assumption turned out to be mostly false. I found some posts on the forum that were helpful. I then dug up an email address using that famously free detective, Google. Graham Fawcett was very helpful in sharing some code with me but for some reason I could not get it to work.
After a week or more of evenings attempting to find a solution, I gave up and offered a bounty on the forum. And Vladimir Panteleev, a regular D community contributor, came to my rescue and gladly took the $100 bounty to be applied toward other issues he would like to see resolved. My deep thanks to both of these community members.
As it turns out, the code that Graham shared with me would have worked except the Win32 bindings code had an x64 bug that would not have manifested itself had I been compiling for x86. Specifically, the winsvc.d code file contained the line:
alias DWORD SERVICE_STATUS_HANDLE;
I took Vladimir’s advice and changed it to:
alias size_t SERVICE_STATUS_HANDLE;
And then later pulled in his final fix as;
mixin DECLARE_HANDLE!("SERVICE_STATUS_HANDLE");
I won’t try to explain the differences here. In any case, the handle in x64 world needed to be a ulong and it was getting declared as a uint (C# equivalents here). And once that was resolved, I was very happy to see the code work.
You can get or read the code for that first success on GitHub. I refactored that code using a reference app in C++ that followed a familiar pattern having written many Windows Service in C#, even to the point of writing a short cut to standing up a Windows Service in .NET.
In any case, if you are curious to see my first real foray into the world of D programming, you can check out the code on GitHub. It even includes a minor improvement suggested by a forum member already. And if you have questions or need help, please leave a comment and I will do my best to help.