我已经尝试使用https://msdn.microsoft.com/en-us/library/windows/desktop/bb540475(v=vs.85).aspx中描述的StartServiceCtrlDispatcher(),除了参数不会传递给SvcMain之外它还可以。我可以使用StartService()来解决这个问题吗?除了StartService()似乎需要的额外代码之外,还有其他任何区别 - 在这两种启动服务的方法之间吗?
答案 0 :(得分:5)
这是服务的开始方式:
首先,某些进程必须调用StartService()来告诉服务控制管理器(SCM)应该启动该服务。这可能是Windows本身(如果服务配置为自动启动或启动依赖服务),或者它可能是服务管理工具,net start
命令或应用程序。
无论哪个进程调用StartService都可以为服务设置参数。这些参数最终将传递给ServiceMain()。注意:这些参数从不传递给main()。
如果是调用StartService的Windows,则不传递任何参数。
SCM运行服务应用程序命令,该命令是在创建服务时设置的。这是CreateService()调用的lpBinaryPathName
参数,如果您使用binpath
命令,也称为sc create
。
如果命令包含命令行参数,则以通常的方式将它们传递给main()。注意:这些参数从不传递给ServiceMain()。
主函数必须调用StartServiceCtrlDispatcher()来运行服务控制调度程序,它提供SCM和服务进程之间的连接。如果应用程序没有调用StartServiceCtrlDispatcher(),则会得到“服务未及时响应启动或控制请求”。错误。
服务控制调度程序根据SCM的指令,使用调用StartService()设置的参数调用ServiceMain()。
ServiceMain()或由它启动的线程然后执行实际工作,包括在必要时通知SCM服务的状态。
您会注意到有两组不同的参数:
由StartService()设置的参数传递给ServiceMain()。
CreateService()或ChangeServiceConfig()设置的参数,传递给main()。
这些用途不同。如果在安装服务时需要配置某些内容,可以使用main()的参数。如果需要在启动服务时配置某些内容,则可以使用ServiceMain()的参数。或者你当然可以做到这两点;只是不要让他们困惑!
通常,ServiceMain()参数仅供旨在与传统应用程序协同工作的服务使用,并且由该应用程序启动。
请注意,main()不能通过调用StartService()来更改传递给ServiceMain()的参数,原因至少有两个:首先,它已经太晚了,因为启动请求已经被处理,所以参数是已经设定;第二,在服务初始化期间,SCM数据库被锁定,因此尝试调用StartService()将导致死锁。
(如果Windows为我们提供了一些配置默认参数或覆盖指定参数的方法会很好。但是在这种情况下确实没有任何理由不使用全局变量:应用程序的命令行是对应用程序本身全局,因此使用全局变量在哲学上是合理的。)
Nitpickers corner:事实上,当服务配置为自动启动或必须启动服务依赖时,Windows可能不会直接调用StartService; SCM更可能调用等效的内部函数。但结果是一样的。