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


Автор: Гость_Felt 4.7.2005, 04:21
Написал сервис. Отдельно написал программу установки сервиса. Но похоже в сервисе был глюк и его запуск так и не состоялся. В результате теперь он сидит в "Службах" при этом недоступны все задачи в контекстном меню. Мало того, я не могу его еще и удалить. Использую функцию DeleteService. Менеджер открываю с правами SERVICE_ACCESS_ALL. Как удалить сервис? Как правильно его тестировать?
Все целиком писал на API.

Автор: SoWa 4.7.2005, 05:27
А ты попробуй его запусти еще разок, потом прекрати выполнение сервиса, а потом удаляй. А удалить не можешь потому, что он каким-то образом запущен.

Автор: Guest 4.7.2005, 09:43
теперь я не могу его ни запустить, ни удалить. когда изменяю тип запуска (авто или еще какой) и жму применить вылетает сообщение типа сервис отмечен к удалению. Перезагружаюсь, он все равно сидит в службах. Задачи недоступны: я не могу ни запустить, ни остановить.

Автор: Guest 4.7.2005, 11:20
Нет. Все ввроде удалился сервис. Только я теперь даже не знаю, а как тестировать сервис? Пока я пишу программу мне приходится несколько раз компилировать приложение и запускать его. С сервисами это как то проблематично. И еще, а IRC канала своего у вас нету?

Автор: Guest 4.7.2005, 22:53
Мне просто нужно как то быстро тестировать код без регистрации сервиса, без его удаления и т. д. Код вам не поможет, ошибку я найду сам.

Автор: Rennigth 5.7.2005, 16:07
Цитата

  Мне просто нужно как то быстро тестировать код без регистрации сервиса

ну и сделай его на время разработки простым exe-шником, или запускай свой
Добавлено @ 16:10
сервис в отладке с параметром как-нибудь /start прикотором будет запускаться он, необязательно же запускать его запускать рукими...

Автор: SoWa 5.7.2005, 19:09
Ты что, программу-сервис сразу пишешь?
Пиши просто программу, а потом таким кодом запихивай её в сервисы!

Код

function CreateNTService(ExecutablePath, ServiceName: string): boolean;
var
  hNewService, hSCMgr: SC_HANDLE;
  // Rights: DWORD;
  FuncRetVal: Boolean;
begin
  FuncRetVal := False;
  hSCMgr := OpenSCManager(nil, nil, SC_MANAGER_CREATE_SERVICE);
  if (hSCMgr <> 0) then
  begin


    hNewService := CreateService(hSCMgr, PChar(ServiceName), PChar(ServiceName),
      STANDARD_RIGHTS_REQUIRED, SERVICE_WIN32_OWN_PROCESS,
      SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
      PChar(ExecutablePath), nil, nil, nil, nil, nil);
    CloseServiceHandle(hSCMgr);
    if (hNewService <> 0) then
      FuncRetVal := true
    else
      FuncRetVal := false;
  end;
  CreateNTService := FuncRetVal;
end;


function DeleteNTService(ServiceName: string): boolean;
var
  hServiceToDelete, hSCMgr: SC_HANDLE;
  RetVal: LongBool;
  FunctRetVal: Boolean;
begin
  FunctRetVal := false;
  hSCMgr := OpenSCManager(nil, nil, SC_MANAGER_CREATE_SERVICE);
  if (hSCMgr <> 0) then
  begin
    hServiceToDelete := OpenService(hSCMgr, PChar(ServiceName),
      SERVICE_ALL_ACCESS);
    RetVal := DeleteService(hServiceToDelete);
    CloseServiceHandle(hSCMgr);
    FunctRetVal := RetVal;
  end;
  DeleteNTService := FunctRetVal;
end;

function ServiceStart(aMachine, aServiceName: string ): boolean;
// aMachine это UNC путь, либо локальный компьютер если пусто
var
  h_manager,h_svc: SC_Handle;
  svc_status: TServiceStatus;
  Temp: PChar;
  dwCheckPoint: DWord;
begin
  svc_status.dwCurrentState := 1;
  h_manager := OpenSCManager(PChar(aMachine), nil, SC_MANAGER_CONNECT);
  if h_manager > 0 then
  begin
    h_svc := OpenService(h_manager, PChar(aServiceName),
    SERVICE_START or SERVICE_QUERY_STATUS);
    if h_svc > 0 then
    begin
      temp := nil;
      if (StartService(h_svc,0,temp)) then
        if (QueryServiceStatus(h_svc,svc_status)) then
        begin
          while (SERVICE_RUNNING <> svc_status.dwCurrentState) do
          begin
            dwCheckPoint := svc_status.dwCheckPoint;
            Sleep(svc_status.dwWaitHint);
            if (not QueryServiceStatus(h_svc,svc_status)) then
              break;
            if (svc_status.dwCheckPoint < dwCheckPoint) then
            begin
              // QueryServiceStatus не увеличивает dwCheckPoint
              break;
            end;
          end;
        end;
      CloseServiceHandle(h_svc);
    end;
    CloseServiceHandle(h_manager);
  end;
  Result := SERVICE_RUNNING = svc_status.dwCurrentState;
end;


function ServiceStop(aMachine,aServiceName: string ): boolean;
// aMachine это UNC путь, либо локальный компьютер если пусто
var
  h_manager, h_svc: SC_Handle;
  svc_status: TServiceStatus;
  dwCheckPoint: DWord;
begin
  h_manager:=OpenSCManager(PChar(aMachine),nil, SC_MANAGER_CONNECT);
  if h_manager > 0 then
  begin
    h_svc := OpenService(h_manager,PChar(aServiceName),
    SERVICE_STOP or SERVICE_QUERY_STATUS);
    if h_svc > 0 then
    begin
      if(ControlService(h_svc,SERVICE_CONTROL_STOP, svc_status))then
      begin
        if(QueryServiceStatus(h_svc,svc_status))then
        begin
          while(SERVICE_STOPPED <> svc_status.dwCurrentState)do
          begin
            dwCheckPoint := svc_status.dwCheckPoint;
            Sleep(svc_status.dwWaitHint);
            if(not QueryServiceStatus(h_svc,svc_status))then
            begin
              // couldn't check status
              break;
            end;
            if(svc_status.dwCheckPoint < dwCheckPoint)then
              break;
          end;
        end;
      end;
      CloseServiceHandle(h_svc);
    end;
    CloseServiceHandle(h_manager);
  end;
  Result := SERVICE_STOPPED = svc_status.dwCurrentState;
end;

Это все, что нужно дл яработы с сервисами!

Автор: Guest 7.7.2005, 03:00
SoWaЯ об этом уже думал, но мне нужно правильно реагировать на остановку сервиса, запуск, приостановку. Поэтому все так нужно писать сервис.

Автор: Elfix 14.7.2005, 13:14
Установил свой сервис выше приведенными функциями. Сервис установился, но запускаться не стал. Пришлось вручную его запускать, в выпадающем списке выбрал тип запуска Авто и нажал кнопку Пуск. Взамен получил окно "Не удалось запустить службу на Локальный компьютер. Служба не ответила на запрос своевременно".
Мне нужно:
1. Установить службу и запустить ее с типом запуска Авто
2. Установить службу не только из под админского сеанса, но и с любого другого.

P. S. Моя программа не сервис, но судя по всему любую прогу можно запустить как сервис.

Автор: Elfix 17.7.2005, 16:55
Неужели никто никогда не работал с сервисами Windows?

Автор: Girder 17.7.2005, 17:54
Цитата(Elfix @ 17.7.2005, 17:55)
Неужели никто никогда не работал с сервисами Windows?
Работали... работаем... будем работать.

Мы же тут не телепаты... smile Нужен код... или на худой конец тип сервиса... и в чем проблемма.

Автор: Elfix 18.7.2005, 09:44
Для примера, есть такая программа:
Код
program Project1;

uses
  Windows,
  WinSvc;

var
 hTh, hThread: THandle;

procedure ThreadProc; stdcall;
begin
 while True do
  begin

  end;
end;

procedure CreateService(ServiceName, ExecutablePath: String);
var
 hSCMgr, hService: SC_HANDLE;
begin
 hSCMgr:=OpenSCManager(nil, nil, SC_MANAGER_CREATE_SERVICE);
 if hSCMgr <> 0 then
  begin
   hService:=WinSvc.CreateService(hSCMgr, PChar(ServiceName), PChar(ServiceName), STANDARD_RIGHTS_REQUIRED, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, PChar(ExecutablePath), nil, nil, nil, nil, nil);
   CloseServiceHandle(hSCMgr);
   if hService <> 0 then
    CloseServiceHandle(hService);
  end;
end;

procedure CheckParams;
var
 i: Byte;
begin
 for i:=1 to ParamCount do
  if ParamStr(i) = '/install' then
   begin
    CreateService('TestService', ParamStr(0));
    ExitProcess(0);
   end;
end;

begin
 CheckParams;
 hThread:=CreateThread(nil, 0, @ThreadProc, 0, 0, hTh);
 WaitForSingleObject(hThread, INFINITE);
 CloseHandle(hThread);
end.
Если программа запущена с параметром /install то происходит автоматическая установка сервиса. После я пытаюсь через панель управления запустить сервис, но ничего не выходит. Менеджер очень долго пытается запустить сервис, но в результате выдает ошибку.

Автор: Girder 18.7.2005, 09:57
Понятно... smile

Для начала сделай вот так:

1. File->New->Other->Service Application

2. http://forum.vingrad.ru/index.php?showtopic=43453&view=findpost&p=336679

Как сделаеш... продолжим.

Автор: Elfix 18.7.2005, 11:27
Попробовал сделать так как ты предложил. Сервис установился, потом я его вручную запустил. Все прошло прекрасно. Только мне нужно полностью отказаться от использования встроенных средств Delphi и все сделать только на чистом API. Я не могу понять в чем происходит ошибка, почему сервис не запускается?
Добавлено @ 11:29
Говорят, что любую программу можно запустить как сервис. Мне важно, чтобы прога работала или как обычная прога (в 98x) или как сервис (XP по желанию пользователя, т. е. если он сам запустит с параметром /install).

Автор: Girder 19.7.2005, 11:09
Вот пример накатал... изучай:
Код
program gServ;

uses
  Windows, WinSvc, Messages;

{$R *.res}

type
 TSysCharSet=set of Char;
 TCurrentStatus=(csStopped,csStartPending,csStopPending,csRunning,
                 csContinuePending,csPausePending,csPaused);


var tID,hThread:DWord;
    FStatusHandle:DWord;
    Name:string;
    OldExitProc:Pointer;
    STE:array [0..1] of _Service_Table_Entrya;
    Status:TCurrentStatus;
    AppStart:Boolean;

function AnsiCompareText(const S1, S2: string): Integer;
begin
 Result:=CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, PChar(S1), Length(S1), PChar(S2), Length(S2)) - 2;
end;

procedure ReportStatus;
const
 LastStatus:TCurrentStatus = csStartPending;
 NTServiceStatus: array[TCurrentStatus] of Integer =
                  (SERVICE_STOPPED,SERVICE_START_PENDING,
                   SERVICE_STOP_PENDING,SERVICE_RUNNING,
                   SERVICE_CONTINUE_PENDING,SERVICE_PAUSE_PENDING,SERVICE_PAUSED);
 PendingStatus: set of TCurrentStatus = [csStartPending,csStopPending,
                                         csContinuePending,csPausePending];
var
  ServiceStatus: TServiceStatus;
begin
 with ServiceStatus do
  begin
   dwWaitHint:=5000;
   dwServiceType:=SERVICE_WIN32_OWN_PROCESS;
   if Status=csStartPending then dwControlsAccepted:=0 else
    dwControlsAccepted:=SERVICE_ACCEPT_SHUTDOWN or SERVICE_ACCEPT_STOP or SERVICE_ACCEPT_PAUSE_CONTINUE;
   if (Status in PendingStatus)and(Status=LastStatus) then
    Inc(dwCheckPoint) else dwCheckPoint:=0;
   dwCurrentState:=NTServiceStatus[Status];
   dwWin32ExitCode:=0;
   dwServiceSpecificExitCode:=0;
   SetServiceStatus(FStatusHandle, ServiceStatus);
  end;
end;


function ThreadProc(Param:Pointer):DWord; stdcall;
begin
 //главная функции программы - здесь должен быть основной код сервиса.
 //Result:=0;
 while true do
  begin
   Sleep(1000);
   //Какой-то код;
  end;
end;

procedure Handler(CtrlCode: DWord);stdcall;
begin
 case CtrlCode of
  SERVICE_CONTROL_STOP: begin
                          Status:=csStopPending;
                          //Какой-то код;
                          TerminateThread(hThread,0);
                        end;
  SERVICE_CONTROL_SHUTDOWN: begin
                             Status:=csStopPending;
                             //Какой-то код;
                             TerminateThread(hThread,0);
                            end;
  SERVICE_CONTROL_PAUSE: begin
                          Status:=csPausePending;
                          //Какой-то код;
                          Status:=csPaused;
                          SuspendThread(hThread);
                         end;
  SERVICE_CONTROL_CONTINUE: begin
                             ResumeThread(hThread);
                             Status:=csContinuePending;
                             //Какой-то код;
                             Status := csRunning;
                            end;
  SERVICE_CONTROL_INTERROGATE: ReportStatus;
 end; 
 ReportStatus; 
end;

procedure ServiceMain(Argc: DWord; Argv: PLPSTR); stdcall;
begin
 hThread:=CreateThread(nil,0,@ThreadProc,nil,0,tID);
 FStatusHandle:=RegisterServiceCtrlHandler(PChar(Name),@Handler);
 Status:=csStartPending;
 ReportStatus();
 //Какой-то код;
 Status:=csRunning;
 //Какой-то код;
 ReportStatus();
 WaitForSingleObject(hThread,INFINITE);
 CloseHandle(hThread);
 Status:=csStopped;
 //Какой-то код;
 ReportStatus();
end;

procedure DoneServiceApplication(ex:DWord);stdcall;
begin
 ExitProc:=OldExitProc;
end;

function FindCmdLineSwitch(const Switch: string; const Chars: TSysCharSet):Boolean;
var I:Integer;
    S:string;
begin
 for I:=1 to ParamCount do
  begin
   S := ParamStr(I);
   if ((Chars=[])or(S[1] in Chars))and(AnsiCompareText(Copy(S,2,Maxint),Switch)=0) then
    begin
     Result:=True;
     Exit;
    end;
  end;
 Result:=False;
end;

function FindSwitch(const Switch: string): Boolean;
begin
 Result:=FindCmdLineSwitch(Switch,['-', '/']);
end;

function RegisterServices(Install,Start:Boolean):Boolean;
var SvcMgr:DWord;
function InstallService():Boolean;
var Svc:Integer;
    Path:string;
    lpServiceArgVectors:PChar;
begin
 Result:=false;
 Path:=ParamStr(0);
 Svc:=CreateService(SvcMgr,PChar(Name),'Аааа - Сервис',SERVICE_ALL_ACCESS,
                    SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
                    PChar(Path),'',nil,'',nil,'');
 if Svc=0 then exit;
 if Start then
  begin
   lpServiceArgVectors:=nil;
   if StartService(Svc,0,PChar(lpServiceArgVectors)) then Result:=true else DeleteService(Svc);
  end else Result:=true; 
 CloseServiceHandle(Svc);
end;
function UninstallService():Boolean;
var Svc:Integer;
    ServiceStatus:TServiceStatus;
begin
 Result:=false;
 Svc:=OpenService(SvcMgr,PChar(Name),SERVICE_ALL_ACCESS);
 if Svc=0 then exit;
 ControlService(Svc,SERVICE_CONTROL_STOP,ServiceStatus);
 if DeleteService(Svc) then Result:=true;
 CloseServiceHandle(Svc);
end;
begin
 Result:=false;
 SvcMgr:=OpenSCManager(nil,nil,SC_MANAGER_ALL_ACCESS);
 if SvcMgr=0 then exit;
 if Install then Result:=InstallService() else Result:=UninstallService();
 CloseServiceHandle(SvcMgr);
end;

begin
 AppStart:=true;//Запустить(или нет) сервис после инсталяции
 OldExitProc:=ExitProc;
 ExitProc:=@DoneServiceApplication;
 Name:='GirderX';
 if FindSwitch('INSTALL') then  RegisterServices(True,AppStart) else
  if FindSwitch('UNINSTALL') then RegisterServices(False,AppStart) else
   begin
    STE[0].lpServiceName:=PChar(Name);
    STE[0].lpServiceProc:=@ServiceMain;
    STE[1].lpServiceName:=nil;
    STE[1].lpServiceProc:=nil;
    StartServiceCtrlDispatcher(STE[0]);
   end;
end.


PS: Писать все за тебя я не стал - Лень smile

Что бы не ломать дров... почитай: http://www.rsdn.ru/article/baseserv/services_details.xml

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