Debugging Windows Services

Mike Diehl had a recent blog post about debugging Windows Services.  As I've been doing quite a bit of this lately, I thought I might jump in with some more information on Windows Services and the fun that is debugging them.

Debugging Service Startup

When a Windows Service is installed into the Service Control Manager, it doesn't start running until it's either started manually or if the installer StartType property is set to "Automatic" then after the system reboots.  What this means to your debugging is that you can't simply install the service and attach the Visual Studio debugger to the process as there isn't one to attach to until after you start the service.  However, once you start the service if you have a bug such as an exception in the service's initialization you won't get the debugger attached to the process before it's too late.  So then, how do you debug the service class' initalization?  Using the System.Diagnostics.Debugger.Lauch() method.

// The main entry point for the process

static void Main()

{

#if DEBUG

      System.Diagnostics.Debugger.Launch();

#endif   ...

This method pops up the following screen asking you which instance of the debugger it should use to debug the application.



Note that I have placed the Debugger.Launch method call inside a "#if DEBUG" compiler directive.  DEBUG is a predefined directive that is automatically added when the application is compiled in Debug mode.  Therefore, while I am working on the application the Debugger.Launch method will be called, but when I switch to Release mode the C# compiler will skip that command.  This will keep you from having to remember to remove all of your Debug code (not that you shouldn't be doing that anyway).

Debugging After Startup

After the service has intialized and the OnStart override has been executed the service will begin its work.  If you've used the method listed above to start the Debugger when the service starts up you can then create breakpoints in Visual Studio or you can put Debugger.Break() methods into your code where you want the debugger to stop code execution. 

You can however choose to debug a service that is already running, by attaching the Visual Studio Debugger to the process.  Click on the Debug menu option and select "Processes".  This will bring up the following window listing the processes currently running on the machine. 



Select the process you want to debug and hit the 'Attach..." button.  The next window asks what types of programs you want to debug.  Make sure the "Common Language Runtime" option is checked and hit OK.  You are now debugging that process.  If the EXE is compiled in Debug mode and the PDB file is in the same directory as the EXE, you should see the source code for your service.  Just set your breakpoints and you're off and debugging.



Recompiling The Service

When the Service Control Manager tells the service to stop, the process for the service should finish up any work and end gracefully.  As long as this is happening and no threads are left running, you should be able to simply recompile your service in place without reinstalling it.  However, if you do leave any residue running Visual Studio will give a build error saying that the  EXE file cannot be copied because access is denied, file in use by another process.  This is a design issue so if you find that after stopping your service you still cannot access the EXE file, you should debug the application to make sure you have cleaned up all of the resources and threads.

Execution Permissions

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. 

Hope this information helps in your Windows Service Debugging

1 Comment

  • I am trying to debug a windows service that is running under a windows domain account. I am using the debugactiverprocess function to try and connect to the process. I have already changed the security token and am impersonating my own account (which the process is running under) but it will not bind to the process. If the account runs under the local system account then it will work ok but not under a domain account.

    Do you know what the reason behind this is?



    Karl

Comments have been disabled for this content.