Как стать автором
Обновить

Сервисы Windows на C#

Время на прочтение 3 мин
Количество просмотров 2.1K
Предисловие

Сервисы в Windows управляют практически всем: от поддержки самой системы на плаву до служб родительского контроля. В Диспетчере задач есть инструмент для их обзора и остановки\запуска, не говоря уже об отдельной встроенной в Windows утилите. Но что если вам необходимо встроить и в свою программу такой инструмент. Где брать всю эту информацию? Как управлять службами? Расскажу как это делал я на С# и с какими сложностями столкнулся.

Как все начиналось

Я – начинающий разработчик приложений на C#. Точнее начинающим я был около года назад. Сейчас же думаю, что при особом желании вполне смогу разработать довольно сложные вещи. Ну да речь не об этом. В общем, создать мне необходимо было утилиту, которая корректно отображала бы и владела самым необходимым функционалом для управления службами. Что-то наподобие существующей возможности в диспетчере windows.

Как все рисовалось

Интерфейс богатством не грозил и остановиться я решил на панели инструментов и списке в котором службы будут отображаться. В качестве последнего был выбран DataGridView, потому что он выводит информацию в колоночном виде, что мне было очень удобно, а также имеет некоторые удобства и для пользователей (сортировка, например).
На панели инструментов же были порядка 6 кнопок, которые управляли выбранными службами.
Сложностей на стадии рисования интерфейса не было никаких, и закончен он был успешно буквально за несколько часов.

Как все разрабатывалось

Ну прежде всего были необходимы два механизма: первый, который был находил все службы зарегистрированные на данной машине и информацию о них, а второй, который бы корректно загонял все это в DataGridView. Со вторым проблем не должно было возникнуть. А вот с первым пришлось помучаться (и как оказалось, это была самая сложная часть разработки). О нем подробней…

По задумке необходимо было найти в системе следующую информацию о каждой службе: имя, причем не системное, а пользовательское; описание службы; ее состояние; тип запуска; путь к файлу и от чьего имени она была запущена. С именем не было никаких проблем – DisplayName из класса ServiceController очень корректно отображал его. Со статусом тоже не особо сложно – свойство Status из того же класса отлично помогло. А вот чтобы узнать от кого была запущена служба, какой тип ее запуска и где находится образ — уже пришлось лезть в реестр. Тоже, в принципе, ничего заоблачно сложного, но посидеть пришлось дольше, чем над предыдущими атрибутами.

Чем все усложнилось

Как в итоге оказалось, камнем преткновения стало описание службы, понятное для пользователя. Начав искать способы как его получить, я понял что ни ServiceController, ни даже реестр не могут дать нормального описания. Зачастую в реестре в строке Description находится ссылка на dll библиотеку и номер строки, в которой в этой библиотеке находится описание службы. А так как C# ещё не умеет динамично брать информацию из dll, то при каждом обновлении списка приходилось смотреть в реестр, там брать ссылку и номер строки, идти в библиотеку, загружать ее, искать строку, копировать описание и обратно выгружать библиотеку. Как и ожидалось, это ужасно сказалось на быстродействии. Первый запуск такой скромной программки занимает секунд 5 (хоть последующие обновления производятся довольно быстро).

Как все закончилось

Все остальное (элементы управления, вывод информации в DataGrid, удобности для пользователя в виде возврата фокуса и сортировки на место после обновления списка и т.д.) было довольно простым. Методом проб и ошибок (и бесконечного шуршания в сети) это все было достигнуто. В итоге, утилита оказалась довольно удобной и некоторые даже согласились в качестве теста пользоваться ей вместо стандартного сервиса в диспетчере задач.
Вот скрин работающей проги image

Код (даже основная часть) довольно объемный, вот часть про поиск информации описания:

val = targetKey.GetValue(«Description»);
if (val == null)
row[1] = ""; // Описания нет
else
{
string s = (string)val;
Match m = Regex.Match(s, @"^[@](?(.*)),\s*-(?(\d*))");
if (m.Success) // Проверяем является ли строка ссылкой на ресурс
{
string w1 = m.Groups[«path»].Value; // Путь к dll
// Замена системной переменной %SystemRoot% в пути (если есть)
string w2 = Regex.Replace(w1, @"%SystemRoot%|%windir%", SystemRootPath, RegexOptions.IgnoreCase);
// Замена системной переменной %ProgramFiles% в пути (если есть)
string DllPath = Regex.Replace(w2, @"%ProgramFiles%", ProgramFilesPath, RegexOptions.IgnoreCase);
int ID = Convert.ToInt32(m.Groups[«id»].Value); // ID ресурса
// Загружаем требуемую dll
IntPtr hndl = DllInterop.LoadLibrary(DllPath);
// Получаем описание
row[1] = DllInterop.LoadStringDll(hndl, ID);
// Выгружаем dll
DllInterop.FreeLibrary(hndl);
}
else
row[1] = s;

P.S. Я думаю (уверен практически), что «закоренелые» разработчики и программисты не найдут ничего нового для себя, но людям, не работающим ранее с сервисами Windows в С#, думаю будет познавательно. Если нужны какие-то части кода или даже сама программа, то обращайтесь, будет очень приятно помочь.
Теги:
Хабы:
-8
Комментарии 16
Комментарии Комментарии 16

Публикации

Истории

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн