Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > Описание сервиса


Автор: oleg2s 24.5.2012, 13:01
Доброе время суток.
Пишу сервис (пытаюсь). Подскажите, где (как) ввести описание сервиса, которое выводится в списке сервисов в колонке "описание"?

Автор: kami 24.5.2012, 13:17
Стандартно (существующими в VCL возможностями) - нигде.
Меняется с помощью ChangeServiceConfig2 с параметром SERVICE_CONFIG_DESCRIPTION.
Пошукайте гуглом эту функцию, что-нибудь найтись должно. Если нет - набросаю пример, но позже, сейчас Delphi не под рукой.

Автор: oleg2s 25.5.2012, 05:50
Нашел вот такую строку, но она выдает ошибку, что ChangeServiceConfig2 и SERVICE_CONFIG_DESCRIPTION не определены
Код

Result := ChangeServiceConfig2(Service,  SERVICE_CONFIG_DESCRIPTION, @Info);


В каком модуле определяется функция?
Как заполнить Info?

Автор: MetalFan 25.5.2012, 09:28
oleg2s, а можно напрямую в реестр записать... это описание сервиса.

Автор: kami 25.5.2012, 12:11
Цитата(MetalFan @  25.5.2012,  09:28 Найти цитируемый пост)
а можно напрямую в реестр записать

Можно-то оно конечно можно smile
Помнится, на delphimaster была достаточно большая дискуссия на эту тему - пользоваться функцией или реестром. В конечном итоге (само собой - к единому знаменателю так и не пришли), но был сделан промежуточный вывод, что использовать реестр для этой цели можно, но не совсем правильно, т.к. установка Description через реестр документирована неявно и использовать ее можно так же как и остальное недокументированное - на свой страх и риск. 
Правда, этот "страх и риск" действует от начала появления сервисов и как минимум до Win7 smile

Автор: oleg2s 25.5.2012, 14:24
Цитата(kami @ 25.5.2012,  12:11)
Цитата(MetalFan @  25.5.2012,  09:28 Найти цитируемый пост)
а можно напрямую в реестр записать

Можно-то оно конечно можно smile
Помнится, на delphimaster была достаточно большая дискуссия на эту тему - пользоваться функцией или реестром. В конечном итоге (само собой - к единому знаменателю так и не пришли), но был сделан промежуточный вывод, что использовать реестр для этой цели можно, но не совсем правильно, т.к. установка Description через реестр документирована неявно и использовать ее можно так же как и остальное недокументированное - на свой страх и риск. 
Правда, этот "страх и риск" действует от начала появления сервисов и как минимум до Win7 smile

Напрямую писать в реестр мне очень не хочется, т.к. считаю в данном случае, это дурной тон.

Автор: northener 25.5.2012, 14:38
Цитата(kami @  25.5.2012,  12:11 Найти цитируемый пост)
Помнится, на delphimaster была достаточно большая дискуссия на эту тему

http://www.delphimaster.net/view/4-1130765521

Автор: kami 25.5.2012, 18:25
northener, точно, я же тогда участвовал в этой ветке smile даже пытался умные мысли (которых у меня тогда не было, но я об этом не знал smile ) толкать.
Цитата(oleg2s @  25.5.2012,  14:24 Найти цитируемый пост)
Напрямую писать в реестр мне очень не хочется, т.к. считаю в данном случае, это дурной тон.
Цитата(oleg2s @  25.5.2012,  05:50 Найти цитируемый пост)
В каком модуле определяется функция?

В стандартных модулях Delphi - нет определения. Можно или объявить самому, или воспользоваться JEDI API (правда, там объявлены не все структуры и константы, воспринимаемые рассматриваемой функцией, но того что есть хватит). Если дальнейшие планы сильно затрагивают использование WinAPI - настоятельно рекомендую скачать. Если же нет - то проще объявить в своем модуле.
Цитата(oleg2s @  25.5.2012,  05:50 Найти цитируемый пост)
Как заполнить Info?

Туда "запихивается" указатель на предварительно заполненную структуру SERVICE_DESCRIPTION. Само собой - объявления SERVICE_DESCRIPTION в стандартных модулях тоже нет.

Кстати, небольшое дополнение - правильно работает только ChangeServiceConfig2W. C A вариантом какие-то траблы - не полностью воспринимает LPStr в каких-то параметрах.

Какая версия Delphi?
Сам какой-нибудь код набросал уже? А то мне не терпится выложить на всеобщее поругание "усовершенствованный" SvcMgr.pas smile

Автор: northener 26.5.2012, 02:00
Цитата(kami @  25.5.2012,  18:25 Найти цитируемый пост)
northener, точно, я же тогда участвовал в этой ветке

delphimaster помнит своих героев! 
smile

Автор: MetalFan 27.5.2012, 21:55
Цитата(kami @  25.5.2012,  18:25 Найти цитируемый пост)
А то мне не терпится выложить на всеобщее поругание "усовершенствованный" SvcMgr.pas

Ну так выкладывай, коли не терпится!
Пригодиться я думаю. А мы с радостью "покритикуем" или "похвалим")
Только давай отдельной темой в разделе WinApi.

Автор: oleg2s 28.5.2012, 06:45
Цитата(kami @  25.5.2012,  18:25 Найти цитируемый пост)
Сам какой-нибудь код набросал уже? А то мне не терпится выложить на всеобщее поругание "усовершенствованный" SvcMgr.pas 

А что я могу написать, если функция не описана и выдает ошибки?
Я поэтому и задаю вопросы. Хотелось бы конкретных пример описания сервиса без лишнего кода.

Автор: kami 28.5.2012, 07:11
Цитата(oleg2s @  28.5.2012,  06:45 Найти цитируемый пост)
А что я могу написать, если функция не описана и выдает ошибки?

понятно. Плохо, что не воспользовался
Цитата(kami @  25.5.2012,  18:25 Найти цитируемый пост)
JEDI API (правда, там объявлены не все структуры и константы, воспринимаемые рассматриваемой функцией, но того что есть хватит)

Используемые типы:
Код

  SERVICE_DESCRIPTION = record
    lpDescription: PChar;
  end;
  TServiceDescription = SERVICE_DESCRIPTION;
  PServiceDescription = ^SERVICE_DESCRIPTION;

  TChangeServiceConfig2 = function(scHandle: SC_HANDLE; dwInfoLevel: DWord; lpInfo: pointer): BOOL; stdcall;

глобальные переменные:
Код

var
  advapi32: THandle;
  ChangeServiceConfig2: TChangeServiceConfig2;

Инициализация функций. Я почти всегда (не знаю почему) использую для этого секцию инициализации:
Код

initialization
advapi32 := LoadLibrary('advapi32.dll');
if advapi32 <> 0 then
    ChangeServiceConfig2 := GetProcAddress(advapi32, 'ChangeServiceConfig2W');
else
    ChangeServiceConfig2 := nil;

finalization
FreeLibrary(advapi32);


ну и сама работа:
Код

function TService.GetServiceHandles(var SCManagerHandle, ServiceHandle: THandle): Boolean;
begin
  Result := False;
  SCManagerHandle := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
  if SCManagerHandle <> 0 then
    begin
      ServiceHandle := OpenService(SCManagerHandle, PChar(Name), SERVICE_ALL_ACCESS);
      if ServiceHandle <> 0 then
        Result := True
      else
        CloseServiceHandle(SCManagerHandle);
    end;
end;

procedure TService.FreeServiceHandles(SCManagerHandle, ServiceHandle: THandle);
begin
  CloseServiceHandle(ServiceHandle);
  CloseServiceHandle(SCManagerHandle);
end;

procedure TService.SetDescription(const Value: String);
var
  Desc: TServiceDescription;
  hSCM, hService: THandle;
begin
  if Assigned(ChangeServiceConfig2) then
    if GetServiceHandles(hSCM, hService) then
      begin
        FDescription := Value;
        //Desc := AllocMem(SizeOf(TServiceDescription));
        Desc.lpDescription := AllocMem(Length(Description) * SizeOf(Char) + SizeOf(Char));

        Move(Description[1], Desc.lpDescription^, Length(Description) * SizeOf(Char));
        ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, @Desc);

        FreeMem(Desc.lpDescription);
        //FreeMem(pDesc);

        FreeServiceHandles(hSCM, hService);
      end;
end;

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)