Introduction
Windows Services is a powerful programming tool that the Windows OS give us to run programs without the need for a human user logged in to the system.
Due the Windows Service nature, Visual Studio cannot directly launch a service and debug it. Also, you cannot attach a service to debug the service constructor or to debug the Start
event. That is because you cannot attach a process that does not exist!
There exists different solutions: one of these is explained in an excellent article by Lee Humphries. But, what about attaching the debugger at the program point where we want to begin to debug? Well, it is possible in .NET 2.0, you only need to use the Debugger
class from System.Diagnostic
namespace.
Background
Debugger class in System.Diagnostic has an important method for our purposes: Debugger.Launch()
.
When Debugger.Launch()
is executed, it watches if the actual process is attached to any debugger; if it is not, it opens the debugger attachment windows and prompt us to select the appropriate debugger to use with the program. Then, you only need to locate the call to Launch()
where you want to begin controlling the service.
See the following code an example to init a debugger in the OnStart
event of a Windows Service:
protected override void OnStart(string[] args)
{
iTest = 1;
#if (DEBUG)
Debugger.Launch();
#endif
timer1.Enabled = true;
}
When the framework executes the Debugger.Launch
method and prompts you to select the debugger, select the VS instance that shows the service code and continue to run the service under the control of the debugger.
You need to surround the instruction with a #if #endif
clause because the method Debugger.Launch()
also executes in Release mode (that should not happen, but .NET 2.0 has a bug in the Debugger.Launch()
method).
Using the code
- Download and compile the code attached to the article with the DEBUG option.
The code is a simple Windows Service that uses a timer to increment an integer value with an interval of 5 seconds. The service writes the value of the integer variable in the output windows. Take a look at the the Launch()
method in the code.
- Install the Windows Service. I recommend automating this task. Personally, I created in the Tool -> External Tool menu, two inputs: one to install and another to uninstall the service. See the image below:
If you have another system to install/uninstall the service, skip the following description:
To create an entry to install the example Windows Service, click Tool -> External Tool -> Add, and enter:
- Title: InstallService
- Command: C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe (use the directory of your Windows installation)
- Argument: WServiceDebug.exe
- Initial Directory: $(ProjectDir)/bin/debug
To create an entry to uninstall the example Windows Service, click Tool -> External Tool -> Add, and enter:
- Title: UnInstallService
- Command: C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe (use the directory of your Windows installation)
- Argument: /u WServiceDebug.exe
- Initial Directory: $(ProjectDir)/bin/debug
- In Visual Studio, see that the code page of the Web Service is open.
- Start the service. Open the Services applet: Control Panel -> Administrative Tools - > Services. You will see that the service named WServiceDebug is not started. Right clickand select Start. You can see the dialog to select the debugger is open. Select the instance of Visual Studio that has the Windows Service project open. Go to Visual Studio, see that the program is stopped and ready to debug. Press F5 and see in the Output windows that the timer writes the value of the integer value in 5-second intervals. Do not start a new debugger; use the Visual Studio instance when you have the service compiled.
- Set a break point in the Stop procedure and stop the service. You will see that the program stops at the break point, Press F5 to end the debug session.
- Uninstall the Windows Service (use the shortcut created in point 3). Recompile the application but in Release mode. Then, re-install the Windows Service and start it (you must modify the shortcut to install/uninstall to the initial directory: $(ProjectDir)/bin/release. You will see that the invocation to the debugger will not succeed and the service starts normally.
- Recompile the program in Debug mode and experiment with different situations of the
Launch()
method inside the service code.
Points of interest
Using the System.Debugger.Launch()
method is a simple solution to resolve the problem of debugging Windows Services. I suppose that a lot of you are using this technique, but I have not found much information about this (I have not done much research).
History
- 07 August 2007 - First version.