Channels ▼
RSS

.NET

Debugging Windows Services


The only thing I need to send a message to my screen is the console session ID, and Microsoft was kind enough to provide an API for that as well. The lines inserted into my app to support this look like this:

#include <Wtsapi32.h>
#pragma comment( lib, "Wtsapi32.lib" )
//
// other parts of your program ...
//
HRESULT CmrnServiceModule::PreMessageLoop(int nShowCmd)
{
#ifdef _DEBUG
    wchar_t title[] = L"mrnservice in startup - 60 seconds to take action";
    wchar_t message[] = L"To debug, first attach to the process with Visual "
                        L"Studio, then click OK. If you don't want to debug, "
                        L"just click OK without attaching";
    DWORD consoleSession = ::WTSGetActiveConsoleSessionId();
    DWORD response;
    BOOL ret = ::WTSSendMessage( WTS_CURRENT_SERVER_HANDLE,
                                consoleSession,
                                title, sizeof(title),
                                message, sizeof(message),
                                MB_OK,
                                60,
                                &response,
                                TRUE );
#endif
// my next line of real code

With this code in place, when I am unsure about what is happening with the startup, my workflow works like this:

  • I build my project, and install the service with mrnService.exe /service.
  • I set a breakpoint in my program at the the first line of code after WTSSendMessage — the point where initialization commences. If I am drilling down with more specificity, I might set the breakpoint at a different point in the startup code.
  • I start the service with sc start mrnService.
  • I see a dialog popup, as shown in Figure 5.
  • I switch to Visual Studio, and invoke Debug|Attach to Process.
  • In the resulting dialog, I make sure that I have "Show processes from all users" checked.
  • I navigate down to mrnService.exe as quickly as possible, then click the Attach button.
  • Finally, I return to the dialog popped up by my service and click OK.
  • If all is working properly, I will then immediately hit a breakpoint in my service, and I can start walking through my code to see where things have gone awry.

Windows Services
Figure 5: My service startup popup.

This is a simple hacke and it works more or less as expected. Compared with other techniques for debugging service startup, I find it a winner.

A Few Other Issues

Microsoft really blew it when they decided to name this special class of processes "Windows Services." The word "Services" is so heavily overloaded in the world of Windows that you could easily come up with a dozen different uses for the term — starting with the biggest conflict, COM Services/Servers. This makes it extraordinarily hard to use Web searches to find information on any problem.

*IX is way out ahead on this, with their equivalent processes having the unique name "daemons." The search space is much more constrained, allowing you to drill down a lot faster.

One other problem you might run into when debugging services is that the Service Control Manager will run out of patience when trying to start your service. After a minute or two, you are going to fail out. Buried in MS KB824344, you can find the instructions on modifying your registry settings to allow for long timeouts — not something you want to do on production machines, but totally appropriate in a development world.

My demo 32-bit C++ Windows Service project for Visual Studio 2012 is just a shell and doesn't do much, but you can experiment with it to do sanity testing.

If you are using RDP to connect to the machine where you are debugging, the technique shown here won't quite work. It will pop up a dialog on the console of the machine you are connected to — not the RDP window that you are using. I'll show you how to get around this problem in a future article.

None of this stuff matters if you are developing on Windows XP. Of course, being on XP means you have plenty of other problems to deal with, but Session 0 isolation is not one of them.

I highly recommend not using the mmc.exe Services plugin to start and stop your services during development — in fact, it is best if you don't even run mmc.exe while you are doing service development. There are issues you will run into where your services become disabled but can't be removed, sometimes even requiring a reboot. Open an escalated CMD.EXE window in the Debug directory of your project, and get used to using these commands over and over:

rem
rem initial registration of your service
rem
servicename.exe /service
rem
rem stop and start service
rem
sc start servicename
sc stop servicename
rem
rem Removal of service
rem
servicename.exe /unregserver

Of course, keep in mind that the name of your executable and the name of your service won't necessarily be the same. That's up to you.

Good luck with your service development! Once you get past some of these tricky bits, it's really no different than debugging your normal apps. You just have to become a bit of a start-up guru.


Mark Nelson is a blogger for Dr. Dobb's.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video