Service Causes SCM Error "reported an invalid current state 0"

6

I wrote a small service, which acts as a local network server. To write the service, I followed a tutorial on MSDN, how to write a service using the ServiceBase class.

But when I register and start the service, I get error messages as shown below. I get exactly two of these error messages at the start and at the service stop. (Example = name of service).

The Example service has reported an invalid current state 0.

Here a minimal sample of my service with all relevant parts. The code starts with an enum and struct definition which was provided in the MSDN tutorial:

public enum ServiceState
{
    SERVICE_STOPPED = 0x00000001,
    SERVICE_START_PENDING = 0x00000002,
    SERVICE_STOP_PENDING = 0x00000003,
    SERVICE_RUNNING = 0x00000004,
    SERVICE_CONTINUE_PENDING = 0x00000005,
    SERVICE_PAUSE_PENDING = 0x00000006,
    SERVICE_PAUSED = 0x00000007,
}

[StructLayout(LayoutKind.Sequential)]
public struct ServiceStatus
{
    public long dwServiceType;
    public ServiceState dwCurrentState;
    public long dwControlsAccepted;
    public long dwWin32ExitCode;
    public long dwServiceSpecificExitCode;
    public long dwCheckPoint;
    public long dwWaitHint;
};

After this, the service code I wrote, reduced to the relevant parts:

namespace example
{
    public partial class Service : ServiceBase
    {
        public Service()
            : base()
        {
            this.ServiceName = "ExampleService";
            this.AutoLog = false;
            this.CanStop = true;
            this.CanShutdown = false;
            this.CanPauseAndContinue = false;
            this.CanHandlePowerEvent = false;
            this.CanHandleSessionChangeEvent = false;
        }

        protected override void OnStart(string[] args)
        {
            try {
                SetServiceState(ServiceState.SERVICE_START_PENDING, 100000);
                // ... initialise and start...
                SetServiceState(ServiceState.SERVICE_RUNNING);
            } catch (System.Exception ex) {
                SetServiceState(ServiceState.SERVICE_STOPPED);
            }
        }

        protected override void OnStop()
        {
            SetServiceState(ServiceState.SERVICE_STOP_PENDING, 100000);
            // ... stop service ... 
            SetServiceState(ServiceState.SERVICE_STOPPED);
        }

        private void SetServiceState(ServiceState state, int waitHint = 0)
        {
            ServiceStatus serviceStatus = new ServiceStatus();
            serviceStatus.dwCurrentState = state;
            serviceStatus.dwWaitHint = waitHint;
            SetServiceStatus(this.ServiceHandle, ref serviceStatus);
        }

        [DllImport("advapi32.dll", SetLastError=true)]
        private static extern bool SetServiceStatus(IntPtr handle, ref ServiceStatus serviceStatus);
    }
}

The main entry point is simple as this:

static void Main(string[] args)
{
    ServiceBase.Run(new Service());
}

As you can see, the number of error messages matches the number of SetServiceState calls. If I add additional such calls, the number of error messages increases accordingly.

So I assume, the whole problem is somewhere in the way I call the SetServiceStatus API, but I currently can't see the problem.

Can you spot the Problem?

Anyway is this the correct way to build a Service using C# and .NET?

c#
.net
service
asked on Stack Overflow May 18, 2015 by Flovdis • edited May 18, 2015 by Owen Pauling

1 Answer

14

First:

It is normally not necessary to call the SetServiceState method. It may be needed if your service really takes a long time to initialize (where you can tell the SCM you are still alive with SERVICE_START_PENDING and need a few more seconds) . Normally, you start a thread in OnStart and return asap.

I have written many services in C# the last years and never needed this.

But - I found a bug in the MSDN sample code (I tested your code myself).

In the ServiceStatus struct replace long with int or (better unit). If you use uint, you also have to change this in SetServiceStatemethod.

Also see Should DWORD map to int or uint?.

If you are interested in a small introduction how you can start with a Windows service in C# with an additional setup, you can check my blog entry:

http://www.rsprog.de/samplewindowsservice/

[Update 2018-01-20]

I created a new article about that, which uses the self-installation method which has the advantage (at least for me), that it does not need the setup project extension of Visual Studio

http://www.rsprog.de/windowsserviceselfinstall/

answered on Stack Overflow May 18, 2015 by Rainer Schaack • edited Jan 20, 2018 by Rainer Schaack

User contributions licensed under CC BY-SA 3.0