从C开始使用StartServiceCtrlDispatcher和StartService的Windows服务有什么区别?

我试图使用StartServiceCtrlDispatcher()中所述的https://msdn.microsoft.com/en-us/library/windows/desktop/bb540475(v=vs.85).aspx ,它的工作原理除了参数没有传递给SvcMain。 我可以使用StartService()来解决这个问题吗? 除了StartService()似乎需要的其他代码之外,还有其他什么区别 – 在这两种启动服务的方法之间?

这是一个服务如何开始:

  • 首先,一些进程必须调用StartService()来告诉服务控制管理器(SCM)该服务应该启动。 这可能是Windows本身(如果服务配置为自动启动或启动依赖服务),也可能是服务管理工具, net start命令或应用程序。

    无论哪个进程调用StartService都可以为该服务设置参数。 这些参数最终将被传递给ServiceMain()。 注意:这些参数永远不会传递给main()。

    如果是Windows,则调用StartService,不传递参数。

  • SCM运行创建服务时设置的服务应用程序命令。 这是CreateService()调用的lpBinaryPathName参数,如果使用sc create命令,也称为binpath

    如果该命令包含命令行参数,则以通常的方式将这些参数传递给main()。 注意:这些参数永远不会传递给ServiceMain()。

  • 主函数必须调用StartServiceCtrlDispatcher()来运行服务控制调度器,它提供了SCM和服务进程之间的连接。 如果应用程序不调用StartServiceCtrlDispatcher(),则会得到“该服务未及时响应启动或控制请求”。 错误。

  • 服务控制调度程序根据来自SCM的指令调用ServiceMain(),并使用由StartService()调用设置的参数。

  • ServiceMain()或由它启动的线程将执行实际的工作,包括通知SCM服务的状态。

您会注意到有两组不同的参数:

  • 由StartService()传递给ServiceMain()的参数。

  • 由传递给main()的CreateService()或ChangeServiceConfig()设置的参数。

这些服务不同的目的。 如果您需要在安装服务时配置某些内容,则可以使用main()的参数。 如果您需要在服务启动时配置某些内容,则可以使用ServiceMain()的参数。 或者当然你也可以做; 只是不要让他们困惑!

通常,ServiceMain()参数仅用于与传统应用程序协同工作的服务,并由该应用程序启动。

请注意,main()不能通过调用StartService()来传递给ServiceMain()的参数,至少有两个原因:首先,已经太迟了,因为已经处理了启动请求,所以参数已经设置好了。 其次,在服务初始化期间SCM数据库被锁定,所以试图调用StartService()将导致死锁。

(如果Windows给了我们一些配置默认参数或重写指定参数的方法,那将是非常好的,但是在这个上下文中没有任何理由不使用全局变量:应用程序的命令行本身就是应用程序的全局变量所以使用全局变量在哲学上是合理的。)


Nitpickers corner:事实上,当服务配置为自动启动或必须启动服务依赖关系时,Windows可能不会真正地调用StartService; SCM更可能调用等效的内部函数。 但结果是一样的。