В чем разница между запуском службы Windows с C, используя StartServiceCtrlDispatcher vs StartService?

Я попытался использовать StartServiceCtrlDispatcher (), как описано в 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 запускает команду приложения-службы, которая была установлена ​​при создании службы. Это аргумент lpBinaryPathName для вызова CreateService (), также известного как binpath если вы используете команду sc create .

    Если команда содержит аргументы командной строки, они передаются main () обычным способом. Примечание. Эти аргументы никогда не передаются в ServiceMain ().

  • Основная функция должна вызвать StartServiceCtrlDispatcher () для запуска диспетчера управления службами, который обеспечивает соединение между SCM и процессом обслуживания. Если приложение не вызывает StartServiceCtrlDispatcher (), вы получаете сообщение «Служба не ответила на запрос запуска или управления своевременно». ошибка.

  • Диспетчер управления службами, действуя по инструкциям SCM, вызывает ServiceMain () с аргументами, установленными вызовом StartService ().

  • ServiceMain () или streamи, запущенные им, затем выполняют фактическую работу, включая информирование SCM о статусе службы по мере необходимости.

Вы заметите, что есть два разных набора аргументов:

  • Аргументы, заданные StartService (), которые передаются в ServiceMain ().

  • Аргументы, заданные CreateService () или ChangeServiceConfig (), которые передаются в main ().

Они служат различным целям. Если вам нужно что-то настроить, когда служба установлена, вы можете использовать аргументы для main (). Если вам нужно что-то настроить, когда служба запущена, вы можете использовать аргументы в ServiceMain (). Или, конечно, вы можете сделать то и другое; просто не путайте их!

Как правило, аргументы ServiceMain () используются только службами, которые предназначены для совместной работы с обычным приложением и которые запускаются этим приложением.

Обратите внимание: main () не может изменить аргументы, переданные ServiceMain (), вызывая StartService () по крайней мере по двум причинам: во-первых, уже слишком поздно, поскольку запрос на запуск уже обработан, поэтому аргументы уже установлены; во-вторых, во время инициализации службы firebase database SCM заблокирована, поэтому попытка вызвать StartService () вызовет тупик.

(Было бы неплохо, если бы Windows дала нам способ настроить аргументы по умолчанию или переопределить указанные аргументы. Но в этом контексте нет причин не использовать глобальные переменные: командная строка приложения по своей сути является глобальной для приложения поэтому использование глобальной переменной философски обосновано).


Угол Nitpickers: по сути, Windows, вероятно, буквально не вызывает StartService, когда служба настроена на автоматический запуск или когда должна быть запущена зависимость службы; более вероятно, что SCM вызывает эквивалентную внутреннюю функцию. Но результат тот же.