5

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?

Simsons
  • 12,295
  • 42
  • 153
  • 269
  • Explorer is always running on Windows, so it wouldn't be restarting it. Check out your task manager, about what is happening. – DumbCoder Feb 21 '11 at 09:56
  • What you expected from this code? What it means "when I start the service it does nothing"? If you expect some window you should change service property and set "Allow service to interact with desktop" check box. – Sergey Teplyakov Feb 21 '11 at 12:08
  • It looks like you're trying to open a new explorer window every 150 seconds (assuming the service is marked as "allow desktop interaction). If this is all your service does, you would better off setting up a scheduler task to do this. – Ferruccio Feb 21 '11 at 14:25

7 Answers7

7

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.

Ian Goldby
  • 5,609
  • 1
  • 45
  • 81
  • @Dims So either the service crashes before it begins executing your code (where you put the DebugBreak()), or you are mistaken about which part of your code is executed first. First, confirm that DebugBreak() works for you as the first line of a very simple console executable. (You might not have JIT debugging configured.) Once that's working, try the service again. If you are certain that the very first piece of your own code to execute is the DebugBreak() and it's still not entering the debugger then it means that it is crashing in the service framework. Get a new framework. – Ian Goldby Sep 09 '20 at 08:21
4

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.

Ferruccio
  • 98,941
  • 38
  • 226
  • 299
3

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 );
Praveen Patel
  • 429
  • 4
  • 11
  • Worked great. Note I had to run VS 2022 as Administrator for the Debug -> Attach to Process menu option to "see" my Windows Service. Thanks, Praveen. – buzz3791 May 26 '22 at 18:18
  • Please consider contributing your answer to https://learn.microsoft.com/en-US/windows/win32/services/debugging-a-service – buzz3791 May 26 '22 at 18:28
0

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.");

   //...
}
AudioDroid
  • 2,292
  • 2
  • 20
  • 31
0

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.

Community
  • 1
  • 1
the_mandrill
  • 29,792
  • 6
  • 64
  • 93
-1

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..

deepak_
  • 1
  • 2
-1

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).

OJ.
  • 28,944
  • 5
  • 56
  • 71