- Создание сервисов для Windows NT
- Создание сервиса
- Создание сервиса
- Функция main()
- Функция ServiceMain()
- Функция ServiceControl()
- Функция SetSomeServiceStatus()
- Функции InitSomeServiceData() и StopSomeService()
- Приложение, управляющее сервисом
- Функция WndProc()
- Функция WndProcOnCommand()
- Функции WndProcOnDestroy() и GetSomeSvcError()
- Разработка приложений службы Windows Develop Windows service apps
- Содержание раздела In this section
- Связанные разделы Related sections
- Создание службы в Windows 10
- Создание службы с помощью программы Sc.exe
- С помощью утилиты PowerShell
Создание сервисов для Windows NT
Создание сервиса
Приложение, управляющее сервисом Код, описанный в этой статье, работает только в Windows NT / 2000 / XP, поскольку Windows 98 не поддерживает работу с сервисами.
Создание сервиса
Как правило сервис представляет собой консольное приложение, поэтому программа должна содержать функцию main().
Сначала объявим глобальные переменные:
Функция main()
Здесь мы создаем таблицу точек входа сервиса.
Структура типа SERVICE_TABLE_ENTRY позволяет задать функцию ServiceMain() для сервиса, носящего указанное в структуре имя.
Функция StartServiceCtrlDispatcher() связывает главный поток сервиса с менеджером сервисов (service control manager, SCM).
Когда SCM запускает сервис, он ожидает выполнения сервисом функции StartServiceCtrlDispatcher(). Главный поток сервиса должен вызвать эту функцию как можно быстрее. Если функция выполняется успешно, она связывает вызывающий ее поток с SCM и не завершается, пока не будет остановлен сервис. SCM использует это соединение, чтобы посылать сервису управляющие запросы.
Если сервис запускается как отдельный процесс (как, например, в нашем случае), он должен вызвать функцию StartServiceCtrlDispatcher() немедленно. Поэтому всю инициализацию следует делать позже, в функции ServiceMain(). Если в рамках одного процесса запускается несколько сервисов, главный поток должен вызвать функцию StartServiceCtrlDispatcher() не позднее, чем через 30 секунд.
Функция ServiceMain()
Функция ServiceMain() определяется процессом в качестве точки входа для данного сервиса. Эта функция может носить любое имя, заданное приложением.
Аргументы функции ServiceMain() (аналогичны аргументам функции main()): dwArgc — количество аргументов, lpszArgv — указатель на массив, который содержит указатели на строковые аргументы функции.
Функция RegisterServiceCtrlHandler() регистрирует функцию, которая будет обрабатывать управляющие запросы к сервису (такие, например, как остановка сервиса). В случае успешного завершения функция возвращает дескриптор статуса сервиса (service status handle). При неудачном завершении функция возвращает нулевое значение.
Поле dwServiceType структуры ss устанавливаем в SERVICE_WIN32_OWN_PROCESS. Это означает, что сервис будет выполняться как отдельный процесс, т.е. будет иметь собственное адресное пространство.
Затем устанавливаем состояние ожидания запуска сервиса c помощью созданной нами вспомогательной функции SetSomeServiceStatus(). Эта функция изменяет содержимое структуры ss, которое использует SCM для получения информации о сервисе.
Далее можно выполнить всю необходимую инициализацию для сервиса (определяемая пользователем функция InitSomeServiceData()).
Когда инициализация выполнена, вызываем функцию SetSomeServiceStatus() с параметром SERVICE_RUNNING, чтобы установить состояние работающего сервиса.
После изменения состояния сервиса выполняется основной код программы.
Функция ServiceControl()
Эта функция является управляющей функцией сервиса и может носить любое имя, определенное приложением.
С помощью функции SetSomeServiceStatus() мы устанавливаем состояние ожидания остановки сервиса, после чего можно вызвать определяемую пользователем функцию StopSomeService(), которая выполнит все необходимые действия перед остановкой сервиса. Содержимое этой функции зависит от конкретного сервиса.
Далее с помощью функции SetSomeServiceStatus() сообщаем SCM, что сервис остановлен.
Когда сервис получает команду SERVICE_CONTROL_INTERROGATE, это означает, что он должен немедленно обновить информацию о статусе сервиса, используемую SCM.
Функция SetSomeServiceStatus()
Эта функция изменяет содержимое структуры ss, которое использует SCM для получения информации о статусе сервиса.
Значение поля dwCheckPoint следует периодически изменять во время длительного запуска или остановки. Например, если при запуске сервиса инициализация выполняется в несколько этапов, то нужно увеличивать значение dwCheckPoint после каждого этапа. При этом программа, которая запросила услуги сервиса, может узнать, какой объем работы уже выполнен сервисом. Поле dwCheckPoint должно быть равно нулю, когда сервис не находится в состоянии запуска, остановки или выполнения длительной операции.
Поле dwControlsAccepted определяет управляющий код, который может принимать и обрабатывать данный сервис. По умолчанию все сервисы могут принимать команду SERVICE_CONTROL_INTERROGATE. Если это поле имеет значение SERVICE_ACCEPT_STOP, то сервис может быть остановлен с помощью команды SERVICE_CONTROL_STOP.
Функции InitSomeServiceData() и StopSomeService()
С помощью этих функций проводится инициализация, необходимая для данного сервиса, а также действия, которые необходимо выполнить перед остановкой сервиса. Содержимое этих функций зависит от конкретного сервиса.
Приложение, управляющее сервисом
Приложение SomeSrvcApp может инсталлировать сервис в систему, запускать и останавливать его, получать информацию о сервисе и удалять сервис из системы.
Здесь не будут описываться функции WinMain() и InitApp(), поскольку они не обладают никакими особенностями, заслуживающими внимания. Функция WinMain() создает главное окно с шестью кнопками: «Install Service», «Start Service», «Get Service Configuration», «Stop Service», «Remove Service» и «Exit».
Функция WndProc()
В функции WndProc() используются макросы для обработки сообщений WM_COMMAND и WM_DESTROY:
Функция WndProcOnCommand()
Функция WndProcOnCommand() вызывается функцией WndProc(), если окно получает сообщение WM_COMMAND. Функция WndProcOnCommand() содержит код, выполняющийся при нажатии на кнопки главного окна приложения.
Приведем полностью код этой функции:
Здесь мы отрываем базу данных Service Control Manager (SCM) с помощью функции OpenSCManager() с уровнем доступа SC_MANAGER_CREATE_SERVICE, который позволяет создавать сервисы.
Для создания сервиса используется функция CreateService(), которая возвращает дескриптор созданного сервиса или NULL в случае неудачного выполнения. Одним из параметров функции является путь к сервису, который должен соответствовать расположению сервиса в Вашем компьютере. Проследите, чтобы путь был указан правильно, иначе создать сервис не получится.
В качестве типа сервиса мы указали SERVICE_WIN32_OWN_PROCESS. Это означает, что сервис будет выполняться как отдельный процесс. При успешном завершении функция CreateService() добавляет сервис в базу данных SCM. Вы можете в этом убедиться, открыв системную панель управления сервисами (Панель управления -> Администрирование -> Службы).
Для открытия сервиса мы используем функцию OpenService(). Третьим параметром этой функции является тип доступа к сервису. Указывая тип доступа SERVICE_START, мы получаем возможность запускать сервис.
Запуск сервиса осуществляется с помощью функции StartService(), которая возвращает нулевое значение, если запустить сервис не удалось.
На этот раз, открывая сервис, мы указываем тип доступа SERVICE_QUERY_CONFIG, чтобы получить информацию о конфигурации сервиса. Эту информацию мы помещаем в структуру типа QUERY_SERVICE_CONFIG (через указатель на эту структуру lpBufConfig, используя динамически выделяемую память) с помощью функции QueryServiceConfig(). Функция QueryServiceConfig() помещает в структуру типа QUERY_SERVICE_CONFIG информацию о сервисе, которая находится в реестре. Эта информация была помещена в реестр функцией CreateService().
Далее мы помещаем содержимое некоторых полей структуры в буфер szBufConfig и выводим его содержимое с помощью функции MessageBox().
Здесь мы открываем сервис, используя уровень доступа SERVICE_STOP.
Для остановки сервиса используется функция ControlService(). Эта функция посылает сервису управляющий код, который она получает в качестве второго параметра. В нашем случае управляющий код равен константе SERVICE_CONTROL_STOP. Третьим параметром функции является адрес структуры типа SERVICE_STATUS, в которой содержится информация о текущем статусе сервиса. Содержимое этой структуры использует SCM. Если сервис остановить не удалось функция ControlService() возвращает нулевое значение.
В этом случае, открывая сервис, мы используем комбинацию флагов SERVICE_STOP и DELETE, поскольку если сервис в данный момент работает, то прежде чем его удалять из системы, его необходимо остановить. Для удаления сервиса из системы используется функция DeleteService().
Функции WndProcOnDestroy() и GetSomeSvcError()
Приведем код функции WndProcOnDestroy() и функции GetSomeSvcError(), которая используется для вывода сообщений об ошибках:
В функции GetSomeSvcError() анализируется код ошибки, полученный с помощью функции Win API GetLastError(). Полный список кодов ошибок и их значений можно посмотреть в файле WinError.h или в документации по Win API.
Разработка приложений службы Windows Develop Windows service apps
С помощью Visual Studio или пакета SDK для .NET Framework можно легко создавать службы. Просто создайте приложение, которое устанавливается как служба. Using Visual Studio or the .NET Framework SDK, you can easily create services by creating an application that is installed as a service. Такие приложения называются службами Windows. This type of application is called a Windows service. Используя компоненты платформы, можно создавать, устанавливать, запускать, останавливать и администрировать службы. With framework features, you can create services, install them, and start, stop, and otherwise control their behavior.
В Visual Studio можно создать службы с помощью управляемого кода на Visual C# или Visual Basic, который при необходимости может взаимодействовать с существующим кодом C++. In Visual Studio you can create a service in managed code in Visual C# or Visual Basic, which can interoperate with existing C++ code if required. Или можно создать службу Windows на машинном языке C++ с помощью мастера проектов ATL. Or, you can create a Windows service in native C++ by using the ATL Project Wizard.
Содержание раздела In this section
Сведения о приложениях служб Windows, времени существования служб и отличиях приложений служб от распространенных типов проектов. Provides an overview of Windows service applications, the lifetime of a service, and how service applications differ from other common project types.
Пример создания службы на Visual Basic и Visual C#. Provides an example of creating a service in Visual Basic and Visual C#.
Описание элементов языка, используемых при создании служб. Explains the language elements used in service programming.
Создание и настройка служб Windows с помощью шаблона проекта службы Windows. Describes the process of creating and configuring Windows services using the Windows service project template.
Связанные разделы Related sections
ServiceBase — описываются основные характеристики класса ServiceBase, который используется для создания служб. ServiceBase — Describes the major features of the ServiceBase class, which is used to create services.
ServiceProcessInstaller — описываются возможности класса ServiceProcessInstaller, который используется вместе с классом ServiceInstaller для установки и удаления службы. ServiceProcessInstaller — Describes the features of the ServiceProcessInstaller class, which is used along with the ServiceInstaller class to install and uninstall your services.
ServiceInstaller — описываются возможности класса ServiceInstaller, который используется вместе с классом ServiceProcessInstaller для установки и удаления службы. ServiceInstaller — Describes the features of the ServiceInstaller class, which is used along with the ServiceProcessInstaller class to install and uninstall your service.
Create Projects from Templates (Создание проектов на основе шаблонов) — описываются типы проектов, которые используются в этом разделе, и способ их выбора. Create Projects from Templates — Describes the projects types used in this chapter and how to choose between them.
Создание службы в Windows 10
Бывает, что имеется некий исполняемый файл, который необходимо зарегистрировать в системе как службу Windows 10. Существует множество различных способов, которые позволяют это сделать. Сейчас мы рассмотрим два основных и проверенных метода создания службы Windows.
Создание службы с помощью программы Sc.exe
Первый способ позволяет создавать службы, используя утилиты, работающие через командную строку. В данном случае, используется инструмент sc.exe. Он позволяет взаимодействовать с функциями API и выполнять операции со службами Windows 10. Несмотря на то, что данная программа даже не обладает графическим интерфейсом, она является мощным инструментом и может контролировать состояние служб, создавать, редактировать и управлять ими.
Если создавать службу, с помощью sc.exe, то не возникает необходимости в изменении параметров реестра и списка служб в диспетчере. Кроме того, утилита способна работать со службами на локальном компьютере, и выполнять те же действия на удаленных машинах.
Чтобы создать новый сервис, откройте командную строку от имени администратора и запустите команду «Sc create». Она запишет новую службу к базе диспетчера служб. Синтаксис команды представлен следующим образом:
- ServiceName — данным параметром определяется имя раздела службы в реестре;
Данное имя не совпадает с тем именем, которое будет отображаться диспетчере (например, в Services). - BinPath — в этом параметре записываем путь, где хранится исполняемый файл.
Чтобы было понятнее, в качестве примера, мы создадим службу «MySevice». При этом, отображаемое имя будет «My New Service». Указываем тип службы и включаем автозапуск:
Sc create MyService binPath=C:\MyService\MyService.exe DisplayName=″My New Service″ type=own start=auto
Теперь откройте оснастку «Services» и взгляните на то, что получилось:
Параметры службы, которая уже была создана и запущена, можно изменить при помощи команды Sc config. К примеру, мы заменим имя службы, которое отображается как:
Sc config MyService DisplayName=″My Service″
А еще можно избавиться от службы полным ее удалением. Для этого используйте такую команду:
С помощью утилиты PowerShell
Ну а с помощью такого мощного инструмента, как PowerShell можно хоть горы двигать. Он обладает большими возможностями и способен работать с различными службами. Здесь, для добавления новой службы, существует специальная команда «New -Service». Давайте попробуем новую службу, как и в прошлом примере, будем использовать те же имена и значения, только добавим дополнительный параметр, в виде описания. И так, команда, для создания нового сервиса, выглядит следующим образом:
New-Service -Name MyService -BinaryPathName C:\MyService\MyService.exe` -DisplayName ″My New Service″ -Description ″Very Important Service . ″
Для изменения параметров служб, существует команда «Set -Service»:
Set-Service -Name MyService -Description ″Not Very Important Service″ -StartupType Manual
Если не считать дополнительную возможность добавления описаний к службам, PowerShell обладает таким же функционалом, как и утилита Sc.exe. Но есть один маленький минус — здесь нет простой команды для удаления службы. Поэтому приходиться использовать такой вот, немного мудреный, код:
(Get-WmiObject win32_service -Filter ″name=′MyService′″).delete()