Служба Windows на C#: ещё один пример

Служба Windows на C#: ещё один пример

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

Наша служба будет отслеживать количество запусков калькулятора (процесс calc.exe). Результат будет записываться в текстовый файл. Сразу приведу код:

Файл CalcService.cs:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install; // не забываем добавить ссылку
using System.Diagnostics;
using System.IO;
using System.ServiceProcess; // не забываем добавить ссылку
using System.Text;
using System.Threading;

namespace FileWindowsService
{
  // это служебный класс для служб 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 = @"Служба, которая отслеживает запуск исполняемого файла calc.exe (Калькулятор).";
      // указываем, чтобы служба запускалась автоматически при запуске рабочей станции
      serviceInstaller.StartType = ServiceStartMode.Automatic;

      Installers.Add(serviceProcess);
      Installers.Add(serviceInstaller);
    }
  }
  class CalcService
  {
    // количество запусков службы
    private static int count = 0;
    // будем помещать id процесса в массив, чтобы не учитывать процессы с
    // одинаковым id несколько раз
    public static List<int> oldProcsID = new List<int>();
    
    //  
    public static void CalcProcess(Object o)
    {
      // Получаем все процессы calc.exe
      Process[] procs = Process.GetProcessesByName("calc");
      foreach (Process proc in procs)
      {
        // Если данного процесса нет в нашем массиве
        if (!oldProcsID.Contains(proc.Id))
        {
          count++;
          writeInfoToFile("Количество запусков процесса: " + count.ToString() + " | ID процесса: {1}" + proc.Id.ToString() + Environment.NewLine);
          // Добавляем процесс
          oldProcsID.Add(proc.Id);
        }
      }
    }
    
    public static void CheckIDsCalcProcess(Object o)
    {
      Process[] allProcs = Process.GetProcesses();
      foreach (int procID in oldProcsID.ToArray())
      {
        bool isDelete = true;
        foreach (Process proc in allProcs)
        {
          if (proc.Id == procID)
          {
            isDelete = false;
          }
        }
        if (isDelete) oldProcsID.Remove(procID);
      }
    }

    // запись данных в файл
    private static void writeInfoToFile(string info)
    {
      using (StreamWriter sw = new StreamWriter(@"C:\calc.txt", true, Encoding.Unicode))
      {
        sw.WriteLine(info);
      }
    }
  }

  // Наша служба Windows
  public partial class WindowsService : ServiceBase
  {
    Timer t;
    Timer t1;
    // Запуск службы
    protected override void OnStart(string[] args)
    {
      t = new Timer(CalcService.CalcProcess, null, 0, 2000);
      t1 = new Timer(CalcService.CheckIDsCalcProcess, null, 0, 15000);
    }
    // Остановка службы
    protected override void OnStop()
    {
      t = null;
      t1 = null;
    }
  }
}

Файл Program.cs:

using System.ServiceProcess;

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

Метод CheckIDsCalcProcess(), который выполняется раз в 15 секунд, делает следующее:

Он сравнивает содержимое списка oldProcsID со всеми текущими процессами. Если в списке есть id процесса, которого нет во всех процессах, то данный id удаляется из списка.

Далее нам необходимо корректно установить службу. Приведу содержимое двух бат-файлов для установки и удаления службы. После выполнения данных команд необходимо зайти в службы Windows и запустить нашу службу.

Файл InstallService.bat:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\installutil.exe FileWindowsService.exe

Файл UninstallService.bat:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\installUtil.exe /u FileWindowsService.exe

Мы видим, что служба успешно запустилась:

Служба Windows на C#

Давайте теперь протестируем работу службы. Запустите несколько процессов калькулятора. После этого у нас на диске C создастся файл calc.txt:

Служба Windows на C#

Мы видим, что всё работает.

У нашей службы есть один недостаток, который сразу бросается в глаза. Каждый раз при загрузке компьютера, служба будет заново стартовать, при этом переменная count будет равна 0. Чтобы этого избежать значение переменной count можно записывать в текстовый файл или базу данных, и при старте службы переменной count присваивать это значение.

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

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


Комментарии:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *