How to Debug a Windows Service

10.3k Views Asked by At

I have create a windows service using the Code Project Article. I am able to install the service and delete the service using -i and -d switch.

I am able to see the service in services.msc but when I start the service it does nothing.Below I will proide the service main code:

void WINAPI ServiceMain(DWORD argc, LPTSTR *argv)
{
  DWORD status;
  DWORD specificError;
  m_ServiceStatus.dwServiceType = SERVICE_WIN32;
  m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  m_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  m_ServiceStatus.dwWin32ExitCode = 0;
  m_ServiceStatus.dwServiceSpecificExitCode = 0;
  m_ServiceStatus.dwCheckPoint = 0;
  m_ServiceStatus.dwWaitHint = 0;

  m_ServiceStatusHandle = RegisterServiceCtrlHandler("Service1", 
                                            ServiceCtrlHandler); 
  if (m_ServiceStatusHandle == (SERVICE_STATUS_HANDLE)0)
  {
    return;
  }
  m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
  m_ServiceStatus.dwCheckPoint = 0;
  m_ServiceStatus.dwWaitHint = 0;
  if (!SetServiceStatus (m_ServiceStatusHandle, &m_ServiceStatus))
  {
  }

  bRunning=true;
  while(bRunning)
  {

    Sleep(150000);
    ShellExecute(NULL, "open", "C:\\", NULL, NULL, SW_SHOWNORMAL);

  }
  return;
}

But while I start the service neither it sleeps or starts the explorer. Am I missing anything?

7

There are 7 best solutions below

0
On

Services are headless, so trying to fire up anything GUI related will result in no visible effect. ShellExecute would fire up an application in the visual context of the service, which your desktop will not be able to see.

If you want to prove that your service is doing something, write something to file system instead (or trust that it's running given the service manager is rather well equipped to tell you if it's not).

0
On

I would recommend to write a little Logger-Class, that writes information to a text-file. Then you can e.g. put something like:

if (m_ServiceStatusHandle == (SERVICE_STATUS_HANDLE)0)
{
    Logger.LogError("Service handler is 0.");
    return;
}    

while(running) {

   Logger.LogInfo("I am running.");

   //...
}
0
On

You can always build a service in debug mode and attach a debugger to the running service. The only problem with this technique is that you can't debug the service start-up code. For this reason and for the fact that it can be a pain to be constantly registering/unregistering/starting/stopping a service in order to debug it, I always write services so that they can also be run as command line programs.

Your service can tell that it was started from the command line if StartServiceCtrlDispatcher() fails and GetLastError() returns ERROR_FAILED_SERVICE_CONTROLLER_CONNECT.

Of course, when you run a service from the command line it has access to the desktop, which a service normally doesn't and it's running in the context of the currently logged in user, rather than LocalSystem or a specified account so you need to take these differences into account when debugging a service in this manner.

0
On

I've got some general tips on debugging windows services here, though at first glance I think it's the fact that you're using ShellExecute which requires desktop interaction. A service typically runs on a LocalService account so it has no connection to a physical desktop.

0
On

Alternatively, OutputDebugString() can be put in the service app and prints can be seen in DbgView. I have done it to debug my service application. Hope this helps somebody..

1
On

Ferruccio's suggestion to attach a debugger to the running service is a good one, as is the suggestion to include an option to run as a console application (though that won't help in your case).

To debug the startup code, you can call DebugBreak() at the beginning of your startup code. That will launch the debugger and pause execution of your service at that point. Once you are in the debugger, set whatever breakpoints you need and then continue execution.

2
On

Use below code to debug your service, put this in service startup function, it will give you a popup and hold the execution until you say OK or until 60 seconds, put the breakpoint in the next execution statement and you can proceed with debugging -

Include this header-

#include <Wtsapi32.h>
#pragma comment( lib, "Wtsapi32.lib" )

Code-

wchar_t title[] = L"service 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 );