Easier debugging of Windows services

Is there an easier way to step through the code instead of starting the service through the Windows service control manager and attaching the debugger to the thread? It's a bit of a hassle, I wonder if there's a simpler way.

#1 building

A few weeks ago, when I found a new service project, I found this post. Although there are many great suggestions, I still haven't found the solution I want: the OnStart and OnStop methods of the service class can be called with any modification of the OnStop service class.

My proposed solution uses Environment.Interactive to choose the running mode, as shown in the other answers in this post.

static void Main()
{
    ServiceBase[] servicesToRun;
    servicesToRun = new ServiceBase[] 
    {
        new MyService()
    };
    if (Environment.UserInteractive)
    {
        RunInteractive(servicesToRun);
    }
    else
    {
        ServiceBase.Run(servicesToRun);
    }
}

The RunInteractive assistant uses reflection to call protected OnStart and OnStop methods:

static void RunInteractive(ServiceBase[] servicesToRun)
{
    Console.WriteLine("Services running in interactive mode.");
    Console.WriteLine();

    MethodInfo onStartMethod = typeof(ServiceBase).GetMethod("OnStart", 
        BindingFlags.Instance | BindingFlags.NonPublic);
    foreach (ServiceBase service in servicesToRun)
    {
        Console.Write("Starting {0}...", service.ServiceName);
        onStartMethod.Invoke(service, new object[] { new string[] { } });
        Console.Write("Started");
    }

    Console.WriteLine();
    Console.WriteLine();
    Console.WriteLine(
        "Press any key to stop the services and end the process...");
    Console.ReadKey();
    Console.WriteLine();

    MethodInfo onStopMethod = typeof(ServiceBase).GetMethod("OnStop", 
        BindingFlags.Instance | BindingFlags.NonPublic);
    foreach (ServiceBase service in servicesToRun)
    {
        Console.Write("Stopping {0}...", service.ServiceName);
        onStopMethod.Invoke(service, null);
        Console.WriteLine("Stopped");
    }

    Console.WriteLine("All services stopped.");
    // Keep the console alive for a second to allow the user to see the message.
    Thread.Sleep(1000);
}

This is all the code I need, but I also wrote drill Explain.

#2 building

You can also start the service from a command prompt (sc.exe).

Personally, I'll run the code as a stand-alone program during the debugging phase and change to run as a service when most of the errors are resolved.

#3 building

What I've done before is to have a command line switch that can start a program as a service or as a regular application. Then, in my IDE, I set the switch so that I can step through the code.

In some languages, you can actually detect whether it is running in the IDE and automatically perform this switch.

What language do you use?

#4 building

What I usually do is encapsulate the logic of the service in a separate class, starting with the "runner" class. This runner class can be an actual service or just a console application. So your solution has (at least) 3 projects:

/ConsoleRunner
   /....
/ServiceRunner
   /....
/ApplicationLogic
   /....

#5 building

I think it depends on the operating system you use, because of the separation between sessions, Vista is hard to connect to services.

I used to use two options:

  • Use GFlags (in the Windows debugging tool) to set up a permanent debugger for the process. This is useful in the image file execution options registry key. I think you need to adjust the service settings to enable interact with desktop. I use it for all types of debugging, not just services.
  • Another option is to separate the code so that the service part can be interchanged with the normal application startup. This allows you to use simple command-line flags and start as a process rather than a service, which makes debugging easier.

I hope this can help.

Tags: Windows

Posted on Mon, 16 Mar 2020 05:53:33 -0400 by shaoen01