What is the difference between starting a Windows

2019-06-02 03:14发布

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?

1条回答
祖国的老花朵
2楼-- · 2019-06-02 03:38

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.

查看更多
登录 后发表回答