What is the difference between starting a Windows service with C using StartServiceCtrlDispatcher vs StartService?

I tried using StartServiceCtrlDispatcher () as described in https://msdn.microsoft.com/en-us/library/windows/desktop/bb540475(v=vs.85).aspx and it works, except that arguments are not passed to SvcMain. Can I use StartService () to solve this problem? Is there any other difference - apart from the extra code that apparently requires StartService () - between the two approaches to starting the service?

0
source share
1 answer

Here's how the service starts:

  • First, some process must call StartService () to tell the Service Control Manager (SCM) that the service should be started. This can be Windows OS itself (if the service is configured to start automatically or to start a dependent service), or it can be a service administration tool, a net start command, or an application.

    Regardless of which process calls StartService, arguments can be specified for the service. These arguments will be passed to ServiceMain (). Note. These arguments are never passed to main ().

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

  • SCM runs the service application command that was installed when the service was created. This is the lpBinaryPathName argument for calling CreateService (), also known as binpath , if you use the sc create command.

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

  • The main function should call StartServiceCtrlDispatcher () to start the service control manager, which provides the connection between SCM and the service process. If the application does not call StartServiceCtrlDispatcher (), you get the message "The service did not respond to the start or control request in a timely manner." error.

  • The service control manager, following the SCM instructions, calls ServiceMain () with the arguments set by the StartService () call.

  • The ServiceMain () or the threads launched by it then do the actual work, including informing SCM about the status of the service as needed.

You will notice that there are two different sets of arguments:

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

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

They serve for different purposes. If you need to configure something when the service is installed, you can use the arguments for main (). If you need to configure something when the service is running, you can use the arguments in ServiceMain (). Or, of course, you can do both; just don't confuse them!

Typically, ServiceMain () arguments are used only by services that are designed to be run by a regular application and run by that application.

Please note: main () cannot change the arguments passed to ServiceMain () by calling StartService () for at least two reasons: firstly, it is too late because the start request has already been processed, therefore the arguments are already set; secondly, during the initialization of the service, the SCM database is locked, so an attempt to call StartService () will cause a deadlock.

(It would be nice if Windows gave us some way to configure the default arguments or override the specified arguments. But in this context there is no reason not to use global variables: the application command line is inherently global for the application, so using a global variable sounds philosophical.)


Nitpickers corner: essentially, Windows probably doesnโ€™t literally call StartService when the service is configured to start automatically or when the service dependency should be started; SCM is more likely to call an equivalent internal function. But the result is the same.

+4
source

Source: https://habr.com/ru/post/1264083/


All Articles