Предисловие Службы в Windows управляют практически всем: от поддержания самой системы на плаву до служб родительского контроля.
В диспетчере задач есть инструмент для их просмотра и остановки/запуска, не говоря уже об отдельной утилите, встроенной в Windows. Но что, если вам нужно встроить такой инструмент в свою программу? Где я могу получить всю эту информацию? Как управлять услугами? Расскажу, как я это сделал на C# и с какими трудностями столкнулся.
Как это все началось
Я начинающий разработчик приложений на C#.Точнее, я был новичком около года назад. Сейчас я думаю, что если очень захотеть, то смогу разработать довольно сложные вещи.
Ну, мы не об этом говорим.
В общем, мне нужно было создать утилиту, которая правильно будет отображать и обладать самым необходимым функционалом для управления сервисами.
Что-то вроде существующей функции в диспетчере окон.
Как все было нарисовано
Богатством интерфейс не грозил и я решил остановиться на панели инструментов и списке, в котором будут отображаться сервисы.В качестве последнего был выбран DataGridView, поскольку он отображает информацию в виде столбцов, что для меня было очень удобно, а также имеет некоторые удобства для пользователей (сортировка, например).
На панели инструментов было около 6 кнопок, управляющих выбранными сервисами.
На этапе отрисовки интерфейса не возникло никаких сложностей, и он был успешно выполнен всего за несколько часов.
Как все разрабатывалось
Ну, во-первых, нужны были два механизма: первый, который бы находил все зарегистрированные на данной машине сервисы и информацию о них, и второй, который бы корректно вносил все это в DataGridView. Со вторым проблем быть не должно.А вот с первым мне пришлось побороться (и как оказалось, это была самая сложная часть разработки).
Подробнее о нем.
По задумке, о каждом сервисе в системе необходимо было найти следующую информацию: имя, не имя системы, а имя пользователя; Описание услуг; ее состояние; тип запуска; путь к файлу и под чьим именем он был запущен.
С именем проблем не возникло — DisplayName из класса ServiceController отображал его очень корректно.
Статус тоже не представляет особой сложности — очень помогло свойство Status из того же класса.
Но чтобы узнать, кто запустил службу, какой это был тип запуска и где находится образ, нам уже пришлось залезть в реестр.
Тоже в принципе ничего особо сложного, но сидеть пришлось дольше, чем на предыдущих атрибутах.
Как все стало сложнее
Как оказалось в итоге, камнем преткновения стало описание сервиса, понятное пользователю.Начав искать способы его получения, я понял, что ни ServiceController, ни даже реестр не могут дать нормального описания.
Часто в реестре в строке «Описание» стоит ссылка на библиотеку dll и номер строки, в которой находится описание службы в этой библиотеке.
А так как C# пока не умеет динамически брать информацию из dll, то каждый раз при обновлении списка приходилось искать в реестре, брать там ссылку и номер строки, идти в библиотеку, загружать, искать строку , скопируйте описание и выгрузите библиотеку обратно.
Как и ожидалось, это ужасно сказалось на производительности.
Первый запуск такой скромной программы занимает около 5 секунд (хотя последующие обновления производятся довольно быстро).
Как это закончилось
Всё остальное (управление, отображение информации в DataGrid, удобство пользователя в виде возврата фокуса и сортировки на место после обновления списка и т.д.) было достаточно простым.Путем проб и ошибок (и бесконечного шуршания в Интернете) всего этого удалось добиться.
В результате утилита оказалась достаточно удобной и некоторые даже согласились использовать ее в качестве тестовой вместо стандартного сервиса в диспетчере задач.
Вот скриншот работающей программы
Код (даже основная часть) довольно объёмный, вот часть про поиск описательной информации:
val = targetKey.GetValue("Описание");
если (значение == ноль)
строка[1] = ""; // Без описания
еще
{
строка s = (строка) val;
Соответствие m = Regex.Match(s, @"^[@](?(.
*))\s*-(?(\d*))"); if (m.Success) // Проверяем, является ли строка ссылкой на ресурс { строка w1 = m.Groups[“путь”].
Value; // Путь к dll // Заменяем системную переменную %SystemRoot% в пути (если есть) строка w2 = Regex.Replace(w1, @"%SystemRoot%|%windir%", SystemRootPath, RegexOptions.IgnoreCase); // Заменяем системную переменную %ProgramFiles% в пути (если есть) строка DllPath = Regex.Replace(w2, @"%ProgramFiles%", ProgramFilesPath, RegexOptions.IgnoreCase); int ID = Convert.ToInt32(m.Groups["id"].
Value); // Идентификатор ресурса // Загружаем необходимую dll IntPtr hndl = DllInterop.LoadLibrary(DllPath); // Получаем описание row[1] = DllInterop.LoadStringDll(hndl, ID); // Выгружаем dll DllInterop.FreeLibrary(hndl); } еще строка[1] = с; P.S. Думаю (практически уверен), что «хардкорные» разработчики и программисты не найдут для себя ничего нового, но для людей, ранее не работавших с Windows-сервисами на C#, думаю, будет познавательно.
Если вам нужны какие-то части кода или даже сама программа, то обращайтесь к нам, мы будем очень рады помочь.
Теги: #C++ #Чулан #службы Windows
-
Спутник - Это Очень Просто - 2
19 Oct, 24 -
Будущее Азс: 50 Или 250 Квт
19 Oct, 24 -
Сколько Лет Вы Занимаетесь Веб-Разработкой?
19 Oct, 24 -
Проблемы Корпоративного Использования Saas
19 Oct, 24