服务导致 SCM 错误 "reported an invalid current state 0"
Service Causes SCM Error "reported an invalid current state 0"
我写了一个小服务,充当本地网络服务器。写服务,我遵循了tutorial on MSDN,如何使用ServiceBase
写服务class。
但是当我注册并启动服务时,我收到如下所示的错误消息。我在开始和服务停止时收到了两条这样的错误消息。 (示例 = 服务名称)。
The Example service has reported an invalid current state 0.
这里是我的服务的最小样本,包含所有相关部分。代码以 MSDN 教程中提供的枚举和结构定义开头:
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;
};
在此之后,我写的服务代码,缩减为相关部分:
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);
}
}
主要入口点很简单:
static void Main(string[] args)
{
ServiceBase.Run(new Service());
}
如您所见,错误消息的数量与 SetServiceState
调用的数量相匹配。如果我添加额外的此类调用,错误消息的数量会相应增加。
所以我假设,整个问题出在我调用 SetServiceStatus
API 的方式中,但我目前看不到问题。
你能找出问题所在吗?
无论如何,这是使用 C# 和 .NET 构建服务的正确方法吗?
第一个:
通常不需要调用SetServiceState
方法。如果你的服务真的需要很长时间来初始化(你可以告诉 SCM 你还活着 SERVICE_START_PENDING
并且需要几秒钟),它可能是需要的。通常,您会尽快在 OnStart
和 return 中启动一个线程。
过去几年我用 C# 编写了很多服务,但从来不需要这个。
但是 - 我在 MSDN 示例代码中发现了一个错误(我自己测试了你的代码)。
在 ServiceStatus
结构中用 int 或(更好的单位)替换 long。如果您使用 uint,您还必须在 SetServiceState
方法中更改它。
另见 Should DWORD map to int or uint?。
如果您对如何通过额外设置在 C# 中开始使用 Windows 服务的简短介绍感兴趣,可以查看我的博客条目:
http://www.rsprog.de/samplewindowsservice/
[2018-01-20更新]
我写了一篇关于它的新文章,它使用了自安装方法,它的优点是(至少对我而言),它不需要 Visual Studio[=18= 的安装项目扩展]
我写了一个小服务,充当本地网络服务器。写服务,我遵循了tutorial on MSDN,如何使用ServiceBase
写服务class。
但是当我注册并启动服务时,我收到如下所示的错误消息。我在开始和服务停止时收到了两条这样的错误消息。 (示例 = 服务名称)。
The Example service has reported an invalid current state 0.
这里是我的服务的最小样本,包含所有相关部分。代码以 MSDN 教程中提供的枚举和结构定义开头:
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;
};
在此之后,我写的服务代码,缩减为相关部分:
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);
}
}
主要入口点很简单:
static void Main(string[] args)
{
ServiceBase.Run(new Service());
}
如您所见,错误消息的数量与 SetServiceState
调用的数量相匹配。如果我添加额外的此类调用,错误消息的数量会相应增加。
所以我假设,整个问题出在我调用 SetServiceStatus
API 的方式中,但我目前看不到问题。
你能找出问题所在吗?
无论如何,这是使用 C# 和 .NET 构建服务的正确方法吗?
第一个:
通常不需要调用SetServiceState
方法。如果你的服务真的需要很长时间来初始化(你可以告诉 SCM 你还活着 SERVICE_START_PENDING
并且需要几秒钟),它可能是需要的。通常,您会尽快在 OnStart
和 return 中启动一个线程。
过去几年我用 C# 编写了很多服务,但从来不需要这个。
但是 - 我在 MSDN 示例代码中发现了一个错误(我自己测试了你的代码)。
在 ServiceStatus
结构中用 int 或(更好的单位)替换 long。如果您使用 uint,您还必须在 SetServiceState
方法中更改它。
另见 Should DWORD map to int or uint?。
如果您对如何通过额外设置在 C# 中开始使用 Windows 服务的简短介绍感兴趣,可以查看我的博客条目:
http://www.rsprog.de/samplewindowsservice/
[2018-01-20更新]
我写了一篇关于它的新文章,它使用了自安装方法,它的优点是(至少对我而言),它不需要 Visual Studio[=18= 的安装项目扩展]