使用 StartServiceCtrlDispatcher 和 StartService 从 C 启动 Windows 服务有什么区别? [英] What is the difference between starting a Windows service, from C, using StartServiceCtrlDispatcher vs StartService?

查看:41
本文介绍了使用 StartServiceCtrlDispatcher 和 StartService 从 C 启动 Windows 服务有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已尝试使用 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 的指令,使用 StartService() 调用设置的参数调用 ServiceMain().

  • ServiceMain() 或由它启动的线程然后执行实际工作,包括在必要时通知 SCM 服务的状态.

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

  • StartService() 设置的参数,这些参数传递给 ServiceMain().

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

这些有不同的用途.如果您需要在安装服务时配置一些东西,您可以使用 main() 的参数.如果你需要在服务启动时配置一些东西,你可以使用 ServiceMain() 的参数.或者你当然可以两者兼而有之;只是不要让他们感到困惑!

通常,ServiceMain() 参数仅由旨在与传统应用程序协同工作且由该应用程序启动的服务使用.

请注意,main() 不能通过调用 StartService() 来更改传递给 ServiceMain() 的参数,至少有两个原因:首先,为时已晚,因为启动请求已被处理,因此参数是已经设置;其次,在服务初始化期间,SCM数据库被锁定,因此尝试调用StartService()会导致死锁.

(如果 Windows 给了我们一些方法来配置默认参数或覆盖指定的参数,那就太好了.但确实没有任何理由在这种情况下不使用全局变量:应用程序的命令行是 固有对于应用程序是全局的,因此使用全局变量在哲学上是合理的.)

<小时>

Nitpickers 角:事实上,当服务配置为自动启动或必须启动服务依赖项时,Windows 可能不会直接调用 StartService;SCM 更有可能调用等效的内部函数.但结果是一样的.

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. Can I use StartService() to overcome this problem? Is there any other difference-- other than the additional code that StartService() seems to require-- between these two approaches to starting a service?

解决方案

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. 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.

    Whichever process calls StartService can set arguments for the service. These arguments will eventually be passed to ServiceMain(). Note: these arguments are never passed to main().

    If it is Windows that calls StartService, no arguments are passed.

  • The SCM runs the service application command, which was set when the service was created. This is the lpBinaryPathName argument to the CreateService() call, also known as binpath if you are using the sc create command.

    If the command contains command-line arguments, these are passed to main() in the usual way. Note: these arguments are never passed to ServiceMain().

  • The main function must call StartServiceCtrlDispatcher() to run the service control dispatcher, which provides the connection between the SCM and the service process. 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." error.

  • The service control dispatcher, acting on instructions from the SCM, calls ServiceMain() with the arguments set by the call to StartService().

  • ServiceMain() or threads launched by it then do the actual work, including informing the SCM of the service's status as necessary.

You will notice there are two distinct sets of arguments:

  • The arguments set by StartService() which are passed to ServiceMain().

  • The arguments set by CreateService() or ChangeServiceConfig(), which are passed to main().

These serve different purposes. If you need to configure something when the service is installed, you can use the arguments to main(). If you need to configure something when the service is started, you can use the arguments to 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.

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; and secondly, during initialization of a service the SCM database is locked, so attempting to call StartService() will cause a deadlock.

(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.)


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; it is more likely that the SCM calls an equivalent internal function. But the upshot is the same.

这篇关于使用 StartServiceCtrlDispatcher 和 StartService 从 C 启动 Windows 服务有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆