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?
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 SetServiceState
method.
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
User contributions licensed under CC BY-SA 3.0