Отладка сервисов!!!
От: Yanish  
Дата: 18.02.04 07:41
Оценка:
Я почитал многое по поводу отладки сервисов. Чего только не предлагали:

1. написать сначала простой exe а потом перенести в проект с сервисом;
2. запускать сервис и потом атачить его из делфи;
.
.
.



И всё ето не то!!!


А ктонибудь знает что нужно сделать, чтобы сервис можно было отлаживать как обыкновенный exe`шник, нажал F9 и всё прекрасно начинает проверяться!!!!!!!



Заранее спасибо за то что посмотрели!!!
Re: Отладка сервисов!!!
От: Аноним  
Дата: 18.02.04 09:02
Оценка:
Здравствуйте, Yanish, Вы писали:

Y>Я почитал многое по поводу отладки сервисов. Чего только не предлагали:


Ну вот и еще одно предложение...

Создать обычное Service приложение.
Добавить в него новую форму.
Изменить файл .dpr проекта следующим образом.
program SmpService;

uses
  SvcMgr,
  Forms,
  srvMain in 'srvMain.pas' {Service1: TService},
  frmMain in 'frmMain.pas' {MainForm};

{$R *.RES}

begin
  SvcMgr.Application.Initialize;
  SvcMgr.Application.CreateForm(TService1, Service1);
  SvcMgr.Application.Run;
  // this isn't a service application, and we've creating the MainForm to debug
  // But if application runned by Windows Service manager, don't create anything
  if (not Service1.SrvcRunning) then begin
    Forms.Application.Initialize;
    Forms.Application.CreateForm(TMainForm, MainForm);
    MainForm.Show;
    MainForm.Update;
    Service1.OnExecute(Service1);
  end;
end.


В обработчик события
Service1.OnExecute
добавить следующий код:

procedure TService1.ServiceExecute(Sender: TService);
var
  bIsService: Boolean;
begin
  bIsService := not Assigned(MainForm);
  while (Assigned(MainForm) or (bIsService and (not Terminated))) do
    try
      if (bIsService) then ServiceThread.ProcessRequests(True)
      else Forms.Application.HandleMessage();
    except {...} end;
end;


В класс службы добавить свойство
property SrvcRunning: Boolean read FSrvcRunning write SetSrvcRunning;
,
которое необходимо установить в
True
при запуске службы из SCM т.е.
в обработчик события
Service1.OnStart
добавить следующий код

procedure TService1.ServiceStart(Sender: TService; var Started: Boolean);
begin
  FSrvcRunning := True;
end;

Это свойство необходимо для определения типа запуска приложения (из SCM или как простое приложение)

Вот собственно и все, один небольшой минус — иногда программа запускается довольно (20-30 сек.).., а ХЗ почему...
Re: Отладка сервисов!!!
От: Sinclair Россия https://github.com/evilguest/
Дата: 18.02.04 09:36
Оценка: 2 (1)
Здравствуйте, Yanish, Вы писали:

Y>

Y>А ктонибудь знает что нужно сделать, чтобы сервис можно было отлаживать как обыкновенный exe`шник, нажал F9 и всё прекрасно начинает проверяться!!!!!!!

Вроде бы ничего. Ты вообще себе представляешь, как работает отладчик? Ему нужно, грубо говоря, знать ProcessHandle. Для обычных приложений нажатие F9 приводит к тому, что среда получает хэндл при помощи CreateProcess и тут же аттачит дебаггер к нему. Для dll делается то же самое, только запускается не свежескомпиленный экзешник, а тот, который указан в Host Application.
Запуском сервиса ведает специальная штука в винде, svcmgr. Поэтому самая правильная отладка сервиса — это аттач к нему после старта. К сожалению, стандартный Delphi настроить таким образом нельзя.
Надо отметить, что потенциально ToolsAPI позволяет написать плугин к IDE, который будет проверять, не сервисное ли приложение мы пишем, и если да, то по F9
— проверять, скомпилирован ли Exe
— если надо компилировать, проверять, стартован ли сервис
— если надо, стопать сервис
— компилировать
— если надо, регистрировать сервис
— стартовать сервис
— ловить его ProcessID
— аттачиться к сервису
Пока что я таких плугов не видел. Хочешь написать?
... << RSDN@Home 1.1.3 beta 2 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Отладка сервисов!!!
От: Yanish  
Дата: 19.02.04 04:25
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Пока что я таких плугов не видел. Хочешь написать?


Да хотел бы, копаю потихоньку в этом направлении ....
... << RSDN@Home 1.1.3 beta 1 >>
Re[2]: Отладка сервисов!!!
От: Yanish  
Дата: 19.02.04 04:40
Оценка:
Здравствуйте, <Аноним>, Вы писали:

Спасибо!!! я попробую, но считаю что это ЖЕСТКО .
а запускается долго: видимо потому что подгружает scm ... наверное (это просто предположение!!!)
... << RSDN@Home 1.1.3 beta 1 >>
Re[3]: Отладка сервисов!!!
От: ironwit Украина  
Дата: 11.08.06 13:00
Оценка:
Здравствуйте, Yanish, Вы писали:

Y>Здравствуйте, Sinclair, Вы писали:


S>>Пока что я таких плугов не видел. Хочешь написать?


Y>Да хотел бы, копаю потихоньку в этом направлении ....


что накопал?
Я не умею быть злым, и не хочу быть добрым.
Re[4]: Отладка сервисов!!!
От: Danchik Украина  
Дата: 11.08.06 13:40
Оценка:
Здравствуйте, ironwit, Вы писали:

I>Здравствуйте, Yanish, Вы писали:


Y>>Здравствуйте, Sinclair, Вы писали:


S>>>Пока что я таких плугов не видел. Хочешь написать?


Y>>Да хотел бы, копаю потихоньку в этом направлении ....


I>что накопал?


Можна и написать если такого нет. Необходимые знания есть...
Попробую на выходных накалякать Действительно может получится полезная штука.
Только думаю что это будет специятельная кнопочка. Честно влом парсить проэкт на наличие Service Datamodule. Ну и кроме того, сервис можна написать и без стандартной реализации (SvcMgr.pas) или програма может быть написана для работы в двух режимах: GUI и Service.
Re: Отладка сервисов!!!
От: glh Россия  
Дата: 11.08.06 14:01
Оценка:
Здравствуйте, Yanish, Вы писали:

Y>Я почитал многое по поводу отладки сервисов. Чего только не предлагали:

Y>И всё ето не то!!!

Y>

Y>А ктонибудь знает что нужно сделать, чтобы сервис можно было отлаживать как обыкновенный exe`шник, нажал F9 и всё прекрасно начинает проверяться!!!!!!!


Самый простой вариант

Напиши так, что бы работало в 2 режимах, как приложение и как сервис.

где нибудь, у меня в exSvcUtils
var//Глобальная переменная, должна показывать что исполняемся в режиме сервиса
  IsService: Boolean = False;

{ Сервис запущен в режиме установки/удаления }
function SvcIsInstallMode: Boolean;
begin
  Result := FindCmdLineSwitch('INSTALL') or FindCmdLineSwitch('UNINSTALL');
end;

{ Проверяем возможность запуска в режиме сервиса, TRUE если можем }
function SvcCanStart(const sSvc: string; sUser: string = ''): Boolean;
var
  schm: SC_Handle;// service control manager handle
  schs: SC_Handle;// service handle
  ServiceStartName: string;
  lpqscConfig: PQueryServiceConfig;
  dwSize: DWord;
  s: string;
begin
  Result := False;
  schm := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
  if _failed(schm) then Exit;

  schs := OpenService(schm, PChar(sSvc), SERVICE_ALL_ACCESS);
  if _failed(schs) then Exit;

  dwSize := 0;
  QueryServiceConfig(schs, nil, 0, dwSize);
  lpqscConfig := AllocMem(dwSize);
  try
    QueryServiceConfig(schs, lpqscConfig, dwSize, dwSize);
    ServiceStartName := PQueryServiceConfig(lpqscConfig)^.lpServiceStartName;
    if SameText(ServiceStartName, 'LocalSystem') then
      ServiceStartName := 'SYSTEM';
  finally
    Dispose(lpqscConfig);
  end;

  CloseServiceHandle(schs);
  CloseServiceHandle(schm);

  sUser := GetCompUser();
  // здесь пытаемся обработать ситуацию когда указано от имени кого запускать сервис
  if Pos('@', ServiceStartName) <> 0 then begin
    s := RegStringValueGet('System\CurrentControlSet\Services\Tcpip\Parameters', 'Domain', HKEY_LOCAL_MACHINE);
    if s <> '' then
      sUser := sUser +'@'+ s;
  end;

  Result := SameText(ServiceStartName, sUser);
end;


UsesCommon.inc
    exSvcDesktop//must be FIRST!
  , exSvcUtils
  , SvcMgr
  , Forms
  rmTypes in '..\..\rm.common\rmTypes.pas',
  ServiceOptions in '..\svc.common\ServiceOptions.pas',
  ServiceCommon in '..\svc.common\ServiceCommon.pas',
  CmdProcessor in '..\svc.common\CmdProcessor.pas',
  SrvCmdDecoder in '..\svc.common\SrvCmdDecoder.pas',
  dMain in '..\svc.common\dMain.pas' {dmMain: TDataModule},


PrjCommon.inc:
  if SvcIsInstallMode() or SvcCanStart(GetServiceName())
    then begin// Start as service
      SvcMgr.Application.Initialize;
      exSvcUtils.IsService := True;
      SvcMgr.Application.CreateForm(TdmMain, dmMain);
      // удален ресурс, поэтому создаем из кода
      svcService := TsvcServiceCommon.CreateNew(SvcMgr.Application);
      SvcMgr.Application.Run;
    end
    else begin// Start as application
      Application.Initialize;
      Application.CreateForm(TdmMain, dmMain);
      while not Application.Terminated do
        Application.HandleMessage;
      Application.Terminate;
    end;


пример проекта:
program mngFTPin;

uses
{$I ..\svc.common\UsesCommon.inc}
  ftpLoaders in '..\svc.common\ftpLoaders.pas',
  ftpInServiceMng in 'ftpInServiceMng.pas';

{$R '..\svc.res\mainicon.res' '..\svc.res\mainicon.rc'}
{$R 'VersionInfo.res' 'VersionInfo.rc'}

begin
{$I ..\svc.common\PrjCommon.inc}
end.


PS. 3 дюжины сервисов замучался бы отлаживать.
Успехов!
C уважением, Алексей.
------------------------------------------------
Хороших %s не бывает — бывает не худший вариант.
Re[2]: Отладка сервисов!!!
От: Danchik Украина  
Дата: 11.08.06 14:31
Оценка:
Здравствуйте, glh, Вы писали:

glh>Самый простой вариант


glh>Напиши так, что бы работало в 2 режимах, как приложение и как сервис.


[Skip]

Плохо что в коде SC_MANAGER_ALL_ACCESS и SERVICE_ALL_ACCESS. Не все же юзера администраторы

Мне не нравится SvcCanStart. Зачем сие? Тут нужно узнать запустил ли процес Service Manager или мы просто тыкнули в в иконку
Простенький пример я писал вот здесь
Автор: Danchik
Дата: 24.07.06

Но со временем у меня появился более навороченный вариант .

Код портирован мною с С++. Источник: http://win32.mvps.org/security/is_svc.html.

This code fragment determines whether the current process is running interactively or as a service (services running in a real user account have a SID with SECURITY_SERVICE_RID in their token; console processes have a SID with SECURITY_INTERACTIVE_RID; services running as BUILTIN\SYSTEM [LocalSystem] have neither). If the process is a LocalSystem service, the fragment checks for interactive access to the desktop, too.

Kudos to Rohan Philips for sharing this!


type
  TDServiceUtils = class
  protected
    class function InternalIsService(out IsService, IsInteractive : Boolean): Integer;
  public
    ....
    class function IsService: Boolean;
  end;

implementation

class function TDServiceUtils.IsService: Boolean;
var
  aIsService : Boolean;
  aIsInteractive : Boolean;
begin
  aIsService := False;
  Result := (InternalIsService (aIsService, aIsInteractive) <> 0) or aIsService;
end;

class function TDServiceUtils.InternalIsService(out IsService, IsInteractive : Boolean): Integer;
var
  hProcessToken: THandle;
  groupLength: Cardinal;
  groupInfo: PTokenGroups;
  siaNt: SID_IDENTIFIER_AUTHORITY;
  pInteractiveSid: PSID;
  pServiceSid: PSID;
  ndx: Cardinal;
  sanda: SID_AND_ATTRIBUTES;
  aSid: PSID;
  aKey: HKEY;
  aStrKey: string;
  aServiceName: string;
  dwType: Cardinal;
  dwSize: Cardinal;
begin
  hProcessToken := 0;
  groupLength   := 50;
  groupInfo     := nil;

  siaNt := SECURITY_NT_AUTHORITY;
  pInteractiveSid := nil;
  pServiceSid := nil;

  Result := NO_ERROR;

  try
    // open the token
    if not OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, hProcessToken) then
    begin
      Result := GetLastError;
      Exit;
    end;

    // allocate a buffer of default size
    groupInfo := AllocMem (groupLength);

    // try to get the info
    if not GetTokenInformation(hProcessToken, TokenGroups,
      groupInfo, groupLength, groupLength) then
    begin
      // if buffer was too small, allocate to proper size, otherwise error
      if GetLastError <> ERROR_INSUFFICIENT_BUFFER then
      begin
        Result := GetLastError;
        Exit;
      end;

      FreeMem(groupInfo);

      groupInfo := AllocMem(groupLength);

      if not GetTokenInformation(hProcessToken, TokenGroups,
        groupInfo, groupLength, groupLength) then
      begin
        Result := GetLastError;
        Exit;
      end;
    end;

    //
    //  We now know the groups associated with this token.  We want
    //  to look to see if the interactive group is active in the
    //  token, and if so, we know that this is an interactive process.
    //
    //  We also look for the "service" SID, and if it's present,
    //  we know we're a service.
    //
    //  The service SID will be present iff the service is running in a
    //  user account (and was invoked by the service controller).
    //

    // create comparison sids
    if not AllocateAndInitializeSid(siaNt, 1, SECURITY_INTERACTIVE_RID,
      0, 0, 0, 0, 0, 0, 0, pInteractiveSid) then
    begin
      Result := GetLastError;
      Exit;
    end;

    if not AllocateAndInitializeSid(siaNt, 1, SECURITY_SERVICE_RID,
      0, 0, 0, 0, 0, 0, 0, pServiceSid) then 
    begin
      Result := GetLastError;
      Exit;
    end;


    // reset flags
    IsInteractive := False;
    IsService := False;

    // try to match sids
    ndx := 0;
    while ndx < groupInfo.GroupCount do
    begin
      sanda := groupInfo.Groups[ndx];
      aSid  := sanda.Sid;

      //
      //  Check to see if the group we're looking at is one of
      //  the two groups we're interested in.
      //

      if EqualSid(aSid, pInteractiveSid) then
      begin
        //
        //  This process has the Interactive SID in its
        //  token.  This means that the process is running as
        //  a console process
        //
        IsInteractive := True;
        IsService := False;
        Break;
      end else
        if EqualSid(aSid, pServiceSid) then
        begin
          //
          //  This process has the Service SID in its
          //  token.  This means that the process is running as
          //  a service running in a user account ( not local system ).
          //
          IsService := True;
          IsInteractive := False;
          Break;
        end;

      Inc (ndx);
    end;

    if not (IsService or IsInteractive) then
    begin
      //
      //  Neither Interactive or Service was present in the current
      //  users token, This implies that the process is running as
      //  a service, most likely running as LocalSystem.
      //
      IsService := True;

      // determine if the local system service is interactive.  We
      // do this y looking in the service's registry and checking
      // the Type value for the SERVICE_INTERACTIVE_PROCESS bit

      aKey := 0;

      aStrKey := Format ('SYSTEM\CurrentControlSet\Services\%s', [aServiceName]);
      if RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                 PChar (aStrKey),
                 0,
                 KEY_READ,
                 aKey) = ERROR_SUCCESS then
      begin
        dwType := 0;
        dwSize := sizeof(DWORD);
        if RegQueryValueEx(aKey,
                   PChar ('Type'),
                   nil,
                   nil,
                   @dwType,
                   @dwSize) = ERROR_SUCCESS then
        begin
          if (dwType and SERVICE_INTERACTIVE_PROCESS) <> 0 then
            IsInteractive := True;
        end;

        RegCloseKey(aKey);
      end;


    end;
  finally
    if pServiceSid <> nil then
      FreeSid (pServiceSid);

    if pInteractiveSid <> nil then
      FreeSid (pInteractiveSid);

    if groupInfo <> nil then
      FreeMem (groupInfo);

    if hProcessToken <> 0 then
      CloseHandle (hProcessToken);
  end;

end;

Надеюсь комуто это будет полезно.
Re[5]: Отладка сервисов!!!
От: ironwit Украина  
Дата: 11.08.06 14:59
Оценка:
Здравствуйте, Danchik, Вы писали:

D>Здравствуйте, ironwit, Вы писали:


I>>Здравствуйте, Yanish, Вы писали:


Y>>>Здравствуйте, Sinclair, Вы писали:


S>>>>Пока что я таких плугов не видел. Хочешь написать?


Y>>>Да хотел бы, копаю потихоньку в этом направлении ....


I>>что накопал?


D>Можна и написать если такого нет. Необходимые знания есть...

было бы здорово
... << RSDN@Home 1.2.0 alpha rev. 655>>
Я не умею быть злым, и не хочу быть добрым.
Re[2]: Отладка сервисов!!!
От: ironwit Украина  
Дата: 11.08.06 14:59
Оценка:
Здравствуйте, glh, Вы писали:

glh>Здравствуйте, Yanish, Вы писали:


Y>>Я почитал многое по поводу отладки сервисов. Чего только не предлагали:

Y>>И всё ето не то!!!

Y>>

Y>>А ктонибудь знает что нужно сделать, чтобы сервис можно было отлаживать как обыкновенный exe`шник, нажал F9 и всё прекрасно начинает проверяться!!!!!!!


glh>Самый простой вариант


glh>Напиши так, что бы работало в 2 режимах, как приложение и как сервис.

у меня вот здесь com сервер и NT service
Автор: ironwit
Дата: 11.08.06
как приложение все работает, не работает именно в сервисе.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Я не умею быть злым, и не хочу быть добрым.
Re: Отладка сервисов!!!
От: Lepsik Индия figvam.ca
Дата: 14.08.06 04:34
Оценка:
я правда пишу в билдере, но думаю идея понятна


WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR cmd_line, int)
{
    g_Service = true;

    vector<string> lst_param;
    prs::parser( lst_param, cmd_line, ' ');

    try
    {
        Application->Initialize();
        Application->Title = "IPS Zip Service";
        Application->CreateForm(__classid(TmainZip), &mainZip);

        bool IsDebug = ( find( lst_param.begin(), lst_param.end(), "-debug" ) != lst_param.end() );
        if( IsDebug )
        {
 //  тут переходит к функции, котору также вызывает сервис на событие  
            if( mainZip->ServiceDebug() )
            {
                mainZip->CheckFolder( import_type, isForce, ForcedStatus );
            }


то есть если в командной строке proga.exe -debug тогда вызывается ветка отладки
Re[3]: Отладка сервисов!!!
От: glh Россия  
Дата: 14.08.06 06:59
Оценка:
Здравствуйте, Danchik, Вы писали:

D>Плохо что в коде SC_MANAGER_ALL_ACCESS и SERVICE_ALL_ACCESS. Не все же юзера администраторы


Определяется еще и внешними условиями.
C превеликим бы удовольствием работал под System по умолчанию.
Тк Администратор не может настроить мне доступ для учетной записи Network Service для корректного исп-я шар на других машинах.
Учетная запись, из-под которой запускаеться эта группа сервисов имеет права администратора.

D>Мне не нравится SvcCanStart. Зачем сие? Тут нужно узнать запустил ли процес Service Manager или мы просто тыкнули в в иконку

, если можем запуститься как сервис-запускаемся как сервис.
Успехов!
C уважением, Алексей.
------------------------------------------------
Хороших %s не бывает — бывает не худший вариант.
Re[4]: Отладка сервисов!!!
От: Danchik Украина  
Дата: 14.08.06 12:03
Оценка:
Здравствуйте, glh, Вы писали:

glh>Здравствуйте, Danchik, Вы писали:


D>>Плохо что в коде SC_MANAGER_ALL_ACCESS и SERVICE_ALL_ACCESS. Не все же юзера администраторы


glh>Определяется еще и внешними условиями.

glh>C превеликим бы удовольствием работал под System по умолчанию.
glh>Тк Администратор не может настроить мне доступ для учетной записи Network Service для корректного исп-я шар на других машинах.
glh>Учетная запись, из-под которой запускаеться эта группа сервисов имеет права администратора.

Я просто намекаю на то, что можна было обойтись более легкими правами доступа. Тем более что это у вас в какой-то либе. А либы должны быть написаны как можна качественней. Кусок моей либы, для примера, вы видели.

D>>Мне не нравится SvcCanStart. Зачем сие? Тут нужно узнать запустил ли процес Service Manager или мы просто тыкнули в в иконку

glh>, если можем запуститься как сервис-запускаемся как сервис.

Мне всегда нужно было наоборот (и практически всем), сли запускаем не из SvcManager — то работаем как Desktop програма.
Re: Отладка сервисов!!!
От: Аноним  
Дата: 22.08.06 17:45
Оценка:
Здравствуйте, Yanish, Вы писали:

Y>

Y>А ктонибудь знает что нужно сделать, чтобы сервис можно было отлаживать как обыкновенный exe`шник, нажал F9 и всё прекрасно начинает проверяться!!!!!!!



svcom — есть такой продукт для работы с сервисами и иже с ними в Delphi. Алексей Дынников, автор этого продукта поможет Вам информацией более профессионально нежели средний RSDN-овец. Ибо занимается он этим давно и успешно. Копай в сторону aldyn-software.com
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.