Debugging Windows Services

Posted by

Paul Ballard posted recently about Debugging Windows Services, and I thought I should just add a few points to what he said.

Towards the end of his post, he said:

I tested every version of the Account property settings and no setting would prevent me from debugging the application. Therefore, you should not need to add any users or groups to the "Debugger Users" group on your machine. My testing on this was pretty quick though and so there could be some instances where this might be required.

There is one situation when you need to be a member of the Debugger Users group, and that's when you're trying to debug a process (any process, not just services) that's running under a different user account, and you're not a member of the Administrator group. This means if you're trying to write your software with LUA then you may run into problems debugging your service unless you're a member of the Debugger Users group.

But adding yourself to that group has two problems:

  1. It violates LUA, since it means you can attach to any process running under any account, and
  2. Even if you are a member of that group, only Administrators can start/stop services anyway so you're still up the creek!

There's a couple of ways to solve that second problem. The obvious one is to have a couple of batch files which you RunAs an administrators that just call NET START/NET STOP for you, and that's fine, but what I like to do is allow my server applications to run as both a Windows Service (for normal, production running) and as a regular Win32 process (for debugging).

It's actually quite simple to set up, and you can switch which one your server runs as by using the command-line arguments in the Main method. For example, here's some sample code:


public class MyService : ServiceBase
{
  static void Main(string[] args)
  {
    if (args.Length == 1 && args[0] == "-console")
    {
      RunFromConsole();
      return;
    }

    // Otherwise, normal service processing here
    ServiceBase.Run(new ServiceBase[] { new MyService() });
  }

  // Simulates running the service, even though we're
  // actually running from the console.
  static void RunFromConsole()
  {
    MyService service = new MyService();
    service.OnStart();
    // We need to wait for an "exit" event, just waiting for
    // a keypress is probably fine.
    Console.ReadLine();
    service.OnStart();
  }
}

Now, to be honest, I just wrote that from memory so it's probably not completely accurate, but you get the idea. And I'm sure your argument-parsing code would be much more robust than mine :)

This does present a couple of differences to running as a normal service, though. For example, you (obviously) can't run your service as the LOCAL SERVER, LOCAL SERVICE or NETWORK SERVICE accounts. However, for 95% of debugging purposes, it's perfect - especially since you can now just run your service directly from the IDE!

blog comments powered by Disqus