Разработка служб Windows: создание проекта, особенности, установка/удаление служб, запуск службы, события службы

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


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

Файл - Создать проект - Служба Windows



Добавляем в проект класс установщика



Например, нам нужно, чтобы по определенному алгоритму службой обрабатывались файлы в указанной папке. Будем считать, что сам обработчик уже описан в классе SERVICE.FileCheckedProcessor.

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

//#define LOGEVENTS //Включить лог всех событий
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;
using System.Threading.Tasks;
namespace WIN_SERVICE
{
    public partial class WinService : ServiceBase
    {
        private Thread workerThread = null;
        SERVICE.FileCheckedProcessor fileCheckedProcessor = null;
        public WinService()
        {
            InitializeComponent();
            fileCheckedProcessor = new SERVICE.FileCheckedProcessor(WIN_SERVICE.Properties.Settings.Default.CheckedPath);
            fileCheckedProcessor.TEST = WIN_SERVICE.Properties.Settings.Default.TEST;
        }
        protected override void OnStart(string[] args)
        {
            if ((workerThread == null) ||
               ((workerThread.ThreadState &
                (System.Threading.ThreadState.Unstarted | System.Threading.ThreadState.Stopped)) != 0))
            {
#if LOGEVENTS
                EventLog.WriteEntry("WinService", DateTime.Now.ToLongTimeString() +
                    " - Запускаем вспомогательный поток службы");
#endif
                workerThread = new Thread(new ThreadStart(ServiceWorkerMethod));
                workerThread.Start();
            }
        }
        protected override void OnStop()
        {
            // Завершение работы потока обработки
            if ((workerThread != null) && (workerThread.IsAlive))
            {
#if LOGEVENTS
                EventLog.WriteEntry("WinService", DateTime.Now.ToLongTimeString() +
                    " - Останавливаем вспомогательный поток службы");
#endif
                Thread.Sleep(5000);
                workerThread.Abort();
            }
            if (workerThread != null)
            {
#if LOGEVENTS
                EventLog.WriteEntry("WinService", DateTime.Now.ToLongTimeString() +
                    " - Статус вспомогательного потока службы: " +
                    workerThread.ThreadState.ToString());
#endif
            }
            this.ExitCode = 0;
        }
        //Поток обработки
        public void ServiceWorkerMethod()
        {
#if LOGEVENTS
            EventLog.WriteEntry("WinService", DateTime.Now.ToLongTimeString() +
                " - Запускаем цикл обработки запросов во вспомогательном потоке службы");
#endif
            try
            {
                do
                {
                    if (WIN_SERVICE.Properties.Settings.Default.TEST)
                    {
                        EventLog.WriteEntry("WinService", DateTime.Now.ToLongTimeString() +
                       " - Обработка файлов в папке...");
                    }
                    //Обработка в папке файлов
                    fileCheckedProcessor.Process();
                    if (WIN_SERVICE.Properties.Settings.Default.TEST)
                    {
                        EventLog.WriteEntry("WinService", DateTime.Now.ToLongTimeString() +
                       " - Обработка файлов выполнена");
                    }
                    Thread.Sleep(3000);
                    //3 сек пауза перед следующей обработкой
#if LOGEVENTS
                    EventLog.WriteEntry("WinService", DateTime.Now.ToLongTimeString() +
                        " - Выполнение работ во вспомогательном потоке службы");
#endif
                }
                while (true);
            }
            catch (ThreadAbortException exc)
            {
#if LOGEVENTS
                EventLog.WriteEntry("WinService", DateTime.Now.ToLongTimeString() +
                    " - ThreadAbortException: " + exc.Message);
#endif
            }
#if LOGEVENTS
            EventLog.WriteEntry("WinService", DateTime.Now.ToLongTimeString() +
                " - Выход из вспомогательного потока службы");
#endif
        }
    }
}


Класс установщика необходим для установки службы в систему. В нем задаются параметры необходимые для работы службы (название, тип, описание и т.д.).

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;
using System.ServiceProcess;
using System.Threading.Tasks;
namespace WIN_SERVICE
{
    [RunInstaller(true)]
    public partial class WinServiceInstaller : System.Configuration.Install.Installer
    {
        ServiceInstaller serviceInstaller;
        ServiceProcessInstaller processInstaller;
        public WinServiceInstaller()
        {
            InitializeComponent();
            serviceInstaller = new ServiceInstaller();
            processInstaller = new ServiceProcessInstaller();
            processInstaller.Account = ServiceAccount.LocalSystem;
            serviceInstaller.StartType = ServiceStartMode.Manual;
            serviceInstaller.ServiceName = "WIN_SERVICE";
            serviceInstaller.Description = "Processing files";
            Installers.Add(processInstaller);
            Installers.Add(serviceInstaller);
        }
    }
}


Установка/удаление службы Windows

Для упрощения процесса установки/удаления создаем bat-файлы. Используем утилиту установщика поставляемую с NetFramework.

install.bat

cd /d %~dp0
%windir%\Microsoft.NET\Framework\v4.0.30319\InstallUtil /i "WIN_SERVICE.exe"
pause

uninstall.bat

cd /d %~dp0
%windir%\Microsoft.NET\Framework\v4.0.30319\InstallUtil /u "WIN_SERVICE.exe"
pause


Запуск службы Windows

Приложение устанавливается в систему в качестве локальной службы и выполняется вне зависимости от статуса текущего пользователя, запуск службы осуществляется вручную с помощью Service Control Manager (или другими аналогичными способами).


Регистрация событий службы Windows

В локальный системный журнал событий заносятся записи о выполняемых службой операциях (если в коде примера определить LOGEVENTS).


C# Службы Windows