C# “服务导致SCM错误”;报告了无效的当前状态0“;

C# “服务导致SCM错误”;报告了无效的当前状态0“;,c#,.net,service,C#,.net,Service,我编写了一个小型服务,它充当本地网络服务器。为了编写服务,我遵循了一个,如何使用ServiceBase类编写服务 但是,当我注册并启动服务时,会收到如下所示的错误消息。在开始和服务停止时,我正好收到其中两条错误消息。(示例=服务名称) 示例服务报告了无效的当前状态0 这里是我的服务和所有相关部分的最小样本。代码以MSDN教程中提供的枚举和结构定义开始: public enum ServiceState { SERVICE_STOPPED = 0x00000001, SERVICE

我编写了一个小型服务,它充当本地网络服务器。为了编写服务,我遵循了一个,如何使用
ServiceBase
类编写服务

但是,当我注册并启动服务时,会收到如下所示的错误消息。在开始和服务停止时,我正好收到其中两条错误消息。(示例=服务名称)

示例服务报告了无效的当前状态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您仍然在使用
服务\u START\u PENDING
,并且还需要几秒钟),则可能需要此选项。通常,您会在
OnStart
中启动一个线程并尽快返回

在过去的几年里,我用C#编写了许多服务,但从未需要过

但是-我在MSDN示例代码中发现了一个bug(我自己测试了您的代码)

ServiceStatus
struct中,将long替换为int或(更好的单位)。如果使用uint,还必须在
SetServiceState
方法中更改此选项

另见

如果您对如何在C#中启动Windows服务并进行其他设置感兴趣,可以查看我的博客:

[更新2018-01-20]

我写了一篇关于这方面的新文章,它使用了自安装方法,它的优点是(至少对我来说),它不需要VisualStudio的安装项目扩展


太好了,谢谢,这解决了问题。我通常知道MSDN文档有多糟糕,但在这里我只是假设示例中的结构定义是正确的。你也是对的,手动状态更新并不是真的必要。在第一个版本中,代码的启动花费了很长时间,但我将所有内容都移动到了一个线程中,因为这些长过程的结果与启动无关。很棒的博客条目,只是一步一步列表的格式几乎让我头疼;-)。太好了,对我有用。无法计算MSDN有多少错误。。。。这是其中的一个无限数…非常感谢,雷纳-我使用微软的示例代码创建了一个服务,并直接解决了这个问题。我还在他们的页面中添加了一条注释()指向您的解决方案。