Форум программистов, компьютерный форум, киберфорум
Jin X
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  

Пара нюансов при создании службы (Windows Service) и не только

Запись от Jin X размещена 26.03.2019 в 16:27
Показов 16413 Комментарии 0

Пара нюансов при создании службы (Windows Service) и не только

Пишу службу (Windows Service) на Delphi через VCL. В том же EXE-шнике делаю конфигуратор с оконным интерфейсом.
Получается так:
  • При запуске с опцией /install служба устанавливается (встроенная фича TServiceApplication).
  • При запуске с опцией /uninstall служба удаляется (встроенная фича TServiceApplication).
  • При запуске с опцией /config запускается конфигуратор.
  • Запуск службы происходит по специальной схеме (через тот же EXE-шник). Это внутренняя кухня модуля [Vcl.]SvcMgr.
Если вырезать интимные подробности, DPR-файл выглядит примерно так:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
program ServiceTest;
 
uses
  System.SysUtils,
  Vcl.Forms,
  Vcl.SvcMgr,
  MyService in 'MyService.pas',
  ConfigForm in 'ConfigForm.pas';
 
{$R *.RES}
 
begin
  if FindCmdLineSwitch('CONFIG') then
  begin
    // Запуск конфигуратора
    Vcl.Forms.Application.Initialize;
    Vcl.Forms.Application.MainFormOnTaskbar := True;
    Vcl.Forms.Application.CreateForm(TFormConfig, FormConfig);
    Vcl.Forms.Application.Run;
  end
  else
  begin
    // Запуск сервиса или установщика сервиса
    if not Vcl.SvcMgr.Application.DelayInitialize or Vcl.SvcMgr.Application.Installing then
      Vcl.SvcMgr.Application.Initialize;
    Vcl.SvcMgr.Application.CreateForm(TMyService, MyService);
    Vcl.SvcMgr.Application.Run;
  end;
end.
Проблема №1

Оказывается, в VCL нет встроенных средств для запуска службы. Службу можно установить, а запускаться она будет только после перезагрузки компьютера. Довольно странно, но факт.
Решить эту проблему через WinAPI (если класс нашей службы называется TMyService):
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Запуск (Start = True) или остановка (Start = False) службы (метод наследника TService).
procedure TMyService.StartStopService(Start: Boolean);
var
  SvcMgr, Svc: SC_HANDLE;
  P: PChar;
  SS: TServiceStatus;
begin
  // Открываем диспетчер управления службами (SCM)
  SvcMgr := OpenSCManager(nil, nil, STANDARD_RIGHTS_REQUIRED);
  if SvcMgr <> 0 then
  begin
    // Открываем службу с именем Name (это свойство объекта класса-наследника TService)
    Svc := OpenService(SvcMgr, PChar(Name), SERVICE_ALL_ACCESS);
    if Svc <> 0 then
    begin
      // Запуск или остановка?
      if Start then
      begin
        P := nil;
        StartService(Svc, 0, P);  // запускаем службу
      end
      else
      begin
        FillChar(SS, SizeOf(SS), 0);
        ControlService(Svc, SERVICE_CONTROL_STOP, SS);  // останавливаем службу
      end;
      CloseServiceHandle(Svc);
    end;
    CloseServiceHandle(SvcMgr);
  end;
end;
Если нам нужно запускать службу сразу после её установки, делаем так:
Delphi
1
2
3
4
procedure TMyService.ServiceAfterInstall(Sender: TService);
begin
  StartStopService(True);
end;
Представьте себе, остановки при удалении (деинсталляции) службы тоже не происходит, поэтому делаем ещё и так:
Delphi
1
2
3
4
procedure TMyService.ServiceBeforeUninstall(Sender: TService);
begin
  StartStopService(False);
end;
Проблема №2

Каким же образом сообщить службе об изменении конфигурации (чтобы она прочитала её заново – из реестра или с диска)? Проще всего – создать глобальное именованное событие (CreateEvent) и через него сигнализировать (SetEvent) из конфигуратора службе (которая будет ждать его, либо периодически проверять, через WaitForSingleObject). Но тут нас поджидает засада: при попытке открыть из конфигуратора событие (OpenEvent), созданное службой, мы получим ошибку запрета доступа (GetLastError = ERROR_ACCESS_DENIED).

Это происходит из-за того, что объект (событие) создан "системой" (службы запускаются от имени "системы"), а открывается администратором (если конфигуратор находится в том же EXE – установить/удалить службу может только администратор) или даже обычным пользователем (если конфигуратор находится в другом EXE-шнике). Тоже самое будет при попытке открыть обычным пользователем объект, созданный администратором.

Что же делать? Сначала я решил пойти по странному пути: создать объект в конфигураторе, а в службе периодически пытаться открыть его, и после успешного открытия начать проверять состояние ("система" может открыть объект, созданный администратором или обычным пользователем). Но потом эта идея мне показалась костыльной, и я решил разобраться, как создать объект в службе, не защищённый от доступа админов и обычных юзеров.

Вот так это делается (в службе):
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Создать событие с именем Name в глобальном пространстве имён, доступный любым процессам.
function CreateUnprotectedEvent(const Name: String): THandle;
var
  SA: TSecurityAttributes;
  SD: TSecurityDescriptor;
begin
  Result := 0;
  // Создаем дескриптор безопасности
  if InitializeSecurityDescriptor(@SD, SECURITY_DESCRIPTOR_REVISION) and
     // DACL не установлен, объект не защищён
     SetSecurityDescriptorDacl(@SD, True, nil, False) then
  begin
    // Настраиваем атрибуты безопасности, передавая указатель на дескриптор безопасности
    SA.nLength := SizeOf(SA);
    SA.lpSecurityDescriptor := @SD;
    SA.bInheritHandle := False;
    // Создаём событие
    Result := CreateEvent(@SA, True, False, Pointer('Global\' + Name));
  end;
end;
(разумеется, при необходимости создания нескольких событий нет смысла создавать и настраивать несколько дескрипторов и атрибутов безопасности, можно использовать одни и те же; при завершении работы ничего, кроме события, закрывать или освобождать не нужно)

Как вы понимаете, это всё можно делать не только при создании служб и не только для создания событий. Если вам не нравится взаимодействие через события, и вы хотите иметь возможность передавать какие-то данные, можете создать, к примеру, разделяемую память. В общем, простор для творчества есть
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии
 
Новые блоги и статьи
Запустил конкурс "тем и промптов для текстовых квестов созданных почти чисто ИИ"
Adler 06.10.2026
Всем привет! За последние три-четыре дня я создал более 16 текстовых квестовых игр используя преимущественно по одному запросу к ИИ на игру. Мне так понравилось смотреть все ветки/ сцены во всех. . .
ИИ не может найти нужный язык в списке
Supersumestria 05.10.2026
Я ему даю вот такое изображение и прошу найти и подчеркнуть немецкий язык. Возвращает он вот это: https:/ / i. **********/ vqBWLe2. png Нужную строчку в 3й колонке просто выдумал. . Это. . .
Новая последняя моя музыка в SUNO
zorxor 05.10.2026
Здравствуйте, дорогие мои друзья! С большой радостью я хотел бы представить вам свою новую последнею музыку, которую сгенерировала мне по моей просьбе нейросеть SUNO. С уважением, zorxor. Это. . .
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru