Click here to Skip to main content
Email Password   helpLost your password?

Introduction

This article demonstrates how to start and debug a Windows service with Visual Studio 2008. It will also work with Visual Studio 2005.

Background

When developing a Windows service with Visual Studio, you usually have to start the Windows service with the Service Control Manager, and then you have to attach the debugger to the process. But this is not necessary. You can automate this process in most cases so you only have to press F5.

Using the Code

Visual Studio can be automated just like Office. You can use this feature to start and debug a Windows service by pressing F5.

To achieve this goal, create a new Windows Forms project in the solution of your Windows Service project and make it the startup project of your solution. Name the project ServiceDebug and name the form console.

Make some Imports to the class of the form:

Imports System.ServiceProcess
Imports System.Runtime.InteropServices
Imports System.ComponentModel
Imports EnvDTE

This will make the code more readable.

There are two constants. One contains the name of the Windows service, the other contains the full path to the executable of the Windows service:

' Replace the value of this constant with the name of the service.
Private mcsServiceName As String = "INSERT_SERVICE_NAME_HERE"
' Replace the value of this constant with the path of the executable.
Private mcsExecutablePath As String = "INSERT_EXECUTABLE_PATH_HERE"

There is one private variable in the class for the Visual Studio automation object, DTE. It is comparable to Office's Application object; you can access almost every functionality of Visual Studio through this object:

' Visual Studio Object.
Private mDTE As EnvDTE.DTE

All the work will be done in the Load event of the form:

Private Sub Console_Load(ByVal sender As System.Object, _
                         ByVal e As System.EventArgs) Handles MyBase.Load
' Array with all installed windows services.
Dim aoServices() As ServiceController

Dim bFoundService As Boolean
Dim bFoundProcess As Boolean

The first task is to find the Windows service and to start it. You can use the ServiceController class to do this:

' Search the service.
aoServices = ServiceController.GetServices()

' Loop through all services.
For Each oService As ServiceController In aoServices
    ' Service found?
    If (oService.ServiceName = mcsServiceName) Then
        ' Service found. Set flag.
        bFoundService = True

        ' Check state.
        Select Case oService.Status
            ' Running?
            Case ServiceControllerStatus.Running
                ' Stopped?
            Case ServiceControllerStatus.Stopped
                ' Start it.
                oService.Start()
                ' Paused?
            Case ServiceControllerStatus.Paused
                ' Start it.
                oService.Start()
                ' Something else.
            Case Else
                Throw New Exception("Der Windows-Dienst " + mcsServiceName _
                                  + " kann nicht gestartet werden.")
        End Select
    End If
Next oService

' Raise exception if service not found.
If Not bFoundService Then
    Throw New Exception("Der Windows-Dienst " + mcsServiceName _
                      + " ist nicht installiert.")
End If

The second task is to find the process and to attach the Visual Studio debugger to it. You can use the Debugger property of the DTE object to do this:

' Get Visual Studio-Object.
mDTE = CType(Marshal.GetActiveObject("VisualStudio.DTE"), EnvDTE.DTE)

' Search the process.
For Each oEnvDTEProcess As EnvDTE.Process In mDTE.Debugger.LocalProcesses
    Try
        ' Process found?
        If (oEnvDTEProcess.Name = mcsExecutablePath) Then
            ' Process found.
            bFoundProcess = True

            ' Attach to the process.
            oEnvDTEProcess.Attach()
        End If
    Catch ex As Win32Exception
        Debug.Print(ex.ToString)
    Catch ex As COMException
        Debug.Print(ex.ToString)
    End Try
Next oEnvDTEProcess

' Raise exception if process not found.
If Not bFoundProcess Then
    Throw New Exception("Der Prozess " + mcsExecutablePath _
                      + " existiert nicht.")
End If

In the Disposed event of the form, you can enter similar code to stop the Windows service when you close the form:

Private Sub Console_Disposed(ByVal sender As Object, _
                             ByVal e As System.EventArgs) Handles Me.Disposed
    ' Array with all installed windows services.
    Dim aoServices() As ServiceController

    ' Flag set if the service was found.
    Dim bFoundService As Boolean

    ' Search the service.
    aoServices = ServiceController.GetServices()

    ' Loop through all services.
    For Each oService As ServiceController In aoServices
        ' Service found?
        If (oService.ServiceName = mcsServiceName) Then
            ' Service found. Set flag.
            bFoundService = True

            ' Check state.
            Select Case oService.Status
                ' Running?
                Case ServiceControllerStatus.Running
                    ' Stop it.
                    oService.Stop()
                    ' Stopped?
                Case ServiceControllerStatus.Stopped
                    ' Paused?
                Case ServiceControllerStatus.Paused
                    ' Stop it.
                    oService.Stop()
                    ' Something else.
                Case Else
                    Throw New Exception("Der Windows-Dienst " + mcsServiceName _
                                      + " kann nicht gestoppt werden.")
            End Select
        End If
    Next oService

    ' Raise exception if service not found.
    If Not bFoundService Then
        Throw New Exception("Der Windows-Dienst " + mcsServiceName _
                          + " ist nicht installiert.")
    End If
End Sub

Points of Interest

This project will, in most cases, reduce the effort to start and debug a Windows service with Visual Studio to pressing F5. There is one important limitation. When debugging the startup of a Windows service, you cannot use this technique. The reason for this is not clear to me. It just looks like the constructor of the Windows service has already finished when the debugger attaches to the process. If someone has an idea, please let me know.

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralNeed Help...
Jason Langley
3:29 30 Nov '08  
I can't get this code to work in VS 2008 Professional Edition with .Net Framework 3.51 SP1. It first throws an exception trying to start the service. To try and test the rest of the code, I start the service via the services.msc. The code knows that is running, but when it attempts to run the line of code

For Each oEnvDTEProcess As EnvDTE.Process In mDTE.Debugger.LocalProcesses

I get a ComException was unhandled: Call was rejected by callee. (Exception from HRESULT:0x80010001 (RPC_E_CALL_REJECTED))

Can someone help?
AnswerRe: Need Help...
Member 4115604
15:45 22 Jun '09  
I have had the same problem, it can be resolved by making the threading sleep time in Console.vb shorter. I found that if I make the line
System.Threading.Thread.Sleep(10000)
go to:
System.Threading.Thread.Sleep(5000)
It worked. Regards, Martin
General.NET API to debug code
Member 4307035
0:06 21 Jul '08  
System.Diagnostics.Debugger.Break(); will do the same thing. It will break the execution when it hits that line of code. I hope even contructor can be debugged that way.

But since Services run under control of SCM, if the start method doesn't return in time, SCM will generate an exception.

Regards,
Generaleasy way
Pauloc
6:56 19 Jul '08  
maybe not the best way but the easiest way.
just put this where you want to stop and do debug

#ifdef _DEBUG
__asm int 3;
#endif



it's an interrupt that will provoque a break in that point and you can attach to your opened project.
GeneralInstaller/Uninstaller
Happy camper
9:41 18 Jul '08  
Ok, getting lazy but that is what some of these forum are for, right? Cool

How about taking this to the next level and have your form also assist in installing and uninstalling the freshly compiled service or is there a way to the a Build Event to handle that? Handy for step testing newly added code as it is SOOOO hard to toggle between 'installutil /u service' and 'installutil service'. Smile
GeneralRe: Installer/Uninstaller
Michael Leithold
4:43 21 Jul '08  
I don't need this feature so I didn't implement it. Usually I install the service from the bin\Debug directory once in the beginning. When I compile I only have to stop the service, compile and start it again. It is not necessary to uninstall and reinstall in my case.
But it is a great idea. Feel free to extend my example!

Michael
GeneralAlternative method
jimbobmcgee
2:30 18 Jul '08  
I always use a conditional, with a call to Debugger.Launch() myself. In the Start method of your service, put:

#If DEBUG Then
System.Diagnostics.Debugger.Launch()
#End If

That way, when the service starts, if you have compiled in Debug mode, it should pop up the debugger and attach for you.

Yours seems more comprehensive, though.
GeneralRe: Alternative method
PHenry
8:25 18 Jul '08  
JimBobMcGee, can you add a bit more info please? Is your #if DEBUG... the only thing needed? Or does that work in conjunction with the rest of the code?

I'm just getting into creating a Windows Service now and think this is a great entry (and fantastic timing! :>).

Thanks guys! :> (both of you :>)
GeneralRe: Alternative method
Happy camper
8:49 18 Jul '08  
Actually this is great timing for me as well, I wrote my first service yesterday and crashed it today.

The shear convenience of the the F5 that starts the service and debugger is very handy as my crash occurs on service init, and thus manually starting the service getting the debugger launched and hopping through the code before the 'start attempt' is complete gives me very limited time to step to the crash.
GeneralRe: Alternative method
jimbobmcgee
0:27 21 Jul '08  
To be honest, I haven't tried the code in the article. In my case, I found the #If DEBUG... part all I needed. This was based on the consideration that I had no code to run before the Start call (e.g. no constructor code).

The end result of my placing the #If block into my Start routine was that, once I had installed the service and clicked 'Start' in services.msc, the a debugger window would pop up and I would be able to choose my debugger (which could be my already-opened Visual Studio IDE). Then the chosen debugger would launch on the Launch() line and I would have to press 'Continue'.

The caveats of my approach are that:
* you must choose a debugger and continue execution before services.msc's start timer expires
* you must not be 'running' other code in the Visual Studio IDE otherwise it would spawn a new IDE with the breakpoints missing

I coupled this approach with InstallUtil.exe calls in my build events; before building, I would uninstall the service and after, I would install.

I may be wrong but the article code looks like it creates a form with start and stop buttons; the start button starts the service and attaches the current IDE debugger. Without looking further I cannot see if this form also installs/uninstalls the service on Load/Closing. If it does, this looks like a good aproach (bar the limitation listed by the writer).
GeneralRe: Alternative method
Michael Leithold
4:39 21 Jul '08  
Yes, the service will be started and the debugger will be attached to the process when you start the helper application. The service will be stopped when you close the form.
The helper application will not install/uninstall the service. See other post.

Michael
GeneralRe: Alternative method
Michael Leithold
4:35 21 Jul '08  
Also a very nice trick. You still have to start the service with the service control manager. But it will free you from searching the process from the process list and attaching the debugger to it. And you can also use it in the startup code.

Thank you! Michael
GeneralRe: Alternative method
Peter Mauger
17:14 5 Aug '08  
Given the amazing help this has been I thought I'd add to it a little. If you change your service's ProjectInstaller file and add the Committed event then inside this event you can add

ServiceController service = new ServiceController("INSERT YOUR SERVICE NAME HERE");
try
{
service.Start();
}
catch
{
}

What this will do is that when your post-build installutil is successfully committed the service will automatically run and trigger the Debugger.Launch(). ie You press F5 and the debugger starts (with a couple of clicks to attach successfully).

I was having a really hard time getting my new 2.0 project to attach and actually hit the breakpoints so I'm fairly happy now Wink .


Last Updated 18 Jul 2008 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010