Testing Windows Services

| 6 Comments
Mark Pearce writes about Debugging a .Net Windows Service from within the IDE. We do something similar with our C++ Windows services but, as you've probably come to expect from me, it's slightly more complicated than Mark's approach.

Similarly to Mark I allow the main thread of the application to call the service entry point rather than passing the work off to the Service Control Manager (SCM) when we want to run the service in 'debug mode'. We decide if we run in debug mode by passing a command line switch, /debug, in some servers this switch is only valid in debug builds, in others it's useful to have it available all the time.

When a service is in 'debug mode', running as a normal exe rather than via the SCM, we need to intercept the normal service state change notifications that the service might generate rather than simply passing them on to the SCM. Basically we're not allowed to call SetServiceStatus() when running in debug mode. This is made easier by the fact that we have a service base class that passes the derived class (which is where each particular service's code lives) an interface for it to use to notify the SCM of things. Our derived class needn't know that we're running in debug mode because it never calls into the SCM directly, it calls via the interface that it's been given and we can simply decide to ignore the calls when running in debug mode.

The final wrinkle was allowing the service to respond to pause, resume and stop requests. When you're running the exe as a service you can control it using the services control panel. It's useful to have the same functionality available when testing the service so that you can debug issues with service shutdown or pause/resume functionality. It also means that you can run the service under tools such as BoundsChecker or Purify and cleanly shut the service down so that you can produce valid reports. These kinds of controls are usually passed to the service via the callback function that you pass into RegisterServiceCtrlHandlerEx() or RegisterServiceCtrlHandler(). The handler that our service code uses is already decoupled from the main service logic via an internal message queue (implemented with an IOCP) and when in debug mode we simply feed service control messages into the IOCP from a source other than the SCM callback. This 'other source' is simply a thread that listens on a couple of named Win32 event objects. These events can be controlled by a simple gui and allow us to send shutdown and pause/resume controls to the service even when it's running in debug mode.

The result of all of this is that we can run our services as normal exes by supplying a command line switch. The code that we need to write for each service never needs to know or care that it's running in debug mode and we can control the service as normal even when it's not connected to the SCM.

6 Comments

Cool. I have done something similar but a lot simpler when in debug mode. I use SetConsoleCtrlHandler and translate CTRL+C to shutdown and CTRL+BREAK to suspend/resume depending on state. And used a similar technique in C#. I also don't expose SetStatus to the users of the Service class and Service interface. Instead a spawn off a timer that calls SetStatus with pending shutdown/startup status at regular interval while another thread executes the service startup. This works fairly well and is simple but not as complete as your solution. I also depend on being compiled as console application but that generally makes sense for a service. And seing the service tracing away messages in the console when started in debug gives a cosy, warm feeling that something is happening ;) even when not in the debugger.

I like the idea of using CTRL+C etc to control the service... But, I don't build as a console app. I've had a little "two big buttons in a dialog" MFC app that does the shutdown and pause thing for ages as even my non service servers need to be able to do this.

I have a service that provides ssh for my application, regardless, I need that service to be able to spawn a GUI application. For sake of argument say notepad.exe.

I have tried runas but it does not work. Do you know of a solution?

Thank you so much. HeLp

For a service to interact with the desktop you need to configure it to do so... Perhaps that's your problem? See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/interactive_services.asp

That must be the problem, at least those are the symptoms that match the problem.

Also something interesting - If I ShellEx the application, notepad.exe, from the service with "interact with desktop" selected it runs in a SYSTEM context. If I use CreateProcessWithLogonW to spawn the application from the service with "interact with desktop" selected it will not start the application. Trying to avoid the security problem discussed via your link I figured the service could spawn the application under a more secured context, but NOPE no workin.

Any ideas on that? BTW - Thanks so much for the response and link.

I havent played around with CreateProcessWithLogonW. What error do you get? Access denied or something equally useful? Do you have the user credentials? Can you impersonate and then launch? I'm starting to get out of my depth at this point ;) Good luck.

Leave a comment