简体   繁体   English

使用StartServiceCtrlDispatcher与StartService从C启动Windows服务之间有什么区别?

[英]What is the difference between starting a Windows service, from C, using StartServiceCtrlDispatcher vs StartService?

I've tried to use StartServiceCtrlDispatcher() as described in https://msdn.microsoft.com/en-us/library/windows/desktop/bb540475(v=vs.85).aspx , and it works except that arguments do not get passed to SvcMain. 我尝试按照https://msdn.microsoft.com/zh-cn/library/windows/desktop/bb540475(v=vs.85).aspx中所述使用StartServiceCtrlDispatcher()不传递给SvcMain。 Can I use StartService() to overcome this problem? 我可以使用StartService()来解决此问题吗? Is there any other difference-- other than the additional code that StartService() seems to require-- between these two approaches to starting a service? 这两种启动服务的方法之间,除了StartService()似乎需要的其他代码之外,是否还有其他区别?

This is how a service starts: 服务是这样启动的:

  • First, some process has to call StartService() to tell the Service Control Manager (SCM) that the service should be started. 首先,某些过程必须调用StartService()来告知服务控制管理器(SCM)应该启动该服务。 This might be Windows itself (if the service is configured to start automatically or in order to start a dependent service) or it might be the Service administrative tool, the net start command, or an application. 这可能是Windows本身(如果服务配置为自动启动或为了启动从属服务),也可能是服务管理工具, net start命令或应用程序。

    Whichever process calls StartService can set arguments for the service. 无论哪个进程调用StartService都可以为服务设置参数。 These arguments will eventually be passed to ServiceMain(). 这些参数最终将传递给ServiceMain()。 Note: these arguments are never passed to main(). 注意:这些参数永远不会传递给main()。

    If it is Windows that calls StartService, no arguments are passed. 如果是Windows调用StartService,则不传递任何参数。

  • The SCM runs the service application command, which was set when the service was created. SCM运行服务应用程序命令,该命令是在创建服务时设置的。 This is the lpBinaryPathName argument to the CreateService() call, also known as binpath if you are using the sc create command. 这是CreateService()调用的lpBinaryPathName参数,如果使用sc create命令,则也称为binpath

    If the command contains command-line arguments, these are passed to main() in the usual way. 如果命令包含命令行参数,则以常规方式将其传递给main()。 Note: these arguments are never passed to ServiceMain(). 注意:这些参数永远不会传递给ServiceMain()。

  • The main function must call StartServiceCtrlDispatcher() to run the service control dispatcher, which provides the connection between the SCM and the service process. 主要功能必须调用StartServiceCtrlDispatcher()来运行服务控制调度程序,该调度程序提供SCM与服务进程之间的连接。 If the application doesn't call StartServiceCtrlDispatcher(), you get the "The service did not respond to the start or control request in a timely fashion." 如果应用程序未调用StartServiceCtrlDispatcher(),则会显示“服务未及时响应启动或控制请求。” error. 错误。

  • The service control dispatcher, acting on instructions from the SCM, calls ServiceMain() with the arguments set by the call to StartService(). 服务控制调度程序根据来自SCM的指令,使用通过调用StartService()设置的参数来调用ServiceMain()。

  • ServiceMain() or threads launched by it then do the actual work, including informing the SCM of the service's status as necessary. 然后由它启动的ServiceMain()或线程会进行实际工作,包括根据需要将服务状态通知SCM。

You will notice there are two distinct sets of arguments: 您会注意到有两组不同的参数:

  • The arguments set by StartService() which are passed to ServiceMain(). 由StartService()设置的参数,这些参数传递给ServiceMain()。

  • The arguments set by CreateService() or ChangeServiceConfig(), which are passed to main(). 由CreateService()或ChangeServiceConfig()设置的参数,这些参数将传递给main()。

These serve different purposes. 这些有不同的目的。 If you need to configure something when the service is installed, you can use the arguments to main(). 如果在安装服务时需要配置某些内容,则可以使用main()的参数。 If you need to configure something when the service is started, you can use the arguments to ServiceMain(). 如果在启动服务时需要配置某些内容,则可以使用ServiceMain()的参数。 Or of course you can do both; 或者当然可以两者都做; just don't get them confused! 只是不要让他们感到困惑!

Typically, the ServiceMain() arguments are only used by services that are designed to work in tandem with a conventional application, and which are started by that application. 通常,ServiceMain()参数仅由旨在与常规应用程序协同工作并由该应用程序启动的服务使用。

Note that main() can't change the arguments passed to ServiceMain() by calling StartService(), for at least two reasons: firstly, it's too late, in that the start request has already been processed so the arguments are already set; 请注意,由于至少两个原因,main()无法通过调用StartService()来更改传递给ServiceMain()的参数:首先,为时已晚,因为已经处理了启动请求,因此已经设置了参数; and secondly, during initialization of a service the SCM database is locked, so attempting to call StartService() will cause a deadlock. 其次,在服务初始化期间,SCM数据库被锁定,因此尝试调用StartService()将导致死锁。

(It would have been nice if Windows had given us some way to configure default arguments or to override the specified arguments. But there really isn't any reason not to use globals in this context: the application's command line is inherently global to the application so using a global variable is philosophically sound.) (如果Windows提供了某种方式来配置默认参数或覆盖指定的参数,那将是很好的选择。但是,在这种情况下,确实没有任何理由不使用全局变量:应用程序的命令行对于应用程序而言是固有的全局变量因此使用全局变量在哲学上是合理的。)


Nitpickers corner: in point of fact, Windows probably does not literally call StartService when a service is configured to start automatically or when a service dependency must be started; Nitpickers的一角:实际上,当将服务配置为自动启动或必须启动服务依赖项时,Windows可能不会从字面上调用StartService。 it is more likely that the SCM calls an equivalent internal function. SCM更有可能调用等效的内部函数。 But the upshot is the same. 但是结果是一样的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM