Как написать службу для виндовс

Время на прочтение
6 мин

Количество просмотров 61K

Однажды вы задумаетесь, как превратить скрипт или приложение в Windows-службу. Скорее всего, задача окажется не такой уж тривиальной – приложению как минимум потребуется специальный интерфейс для получения команд от системы. А раз есть требования и ограничения, то есть и скрипты, и милые сердцу костылики для преодоления.

Статья будет полезна тем, кто, как и я — «программист не настоящий».

Зачем нужна служба, если есть назначенные задания

В отличие от назначенных заданий служба работает постоянно, запускается при старте ПК и может управляться средствами Windows. А еще регулярно запускаемому скрипту могут понадобиться данные с предыдущего запуска, и может быть полезно получение данных из внешних источников — например, в случае TCP или Web сервера.

Лично мне за последние пять лет приходилось создавать службу три с половиной раза:

  • Потребовалось создать сервис на fail2ban для Windows 2003., который работал с логами FileZilla и Apache, а при подозрении на брутфорс блокировал IP штатными средствами Windows — ipsec.
  • Аналог телнет-сервера для домашних версий Windows. Понадобилось выполнять команды на удаленных рабочих станциях, которые были под управлением Windows 7 Home. По сути, вторая попытка поиграть в службы.
  • Музыкальный проигрыватель для торгового зала под Windows. Задачу по ТЗ можно было решить при помощи mpd и пачки скриптов, но я решил — если уж делать скрипты, то почему бы и не «сваять» проигрыватель самому. За основу взял библиотеку BASS.dll.
  • Когда выбирали веб-сервер с поддержкой загрузки файлов под Windows, одним из вариантов был HFS. Сам по себе работать он не может, поэтому пришлось «запихивать» его в службу. В результате решение не понравилось, и просто установили «тему» Apaxy на web-сервере Apache.

Для создания службы можно использовать взрослые языки программирования вроде C. Но если вы не хотите связываться с Visual Studio, то возьмите готовые утилиты. Существуют платные решения вроде FireDaemon Pro или AlwaysUp, но мы традиционно сосредоточимся на бесплатных.

Способ первый. От Microsoft

Этот уже немолодой механизм состоит из двух компонентов: утилиты instsrv.exe для установки сервиса и srvany.exe — процесса для запуска любых исполняемых файлов. Предположим, что мы создали веб-сервер на PowerShell при помощи модуля Polaris. Скрипт будет предельно прост:

New-PolarisGetRoute -Path '/helloworld' -Scriptblock {
    $Response.Send('Hello World!')
}

Start-Polaris -Port 8080

while($true) {
    Start-Sleep -Milliseconds 10
}


Работа так называемого «сервера».

Теперь попробуем превратить скрипт в службу. Для этого скачаем Windows Resource Kit Tools, где будут наши утилиты. Начнем с того, что установим пустой сервис командой:

instsrv WebServ C:temprktoolssrvany.exe

Где WebServ — имя нашего нового сервиса. При необходимости через оснастку services.msc можно задать пользователя, под которым будет запускаться служба, и разрешить взаимодействие с рабочим столом.

Теперь пропишем путь к нашему скрипту при помощи магии реестра. Параметры службы есть в разделе реестра HKLMSYSTEMCurrentControlSetServicesWebServ. В нем нам нужно добавить новый раздел Parameters и создать там строковый параметр Application, указав в нем путь к исполняемому файлу. В случае скрипта PowerShell он будет выглядеть так:

C:WindowsSystem32WindowsPowerShellv1.0powershell.exe -ExecutionPolicy Bypass -NoProfile -File C:tempPolarisserver.ps1


Настроенная служба.

Можно запустить и радоваться.


Работающая служба.

Однако у этого способа есть недостатки:

  • Утилиты старые, разработаны до изобретения PowerShell, UAC и прочих вещей.
  • Srvany не контролирует работу приложения. Даже если оно выпадет в ошибку, служба продолжит свое дело как ни в чем не бывало.
  • Придется донастраивать и копаться в реестре. Вы же помните, что копаться в реестре небезопасно?

Поэтому перейдем к методу, частично лишенному этих проблем.

Способ второй, почти взрослый

Существует утилита под названием NSSM — Non-Sucking Service Manager, что можно перевести как не-плохой менеджер служб. В отличие от предыдущей, она поддерживается разработчиком, и исходный код опубликован на сайте. Помимо обычного способа, доступна и установка через пакетный менеджер Chocolately.

Создать сервис можно из обычной командной строки, вооружившись документацией на сайте разработчика. Но мы воспользуемся PowerShell. Потому что можем, разумеется.

$nssm = (Get-Command ./nssm).Source
$serviceName = 'WebServ'
$powershell = (Get-Command powershell).Source
$scriptPath = 'C:tempPolarisserver.ps1'
$arguments = '-ExecutionPolicy Bypass -NoProfile -File "{0}"' -f $scriptPath
& $nssm install $serviceName $powershell $arguments
& $nssm status $serviceName
Start-Service $serviceName
Get-Service $serviceName


Установка через PowerShell.

Для разнообразия проверим работу службы не браузером, а тоже через PowerShell командой Invoke-RestMethod.


И вправду работает.

В отличие от srvany, этот метод позволяет перезапускать приложение на старте, перенаправлять stdin и stdout и многое другое. В частности, если не хочется писать команды в командную строку, то достаточно запустить GUI и ввести необходимые параметры через удобный интерфейс.

GUI запускается командой:

nssm.exe install ServiceName


Настроить можно даже приоритет и использование ядер процессора.

Действительно, возможностей куда больше, чем у srvany и ряда других аналогов. Из минусов бросается в глаза недостаточный контроль над всем процессом.

Налицо нехватка «жести». Поэтому я перейду к самому хардкорному методу из всех опробованных.

Способ третий. AutoIT

Поскольку я давний любитель этого скриптового языка, то не смог пройти мимо библиотеки под названием _Services_UDF v4. Она снабжена богатой документацией и примерами, поэтому под спойлером сразу приведу полный текст получившегося скрипта.

Листинг скрипта

Итак, попробуем «завернуть» в нее наш веб-сервис:

#NoTrayIcon
#RequireAdmin
#Region
#AutoIt3Wrapper_Version=Beta
#AutoIt3Wrapper_UseUpx=n
#AutoIt3Wrapper_Compile_Both=y
#AutoIt3Wrapper_UseX64=y
#EndRegion

Dim $MainLog = @ScriptDir & "test_service.log"

#include <services.au3>
#include <WindowsConstants.au3>

$sServiceName="WebServ"

If $cmdline[0] > 0 Then
    Switch $cmdline[1]
        Case "install", "-i", "/i"
            InstallService()
        Case "remove", "-u", "/u", "uninstall"
            RemoveService()
        Case Else
            ConsoleWrite(" - - - Help - - - " & @CRLF)
            ConsoleWrite("params : " & @CRLF)
            ConsoleWrite(" -i : install service" & @CRLF)
            ConsoleWrite(" -u : remove service" & @CRLF)
            ConsoleWrite(" - - - - - - - - " & @CRLF)
            Exit
    EndSwitch
Else
    _Service_init($sServiceName)
    Exit
EndIf

Func _main($iArg, $sArgs)
If Not _Service_ReportStatus($SERVICE_RUNNING, $NO_ERROR, 0) Then
    _Service_ReportStatus($SERVICE_STOPPED, _WinAPI_GetLastError(), 0)
    Exit
EndIf

$bServiceRunning = True
$PID=Run("C:WindowsSystem32WindowsPowerShellv1.0powershell.exe -ExecutionPolicy Bypass -NoProfile -File C:tempPolarisserver.ps1")

While $bServiceRunning
_sleep(1000)
WEnd
ProcessClose($PID)

_Service_ReportStatus($SERVICE_STOP_PENDING, $NO_ERROR, 1000)
DllCallbackFree($tServiceMain)
DllCallbackFree($tServiceCtrl)
_Service_ReportStatus($SERVICE_STOPPED, $NO_ERROR, 0)
DllClose($hAdvapi32_DLL)
DllClose($hKernel32_DLL)
EndFunc

Func _Sleep($delay)
Local $result = DllCall($hKernel32_DLL, "none", "Sleep", "dword", $delay)
EndFunc

Func InstallService()
    #RequireAdmin
    Local $bDebug = True
    If $cmdline[0] > 1 Then
        $sServiceName = $cmdline[2]
    EndIf
    If $bDebug Then ConsoleWrite("InstallService("&$sServiceName &"): Installing service, please wait")
    _Service_Create($sServiceName, $sServiceName, $SERVICE_WIN32_OWN_PROCESS, $SERVICE_AUTO_START, $SERVICE_ERROR_SEVERE, '"' & @ScriptFullPath & '"');,"",False,"","NT AUTHORITYNetworkService")
    If @error Then
        Msgbox("","","InstallService(): Problem installing service, Error number is " & @error & @CRLF & " message : " & _WinAPI_GetLastErrorMessage())
    Else
        If $bDebug Then ConsoleWrite("InstallService(): Installation of service successful")
    EndIf
    Exit
EndFunc

Func RemoveService()
    _Service_Stop($sServiceName)
    _Service_Delete($sServiceName)
    If Not @error Then
    EndIf
    Exit
EndFunc

Func _exit()
    _Service_ReportStatus($SERVICE_STOPPED, $NO_ERROR, 0);
EndFunc

Func StopTimer()
    _Service_ReportStatus($SERVICE_STOP_PENDING, $NO_ERROR, $iServiceCounter)
    $iServiceCounter += -100
EndFunc

Func _Stopping()
    _Service_ReportStatus($SERVICE_STOP_PENDING, $NO_ERROR, 3000)
 EndFunc

Разберу подробнее момент запуска приложения. Он начинается после операции $bServiceRunning = True и превращается в, казалось бы, бесконечный цикл. На самом деле этот процесс прервется, как только служба получит сигнал о завершении — будь то выход из системы или остановка вручную.

Поскольку программа для скрипта является внешней (powershell.exe), то после выхода из цикла нам нужно закончить ее работу с помощью ProcessClose.

Для этого скрипт необходимо скомпилировать в .exe, а затем установить службу, запустив exe с ключом -i.


Оно работает!

Разумеется, этот способ не самый удобный, и все дополнительные возможности придется реализовывать самостоятельно, будь то повторный запуск приложения при сбое или ротация логов. Но зато он дает полный контроль над происходящим. Да и сделать в итоге можно куда больше — от уведомления в Telegram о сбое службы до IPC-взаимодействия с другими программами. И вдобавок — на скриптовом языке, без установки и изучения Visual Studio.

Расскажите, а вам приходилось превращать скрипты и приложения в службы?

Как создать службу в WindowsСлужбы в Windows — особые процессы, выполняемые в фоновом режиме, в том числе от учетной записи «СИСТЕМА», которые могут быть запущены в том числе до входа в систему. При желании вы можете создать свою собственную службу, которая будет работать таким же образом.

В этой инструкции подробно о том, как создать службу в Windows 11 или Windows 10 средствами системы, ограничениях методов и одном дополнительном способе заставить работать ваш процесс в качестве службы.

Создание службы в командной строке

Первый способ — использование команды командной строки для создания своей службы, шаги будут следующими:

  1. Запустите командную строку от имени Администратора (способы запуска командной строки от Администратора).
  2. Используйте команду, заменив текстовые описания и пути на свои:
    sc create Имя_службы binPath="C:service-file.exe" DisplayName= "Описание_службы" type=own start=auto
  3. После нажатия Enter вы получите сообщение: CreateService: успех, что означает, что служба была успешно создана. Создание службы в командной строке Windows

В указанной команде используются следующие параметры:

  • binPath — путь к исполняемому файлу службы.
  • DisplayName — отображаемое в списке служб имя службы.
  • start — тип запуска, возможные значения: boot, auto, demand (значение по умолчанию), disabled, delayed-auto
  • type — тип службы, по умолчанию own, возможны другие значения: share (делит исполняемый файл с другими службами), kernel (драйвер), filesys (драйвер файловой системы), interact (интерактивная служба с возможность взаимодействия с пользователем, поддержка этого типа служб прекращается).

После создания службы вы сможете увидеть её в списке служб (Win+Rservices.msc), а автоматический запуск произойдет при следующей перезагрузке системы.

Созданная служба в списке служб Windows

Создание службы в Windows PowerShell

Создать службу можно и в PowerShell, запущенном от имени администратора (или в Терминале Windows). Базовый вариант команды с параметрами по умолчанию:

New-Service -Name "Имя_Службы" -BinaryPathName '"C:путь_к_файлу параметры_запуска"'

Расширенный вариант с указанием описания и типа запуска:

New-Service -Name MyService -BinaryPathName '"C:путь_к_файлу параметры_запуска"' -DisplayName "Имя_службы" -Description "Описание службы" -StarupType "Automatic"

Создание службы в Windows PowerShell

В случае, если выполняется запуск исполняемого файла без параметров, а путь не содержит пробелов, использование кавычек не обязательно, например:

-BinaryPathName C:remontka.exe

При создании служб в PowerShell доступны и ряд дополнительных параметров, описанных в официальной справке на сайте Майкрософт.

Удаление созданной службы

Удалить созданную службы вы можете также в командной строке, запущенной от имени Администратора с помощью команды:

sc delete Имя_службы

Удаление службы в командной строкеИли в Windows PowerShell:

Remove-Service -Name MyService

После выполнения указанных команд созданная вами служба будет удалена из Windows.

Созданная служба не работает, варианты решения

Из описания можно предположить, что любой файл .exe может быть службой, однако, при попытке добавить свои фоновые утилиты и заставить их работать в виде службы рядовые пользователи обычно сталкиваются с ситуацией, когда процесс запускается, а затем закрывается сам. А при запуске службы вручную через некоторое время сообщает, что служба не ответила на запрос своевременно или о других ошибках.

Причина в том, что исполняемые файлы служб — не совсем обычные программы, они, помимо прочего, обмениваются данными с системой. Если ваш EXE не отвечает на соответствующие запросы системы, Windows «делает вывод» о том, что со службой что-то не так.

Как быть, если вы всё-таки настойчиво хотите использовать свой прикладной исполняемый файл в качестве службы?

  • Использовать планировщик заданий и запуск от соответствующего пользователя — это не будет в полной мере службой, но почти то, что нужно.
  • Ранее существовала программа RunAsSvc, позволяющая запускать любые процессы в качестве службы, но для современных ОC он не применима, а разработка была прекращена. Утилита RunAsSvc
  • Использовать инструменты INSTSRV.EXE и SRVANY.EXE из Windows Server 2003 Resource Kit Tools при создании службы Windows.

Создание пользовательской службы с помощью INSTSRV.EXE и SRVANY.EXE

Последний вариант из приведённого выше списка рассмотрим подробнее. Шаги будут следующими:

  1. Загрузите (вероятнее всего, придется найти в Интернете на сторонних сайтах) Windows Server 2003 Resource Kit полностью или только файлы INSTSRV.EXE и SRVANY.EXE, располагаем их у себя на диске, в моем примере путь — C:Windows
  2. В командной строке от имени администратора используйте команду (пути меняем на свои):
    C:Windowsinstsrv.exe Имя_службы C:Windowssrvany.exe

    Создание службы с помощью instsrv и srvany

  3. Если вы получили сообщение о том, что The service was successfully added, всё прошло успешно. Теперь требуется запустить редактор реестра (Win+Rregedit).
  4. В редакторе реестра перейдите по пути
    HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServices

    и найдите раздел с вашим именем службы. Нажимаем по нему правой кнопкой мыши и выбираем пункт «Создать» — «Раздел», задаем имя «Parameters» для раздела.

  5. Выберите созданный раздел, нажмите правой кнопкой мыши в правой панели редактора реестра и создайте новый строковый параметр с именем Application
  6. Дважды нажмите по параметру и в поле «Значение» укажите путь к вашему файлу exe для запуска службы. Путь к исполняемому файлу службы в реестре

Закройте редактор реестра — служба создана, её можно запустить из services.msc или она будет автоматически запущена после перезагрузки компьютера.

Учитывайте, что во всех приведенных примерах служба по умолчанию запускается с учетной записью «СИСТЕМА». В некоторых случаях это может приводить к неправильной работе. В этом случае может иметь смысл зайти в свойства службы в services.msc и изменить параметры на вкладке «Вход в систему».

Создание службы для Windows

Последнее обновление: 16.10.2019

Одним из важнейших компонентов ОС Windows являются службы. Фактически это отдельные приложения, которые не имеют графического интерфейса и
которые выполняют различные задачи в фоновом режиме. Службы могут быть запущены при старте операционной системы, так и в любой другой момент работы пользователя.
Распространенным примером служб являются различные веб-серверы, которые в фоновом режиме прослушивают
определенный порт на наличие подключений, и если подключения имеются, то взаимодействуют с ними. Это могут быть также различные вспомогательные сервисы
обновлений для других установленных программ, которые обращаются к серверу, чтобы узнать, есть ли новая версия приложения. В общем то мы можем
открыть панель служб и сами увидеть все установленные и запущенные службы:

Создание службы Windows в C#

Рассмотрим, как создавать свои службы в C#. В качестве реализуемой задачи выберем наблюдение за изменениями в определенной папке в файловой системе.
Теперь создадим для ее выполнения службу.

Вначале создадим новый проект, который будет иметь тип Windows Service. Назовем проект FileWatcherService:

Проект Windows Service в Visual Studio 2015

После этого Visual Studio генерирует проект, который имеет все необходимое. Хотя в принципе нам необязательно выбирать именно этот тип проекта,
можно было бы создать проект библиотеки классов, и затем в нем определить все необходимые классы.

Итак, новый проект выглядит следующим образом:

Здесь также есть файл Program.cs и есть собственно узел службы Service1.cs.

Служба представляет обычное приложение, но она не запускаетс сама по себе. Все вызовы и обращения к ней проходят через менеджер управления службами
(Service Control Manager или SCM). Когда служба запускается автоматически при старте системы или вручную, то SCM обращается к методу Main в классе Program:

static class Program
{
    static void Main()
    {
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[]
        {
            new Service1()
        };
        ServiceBase.Run(ServicesToRun);
    }
}

Метод Main по умолчанию определен таким образом, чтобы запускать сразу несколько служб, которые определены в массиве ServicesToRun. Однако по умолчанию
проект содержит только одну службу Service1. Сам запуск производится с помощью метода Run: ServiceBase.Run(ServicesToRun).

Сама запускаемая служба представлена узлом Service1.cs. Однако на самом деле
это не простой файл кода. Если мы откроем этот узел, то увидим в нем файл дизайнера службы Service1.Designer.cs и класс Service1.

Класс Service1 собственно представляет службу. По умолчанию он имеет следующий код:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;

namespace FileWatcherService
{
    public partial class Service1 : ServiceBase
    {
        public Service1()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
        }

        protected override void OnStop()
        {
        }
    }
}

Класс службы должен наследоваться от базового класса ServiceBase. Этот класс определяет ряд методов, важнейшие из которых
метод OnStart(), который запускает действия, выпоняемые службой, и метод OnStop(), останавливающий
службу.

После того, как SCM вызовет метод Main и зарегистрирует службу, происходит непосредственный ее вызов через запуск метода OnStart.

Когда в консоли служб или через командную строку мы посылаем команду на остановку службы, то SCM обращается к методу OnStop для ее остановки.

Кроме этих двух методов в классе службы можно переопределить еще несколько методов базового класса ServiceBase:

  • OnPause: вызывается при приостановке службы

  • OnContinue: вызывается при возобновлении работы службы после ее приостановки

  • OnShutdown: вызывается при завершении работы Windows

  • OnPowerEvent: вызывается при изменении режима электропитания

  • OnCustomCommand: вызывается при получении службой пользовательской команды от Менеджера Управления Службами (Service Control Manager / SCM)

В конструкторе класса Service1 вызывается метод InitializeComponent(), который определен в файле дизайнера Service1.Designer.cs:

namespace FileWatcherService
{
    partial class Service1
    {
        private System.ComponentModel.IContainer components = null;

        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        private void InitializeComponent()
        {
            components = new System.ComponentModel.Container();
            this.ServiceName = "Service1";
        }
    }
}

Единственное, что надо в нем отметить, это установка названия службы (свойство ServiceName):

this.ServiceName = "Service1";

Это то название, которое будет отображаться в консоли служб после установки данной службы. Мы можем его изменить, а можем и оставить как есть.

Теперь изменим код службы следующим образом:

using System;
using System.ServiceProcess;
using System.IO;
using System.Threading;

namespace FileWatcherService
{
    public partial class Service1 : ServiceBase
    {
        Logger logger;
        public Service1()
        {
            InitializeComponent();
            this.CanStop = true;
            this.CanPauseAndContinue = true;
            this.AutoLog = true;
        }

        protected override void OnStart(string[] args)
        {
            logger = new Logger();
            Thread loggerThread = new Thread(new ThreadStart(logger.Start));
            loggerThread.Start();
        }

        protected override void OnStop()
        {
            logger.Stop();
            Thread.Sleep(1000);
        }
    }

    class Logger
    {
        FileSystemWatcher watcher;
        object obj = new object();
        bool enabled = true;
        public Logger()
        {
            watcher = new FileSystemWatcher("D:\Temp");
            watcher.Deleted += Watcher_Deleted;
            watcher.Created += Watcher_Created;
            watcher.Changed += Watcher_Changed;
            watcher.Renamed += Watcher_Renamed;
        }

        public void Start()
        {
            watcher.EnableRaisingEvents = true;
            while(enabled)
            {
                Thread.Sleep(1000);
            }
        }
        public void Stop()
        {
            watcher.EnableRaisingEvents = false;
            enabled = false;
        }
		// переименование файлов
        private void Watcher_Renamed(object sender, RenamedEventArgs e)
        {
            string fileEvent = "переименован в " + e.FullPath;
            string filePath = e.OldFullPath;
            RecordEntry(fileEvent, filePath);
        }
		// изменение файлов
        private void Watcher_Changed(object sender, FileSystemEventArgs e)
        {
            string fileEvent = "изменен";
            string filePath = e.FullPath;
            RecordEntry(fileEvent, filePath);
        }
		// создание файлов
        private void Watcher_Created(object sender, FileSystemEventArgs e)
        {
            string fileEvent = "создан";
            string filePath = e.FullPath;
            RecordEntry(fileEvent, filePath);
        }
		// удаление файлов
        private void Watcher_Deleted(object sender, FileSystemEventArgs e)
        {
            string fileEvent = "удален";
            string filePath = e.FullPath;
            RecordEntry(fileEvent, filePath);
        }

        private void RecordEntry(string fileEvent, string filePath)
        {
            lock (obj)
            {
                using (StreamWriter writer = new StreamWriter("D:\templog.txt", true))
                {
                    writer.WriteLine(String.Format("{0} файл {1} был {2}", 
                        DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss"), filePath, fileEvent));
                    writer.Flush();
                }
            }
        }
    }
}

Ключевым классом, который инкапсулирует всю функциональность, является класс Logger. С помощью объекта FileSystemWatcher он будет вести мониторинг изменений в папке D://Temp.
В методе Start() устанавливается, что мы будем отслеживать изменения через объект FileSystemWatcher. И вся работа будет идти, пока булевая переменная enabled равна true. А метод Stop() позволит
завершить работу класса.

События FileSystemWatcher позволяют отслеживать все изменения в наблюдаемой папке.
При этом будет вестись запись изменений в файл templog.txt. Чтобы не было гонки ресурсов
за файл templog.txt, в который вносятся записи об изменениях, процедура записи блокируется заглушкой lock(obj).

В итоге после создания, изменения, переименования и удаления файл лога будет содержать что-то наподобие:

30.07.2015 12:15:40 файл D:TempНовый текстовый документ.txt был создан
30.07.2015 12:15:46 файл D:TempНовый текстовый документ.txt был переименован в D:Temphello.txt
30.07.2015 12:15:55 файл D:Temphello.txt был изменен
30.07.2015 12:15:55 файл D:Temphello.txt был изменен
30.07.2015 12:16:01 файл D:Temphello.txt был удален

В самом классе службы Service1 в конструкторе устанавливается ряд опций:

this.CanStop = true; // службу можно остановить
this.CanPauseAndContinue = true; // службу можно приостановить и затем продолжить
this.AutoLog = true; // служба может вести запись в лог

В методе OnStart() для запуска объекта Logger вызывется новый поток:

protected override void OnStart(string[] args)
{
    logger = new Logger();
    Thread loggerThread = new Thread(new ThreadStart(logger.Start));
    loggerThread.Start();
}

Новый поток нужен, так как текущий поток обрабатывает только команды SCM и должен возвращаться из метода OnStart как можно быстрее.

Когда от менеджера SCM поступает команда на остановку службы, срабатывает метод OnStop, который вызывает метод logger.Stop(). Дополнительная задержка
позволит потоку логгера остановиться:

protected override void OnStop()
{
    logger.Stop();
    Thread.Sleep(1000);
}

Однако самого класса службы еще недостаточно. Нам необходимо еще создать устанощик службы.

This article introduces Windows Services in .NET and how to create a Windows Service in C# and .NET using Visual Studio.

What is a Windows Service?

Windows Services are non-UI software applications that run in the background. Windows services usually start when an operating system boots and is scheduled to run in the background to execute some tasks. Windows services can also be started automatically or manually. You can also manually pause, stop and restart Windows services. 

Windows service is a computer program that runs in the background to execute some tasks. Some examples of Windows services are auto-update of Windows, check emails, print documents, SQL Server Agent, file and folder scanning and indexing, etc. If you open your Task Manager and click on the Services tab, you will see hundreds of services running on your machine. You can also see the statuses of these services. Some services are running, some have paused, and some have stopped. You can start, stop, and pause a service from here by right click on the service. 

Windows Service in CSharp

You may also find all services running on your machine in the following ways:

  • Go to Control Panel and select «Services» inside «Administrative Tools.»
  • Next, open the Run window (Window + R), type services.msc, and press ENTER.

How to create a Windows service in C#?

Let’s create a Windows Service in C# using Visual Studio. 

Step 1

Open Visual Studio, click File > New, and select a project. Next, select a new project from the Dialog box, select «Window Service,» and click the OK button.

windows service

Step 2

Go to Visual C# ->» Windows Desktop» ->» Windows Service,» give an appropriate name and then click OK.

windows service 

Once you click the OK button, the below screen will appear, which is your service.

windows service 

Step 3

Right-click on the blank area and select «Add Installer.»

How to Add an Installer to a Windows Service

Before you can run a Windows Service, you need to install the Installer, which registers it with the Service Control Manager.

windows service 

After Adding Installer, ProjectInstaller will add to your project, and ProjectInstakker.cs file will be open. Don’t forget to save everything (by pressing the ctrl + shift + s key)

windows service 

Solution Explore looks like this:

windows service 

Step 4

Right-click on the blank area and select «View Code»

windows service

Step 5

It has Constructor, which contains the InitializeComponent method:

The InitializeComponent method contains the logic which creates and initializes the user interface objects dragged on the forming surface and provides the Property Grid of Form Designer.

Very important: Don’t ever try to call any method before the call of the InitializeComponent process.

windows service 

Step 6

Select the InitializeComponent method and press the F12 key to go definition.

windows service 

Step 7

Now add the below line:

this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem;

You also can add a description and display the service name (optionally).

this.serviceInstaller1.Description = "My First Service demo";  
this.serviceInstaller1.DisplayName = "MyFirstService.Demo";  

windows service

Step 8

In this step, we will implement a timer and code to call the service at a given time. Then, we will create a text file and write the current time in the text file using the service. 

windows service 

Service1.cs class

using System;  
using System.Collections.Generic;  
using System.ComponentModel;  
using System.Data;  
using System.Diagnostics;  
using System.IO;  
using System.Linq;  
using System.ServiceProcess;  
using System.Text;  
using System.Threading.Tasks;  
using System.Timers;  
namespace MyFirstService {  
    public partial class Service1: ServiceBase {  
        Timer timer = new Timer(); // name space(using System.Timers;)  
        public Service1() {  
            InitializeComponent();  
        }  
        protected override void OnStart(string[] args) {  
            WriteToFile("Service is started at " + DateTime.Now);  
            timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);  
            timer.Interval = 5000; //number in milisecinds  
            timer.Enabled = true;  
        }  
        protected override void OnStop() {  
            WriteToFile("Service is stopped at " + DateTime.Now);  
        }  
        private void OnElapsedTime(object source, ElapsedEventArgs e) {  
            WriteToFile("Service is recall at " + DateTime.Now);  
        }  
        public void WriteToFile(string Message) {  
            string path = AppDomain.CurrentDomain.BaseDirectory + "\Logs";  
            if (!Directory.Exists(path)) {  
                Directory.CreateDirectory(path);  
            }  
            string filepath = AppDomain.CurrentDomain.BaseDirectory + "\Logs\ServiceLog_" + DateTime.Now.Date.ToShortDateString().Replace('/', '_') + ".txt";  
            if (!File.Exists(filepath)) {  
                // Create a file to write to.   
                using(StreamWriter sw = File.CreateText(filepath)) {  
                    sw.WriteLine(Message);  
                }  
            } else {  
                using(StreamWriter sw = File.AppendText(filepath)) {  
                    sw.WriteLine(Message);  
                }  
            }  
        }  
    }  
}

Code explanation — the above code will call service every 5 seconds, create a folder if none exists, and write our message.

Step 9. Rebuild your application.

Right-click on your project or solution and select Rebuild.

windows service 

Step 10

Search «Command Prompt» and run as administrator.

windows service 

Step 11

Fire the below command in the command prompt and press ENTER.

cd C:WindowsMicrosoft.NETFrameworkv4.0.30319 

windows service 

Step 12

Now Go to your project source folder > bin > Debug and copy the full path of your Windows Service exe file.

windows service

windows service

Installing a Windows Service

Open the command prompt and fire the below command and press ENTER.

Syntax

InstallUtil.exe + Your copied path + your service name + .exe

Our path

InstallUtil.exe C:UsersFaisal-PathansourcereposMyFirstServiceMyFirstServicebinDebugMyFirstService.exe

windows service 

Check the status of a Windows Service.

Open services by following the below steps:

  1. Press the Window key + R.
  2. Type services.msc
  3. Find your Service.

windows service

windows service

You may notice that the Windows service is running. 

windows service

Check Windows Service Output 

The service will create a text file with the following text in it. 

windows service 

The log folder will be created in your bin folder.

Uninstalling a Windows Service

If you want to uninstall your service, fire the below command.

  1. Syntax InstallUtil.exe -u + Your copied path + your service name + .exe
  2. Our path InstallUtil.exe -u C:UsersFaisal-PathansourcereposMyFirstServiceMyFirstServicebinDebugMyFirstService.exe

Summary

This article taught us how to create a Windows Service and install/Uninstall it using InstallUtil.exe from the command prompt.

I hope you found this tutorial easy to follow and understand. 

I also uploaded this project on GitHub; here is the URL https://github.com/faisal5170/WindowsService.

This article introduces Windows Services in .NET and how to create a Windows Service in C# and .NET using Visual Studio.

What is a Windows Service?

Windows Services are non-UI software applications that run in the background. Windows services usually start when an operating system boots and is scheduled to run in the background to execute some tasks. Windows services can also be started automatically or manually. You can also manually pause, stop and restart Windows services. 

Windows service is a computer program that runs in the background to execute some tasks. Some examples of Windows services are auto-update of Windows, check emails, print documents, SQL Server Agent, file and folder scanning and indexing, etc. If you open your Task Manager and click on the Services tab, you will see hundreds of services running on your machine. You can also see the statuses of these services. Some services are running, some have paused, and some have stopped. You can start, stop, and pause a service from here by right click on the service. 

Windows Service in CSharp

You may also find all services running on your machine in the following ways:

  • Go to Control Panel and select «Services» inside «Administrative Tools.»
  • Next, open the Run window (Window + R), type services.msc, and press ENTER.

How to create a Windows service in C#?

Let’s create a Windows Service in C# using Visual Studio. 

Step 1

Open Visual Studio, click File > New, and select a project. Next, select a new project from the Dialog box, select «Window Service,» and click the OK button.

windows service

Step 2

Go to Visual C# ->» Windows Desktop» ->» Windows Service,» give an appropriate name and then click OK.

windows service 

Once you click the OK button, the below screen will appear, which is your service.

windows service 

Step 3

Right-click on the blank area and select «Add Installer.»

How to Add an Installer to a Windows Service

Before you can run a Windows Service, you need to install the Installer, which registers it with the Service Control Manager.

windows service 

After Adding Installer, ProjectInstaller will add to your project, and ProjectInstakker.cs file will be open. Don’t forget to save everything (by pressing the ctrl + shift + s key)

windows service 

Solution Explore looks like this:

windows service 

Step 4

Right-click on the blank area and select «View Code»

windows service

Step 5

It has Constructor, which contains the InitializeComponent method:

The InitializeComponent method contains the logic which creates and initializes the user interface objects dragged on the forming surface and provides the Property Grid of Form Designer.

Very important: Don’t ever try to call any method before the call of the InitializeComponent process.

windows service 

Step 6

Select the InitializeComponent method and press the F12 key to go definition.

windows service 

Step 7

Now add the below line:

this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem;

You also can add a description and display the service name (optionally).

this.serviceInstaller1.Description = "My First Service demo";  
this.serviceInstaller1.DisplayName = "MyFirstService.Demo";  

windows service

Step 8

In this step, we will implement a timer and code to call the service at a given time. Then, we will create a text file and write the current time in the text file using the service. 

windows service 

Service1.cs class

using System;  
using System.Collections.Generic;  
using System.ComponentModel;  
using System.Data;  
using System.Diagnostics;  
using System.IO;  
using System.Linq;  
using System.ServiceProcess;  
using System.Text;  
using System.Threading.Tasks;  
using System.Timers;  
namespace MyFirstService {  
    public partial class Service1: ServiceBase {  
        Timer timer = new Timer(); // name space(using System.Timers;)  
        public Service1() {  
            InitializeComponent();  
        }  
        protected override void OnStart(string[] args) {  
            WriteToFile("Service is started at " + DateTime.Now);  
            timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);  
            timer.Interval = 5000; //number in milisecinds  
            timer.Enabled = true;  
        }  
        protected override void OnStop() {  
            WriteToFile("Service is stopped at " + DateTime.Now);  
        }  
        private void OnElapsedTime(object source, ElapsedEventArgs e) {  
            WriteToFile("Service is recall at " + DateTime.Now);  
        }  
        public void WriteToFile(string Message) {  
            string path = AppDomain.CurrentDomain.BaseDirectory + "\Logs";  
            if (!Directory.Exists(path)) {  
                Directory.CreateDirectory(path);  
            }  
            string filepath = AppDomain.CurrentDomain.BaseDirectory + "\Logs\ServiceLog_" + DateTime.Now.Date.ToShortDateString().Replace('/', '_') + ".txt";  
            if (!File.Exists(filepath)) {  
                // Create a file to write to.   
                using(StreamWriter sw = File.CreateText(filepath)) {  
                    sw.WriteLine(Message);  
                }  
            } else {  
                using(StreamWriter sw = File.AppendText(filepath)) {  
                    sw.WriteLine(Message);  
                }  
            }  
        }  
    }  
}

Code explanation — the above code will call service every 5 seconds, create a folder if none exists, and write our message.

Step 9. Rebuild your application.

Right-click on your project or solution and select Rebuild.

windows service 

Step 10

Search «Command Prompt» and run as administrator.

windows service 

Step 11

Fire the below command in the command prompt and press ENTER.

cd C:WindowsMicrosoft.NETFrameworkv4.0.30319 

windows service 

Step 12

Now Go to your project source folder > bin > Debug and copy the full path of your Windows Service exe file.

windows service

windows service

Installing a Windows Service

Open the command prompt and fire the below command and press ENTER.

Syntax

InstallUtil.exe + Your copied path + your service name + .exe

Our path

InstallUtil.exe C:UsersFaisal-PathansourcereposMyFirstServiceMyFirstServicebinDebugMyFirstService.exe

windows service 

Check the status of a Windows Service.

Open services by following the below steps:

  1. Press the Window key + R.
  2. Type services.msc
  3. Find your Service.

windows service

windows service

You may notice that the Windows service is running. 

windows service

Check Windows Service Output 

The service will create a text file with the following text in it. 

windows service 

The log folder will be created in your bin folder.

Uninstalling a Windows Service

If you want to uninstall your service, fire the below command.

  1. Syntax InstallUtil.exe -u + Your copied path + your service name + .exe
  2. Our path InstallUtil.exe -u C:UsersFaisal-PathansourcereposMyFirstServiceMyFirstServicebinDebugMyFirstService.exe

Summary

This article taught us how to create a Windows Service and install/Uninstall it using InstallUtil.exe from the command prompt.

I hope you found this tutorial easy to follow and understand. 

I also uploaded this project on GitHub; here is the URL https://github.com/faisal5170/WindowsService.

Служба Windows на C#

Всем доброго времени суток. На связи Алексей Гулынин. В данной статье мы напишем простую WCF-службу Windows на C#, и установим её. Её можно будет запускать, останавливать, как и все другие службы Windows.

Клиентская часть будет та же, что и в прошлых двух статьях — это Windows Forms — приложение, которое шлёт сообщения по адресу http://localhost:343/IContract.

Создадим проект WindowsService, который является консольным приложением. Не забываем добавлять в проект необходимые ссылки. Сразу приведу код:

Файл Service.cs:

// не забываем добавлять данные ссылки в проект
using System.ServiceProcess;
using System.ServiceModel;
using System.ComponentModel;
using System.Configuration.Install;

namespace WindowsService
{
  // это служебный класс для служб Windows
  [RunInstaller(true)]
  public class ProjectInstaller : Installer
  {
    private ServiceProcessInstaller serviceProcess;
    private ServiceInstaller serviceInstaller;

    public ProjectInstaller()
    {
      serviceProcess = new ServiceProcessInstaller();
      // учетная запись, под которой будет запускаться служба
      serviceProcess.Account = ServiceAccount.LocalSystem;

      serviceInstaller = new ServiceInstaller();
      serviceInstaller.ServiceName = "Приём сообщений";
      serviceInstaller.Description = @"Служба, которая ожидает приёма сообщений по адресу http://localhost:343/IContract";
      // указываем, чтобы служба запускалась автоматически при запуске рабочей станции
      serviceInstaller.StartType = ServiceStartMode.Automatic;

      Installers.Add(serviceProcess);
      Installers.Add(serviceInstaller);
    }
  }

  // Наш контракт
  [ServiceContract]
  interface IContract                                                  
  {
    [OperationContract]
    string Print(string str);
  }


  // Наш сервис, который реализует контракт
  class Service : IContract
  {
    public string Print(string str)
    {
      return "Сообщение клиента: " + str;
    }
  }

  // Наша служба Windows
  public partial class WindowsService : ServiceBase
  {
    ServiceHost serviceHost = null;

    // Запуск службы
    protected override void OnStart(string[] args)
    {
      if (serviceHost == null)
      {
        serviceHost = new ServiceHost(typeof(Service));
        serviceHost.Open();
      }
    }
    // Остановка службы
    protected override void OnStop()
    {
      if (serviceHost != null)
      {
        serviceHost.Close();
      }
    }
  }
}

Не забываем добавить файл App.config:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>
  <system.serviceModel>
    <services>
      <service name ="WindowsService.Service">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:343/IContract"/>
          </baseAddresses>
        </host>
        <!-- указываем адрес, привязку и контракт -->
        <endpoint address=""
                  binding="basicHttpBinding"
                  contract="WindowsService.IContract" />
      </service>
    </services>
  </system.serviceModel>
</configuration>

Класс Program.cs:

using System.ServiceProcess;

namespace WindowsService
{
  class Program
  {
    // В данном методе запускается наша служба
    static void Main(string[] args)
    {
      ServiceBase[] ServicesToRun;
      ServicesToRun = new ServiceBase[]
      {
        new WindowsService()
      };
      ServiceBase.Run(ServicesToRun);
    }
  }
}

При попытке запустить нашу службу из Visual Studio мы увидим следующую ошибку:

Служба Windows на C#

Давайте установим нашу службу правильно с помощью утилиты installutil.exe. Создадим на диске «C» папку «WindowsService». В эту папку поместим файлы «WindowsService.exe» и «WindowsService.exe.config», который создаётся в момент компиляции программы. Создадим 2 текстовых файла, которые будут устанавливать и удалять нашу службу. У этих двух файлов изменим расширение с «txt» на «bat».

Содержимое файла InstallService.bat:

C:WindowsMicrosoft.NETFrameworkv4.0.30319installutil.exe WindowsService.exe

Содержимое файла UninstallService.bat:

C:WindowsMicrosoft.NETFrameworkv4.0.30319InstallUtil.exe /u WindowsService.exe

Установим нашу службу. Видим, что служба была установлена:

Служба Windows на C#

В панели управления на вкладке «Администрирование — Службы» мы видим, что служба появилась. Запустим её:

Служба Windows на C#

После того, как у нас служба запустилась, запустим клиентскую часть и убедимся, что всё работает (сообщения отправляются):

Служба Windows на C#

В предыдущих статьях наш сервис являлся простым приложением. Для сервиса такой вариант не совсем удобен. Первое, что приходит в голову, — это вариант, когда сервис располагается на сервере. Если у нас сервис не является службой Windows, то при перезагрузке сервера администратору необходимо будет зайти и вручную запустить программу. Чтобы этого не делать, сервис необходимо делать службой, устанавливая автоматический тип запуска.

В данной статье вы создали простую WCF-службу Windows на C#.

На связи был Алексей Гулынин, оставляйте свои комментарии, увидимся в следующих статьях.

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

Sc.exe

Для создания и службы из командной строки можно использовать программу SC (Sc.exe). SC представляет из себя утилиту командной строки, которая реализует вызовы ко всем функциям интерфейса прикладного программирования (API) управления службами Windows. С ее помощью можно производить любые действия со службами —  просматривать состояние, управлять (запускать, останавливать и т.п.), изменять параметры, а также создавать новые службы.

При создании службы с помощью SC нет необходимости вручную создавать записи в реестре и затем перезагружать компьютер, чтобы обеспечить обновление базы данных диспетчером служб. Также SC позволяет указать имя удаленного компьютера, что дает возможность управлять службами как на локальном, так и на удаленном компьютере.

Для создания нового сервиса запускаем команду Sc create. Она создает запись службы в реестре и в базе данных диспетчера служб. Sc create имеет следующий синтаксис:

sc create [ServiceName] [binPath= ] <параметр1= > <параметр2= >

ServiceName — указывает имя, которое будет присвоено разделу службы в реестре. Имейте в виду, что это имя отличается от отображаемого имени службы (имени, которое отображается в оснастке «Services»);
binPath — указывает путь к исполняемому файлу службы.

Для примера создадим службу MyService, укажем отображаемое имя My New Service, зададим тип службы и поставим ее на авто-запуск:

Sc create MyService binPath=C:MyServiceMyService.exe DisplayName=″My New Service″ type=own start=auto

Затем откроем оснастку «Services» и посмотрим результат.

оснастка Службы

Изменять параметры уже созданной службы можно командой Sc config. Например, мне не понравилось отображаемое имя службы и я хочу его изменить:

Sc config MyService DisplayName=″My Service″

Ну и полностью удалить службу можно вот так:

Sc delete MyService

создание, изменение и удаление службы Windows

PowerShell

PowerShell может почти все 🙂 , в том числе и управлять службами Windows. Создать новую службу можно с помощью командлета New-Service. Создадим такой же сервис, как и в предыдущем примере, только добавим к нему описание (Description):

New-Service -Name MyService -BinaryPathName C:MyServiceMyService.exe`
-DisplayName ″My New Service″ -Description ″Very Important Service !!!″

Изменить параметры службы можно командлетом Set-Service:

Set-Service -Name MyService -Description ″Not Very Important Service″ -StartupType Manual

создание и изменение служб с помощью PowerShell

В принципе PowerShell имеет примерно такой же функционал как и Sc.exe, разве что позволяет добавить описание. А вот для удаления служб в PS простого способа нет, придется воспользоваться вот такой конструкцией:

(Get-WmiObject win32_service -Filter ″name=′MyService′″).delete()

Поэтому лично я предпочитаю использовать Sc.exe.

Понравилась статья? Поделить с друзьями:
  • Как написать служебную записку на ремонт помещения образец
  • Как написать сложный пароль
  • Как написать служебную записку на ремонт кровли
  • Как написать сложные слова
  • Как написать служебную записку на ремонт автомобиля образец