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


Автор: m1nder 27.9.2009, 20:30
Здравствуйте! Подскажите как мне корректно завершить службу. Допустим есть простенький код:

Код


procedure Ttask5.ServiceExecute(Sender: TService);
begin
  sleep(10000);
  MoveFile('c:\test.pdf','d:\test.pdf');
  task3.DoPause;
While not Terminated do
ServiceThread.ProcessRequests(True);
  end;

procedure Ttask5.ServicePause(Sender: TService; var Paused: Boolean);
begin
task5.DoStart;
end;



Если вручную завершать службу, то она вылетает с ошибкой, я понимаю, что нужно обработать остановку, но вот только как?
Заранее благодарю!

Автор: Virtuals 28.9.2009, 06:13
m1nder, ничего непонятно, показывай код полностью!.
а так

Код

procedure Ttask5.ServicePause(Sender: TService; var Paused: Boolean);
begin
if смогли_паузу then Paused:=true else Paused:=false;
end;

procedure TService1.ServiceShutdown(Sender: TService);
begin
 остановить всю работу.
end;



Автор: m1nder 28.9.2009, 11:12
Программа сравнивает файлы по датам каждые 10 сек и если они разные - переписывает. Проблемка с остановкой службы. Как корректно остановить службу и завершить ее?

Код

procedure Ttask9.ServiceExecute(Sender: TService);
var file1 : string;
    file2 : string;
    intFileAge1: integer;
    intFileAge2: integer;

begin
  sleep(10000); // 10 сек

  file1:=ParamStr(1);
  file2:=ParamStr(2);

  intFileAge1 := sysutils.FileAge(file1);
  intFileAge2 := sysutils.FileAge(file2);
if intFileAge1 <> intFileAge2 then
  CopyFile(PChar(file1),PChar(file2), false);
  task9.DoPause;
While not Terminated do
ServiceThread.ProcessRequests(True);
  end;

procedure Ttask9.ServicePause(Sender: TService; var Paused: Boolean);
begin
task9.DoStart;
end;

procedure Ttask9.ServiceShutdown(Sender: TService);
begin
  task9.DoStop;
end;


Модератор: не забываем использовать кнопку КОД




Автор: CodeMonkey 28.9.2009, 11:34
Что ЭТО?

Код
procedure Ttask9.ServicePause(Sender: TService; var Paused: Boolean);
begin
  task9.DoStart;
end;

procedure Ttask9.ServiceShutdown(Sender: TService);
begin
  task9.DoStop;
end;

Автор: Virtuals 28.9.2009, 13:06
CodeMonkey, это его сервис сам себя в "прошлое" отправляет smile.

m1nder, 
ты блин зачем основной поток сервиса вообще трогаеш?.
в ServiceExecute ты должен инициализировать все что нужно, и выполнять свое грязное дело внутри цикла
Код

While not Terminated do
ServiceThread.ProcessRequests(True);
  end;

а то что у тебя отрабатывает 1 раз и все.
в идеале, ServiceExecute вообще не трогают а отрабатывают по сообщениям

Код

ServiceStart(Sender: TService; var Started: Boolean);
ServiceStop(Sender: TService; var Stopped: Boolean);
ServiceShutdown(Sender: TService);
ServicePause(Sender: TService; var Paused: Boolean);


тоесть в отдельном потоке.

ЗЫ имхо сделай для начала свою процедуру отдельным потоком (и отлаживать легче будет)
типа 
Код

type
  TThreadcheckfiledate=class(TThread)
  protected
    procedure Execute; override;
  end;
var
  TCD: TThreadcheckfiledate;
...

а потом уже в сервисы лезь.

Автор: m1nder 30.9.2009, 17:11
Пробовал по всякому, не получается нормальной работы со службой. Virtuals, подскажи как  правильно 
Код

While not Terminated do
ServiceThread.ProcessRequests(True);
  end;

в цикл сунуть или как это при помощи потоков сделать. Подскажите поподробнее, пожалуйста.

Автор: CodeMonkey 30.9.2009, 20:53
http://www.delphikingdom.ru/asp/viewitem.asp?catalogid=1348.

Автор: Keeper89 30.9.2009, 23:56
У CodeMonkey на все случаи жизни статьи есть smile 

Автор: m1nder 1.10.2009, 15:42
Пробую через поток, но ничего не выходит! В чем причина?

Код


// Объявляем мой поток
  TNewThread = class(TThread)
    private
    { Private declarations }
  protected
    procedure Execute; override;
  end;

var
  Service3: TService3;
  NewThread: TNewThread;
implementation

{$R *.DFM}

procedure ServiceController(CtrlCode: DWord); stdcall;
begin
  Service3.Controller(CtrlCode);
end;

function TService3.GetServiceController: TServiceController;
begin
  Result := ServiceController;
end;

// Выполняется мой поток

procedure TNewThread.Execute;
 var file1, file2: string;
begin
 While not Terminated do
  begin
{
 ----  Тест ----------------
  sleep(5000); // 5 сек
  file1:='c:\test\test.txt';
  file2:='d:\test\test.txt';
  CopyFile(PChar(file1),PChar(file2), false);
 }

  end;
 end;

// Запускаем мой поток из главного
procedure TService3.ServiceExecute(Sender: TService);
var
  NewThread: TNewThread;
begin
  NewThread:=TNewThread.Create(true);
  NewThread.FreeOnTerminate:=true;
  NewThread.Priority:=tpLower;
  NewThread.Resume;
end;



А через OnStart и OnStop у меня не получается. Пробовал по всякому, иногда запускаешь службу - процесс выполняется, а служба не стартует и выснет. А через Execute цикл While not Terminated do отрабатывает 1 раз. Напишите мне пару строк как сделать и забыть, там же много кода не нужно, заодно я разберусь.

Автор: CodeMonkey 1.10.2009, 17:14
Эх, ещё один шедевр.

Что, по-вашему, должна делать служба, если её Execute-тело заканчивается? 

Цитата(m1nder @  1.10.2009,  15:42 Найти цитируемый пост)
заодно я разберусь. 

Да ни черта вы не разберётесь вы, а втупую запомните пример. 
Учитесь мыслить и делать выводы самостоятельно. Вам это ничто не заменит.

Пример несложного мозгового упражнения. Написано: 

Цитата
Вы можете реализовать работу службы двумя способами.

Вариант первый: стартует служба, вы начинаете что-то делать, время от времени уведомляя систему о своём состоянии, потом служба останавливается.

Вариант второй: стартует служба, создаёт рабочие потоки. По уведомлению от системы потоки останавливаются и служба выключается.

Итак, событие OnExecute реализует первый вариант: вы просто вписываете весь код службы в OnExecute, ....

Для второго варианта реализации вы не должны назначать обработчик OnExecute, но обязаны реализовать, как минимум, OnStart и OnStop. В первом обработчике вы запускаете рабочие потоки службы, а в OnStop — останавливаете. ...


Внимание, наводящий вопрос: нафига вы назначили OnExecute, если в нём вы создаёте поток?

Право же, это несложно.

Автор: m1nder 1.10.2009, 18:23
Всем огромное спасибо!!! Особенно Вам, CodeMonkey! Написал наконец свою программу +) оказалось все просто. Выложу код, вдруг кому понадобится:
Код


{Программа-служба, сравнивает файлы в двух каталогах каждые N минут и если они разные по дате - перезаписывает} 
...
procedure TService2.ServiceExecute(Sender: TService);
var  F: TSearchRec;
     Path, source,files: string;
     Attr,intFileAge1,intFileAge2: Integer;

begin

  path:='d:\test\';   //ParamStr(1)
  source:='i:\test\'; //ParamStr(2)
  files:='';
  Attr:= faAnyFile;
  intFileAge1:=0;
  intFileAge2:=0;

 while not terminated  do
  begin

//-------------------------------------
    sleep(5000); // 5 сек
    FindFirst(Path+'*.*', Attr, F);
    if F.name <> '' then files:= F.Name;
      if intFileAge1 <> intFileAge2 then
        CopyFile(PChar(path + files),PChar(source+files),false);
    while (FindNext(F) = 0) do
      begin
        files:=F.Name;
        intFileAge1 := sysutils.FileAge(path + files);
        intFileAge2 := sysutils.FileAge(source+files);
        if intFileAge1 <> intFileAge2 then
        CopyFile(PChar(path + files),PChar(source+files),false);
      end;
    FindClose(F);
//-------------------------------------
    Service2.ReportStatus;
    if Service2.Status=csStopped then DoStop;
    if Service2.Status=csPaused then DoPause;

  end;

end;


Автор: Virtuals 6.10.2009, 05:59
m1nder, ну нафига sleep(5000); // 5 сек внутри цикла?
статью внимательней читай.
Цитата

ReportStatus — если вы делаете что-либо слишком долго (дольше, чем число миллисекунд, указанных в свойстве WaitHint), то вы должны вызывать этот метод для сообщения системе, что вы ещё живы. Если вы будете выполнять какие-то действия в обработчиках событий или коде инициализации/завершения слишком долго, то SCM может подумать, что ваша служба зависла, и, в некоторых случаях, завершить её (но чаще всего SCM просто вернёт ошибку приложению, запросившему действие).


Цитата

WaitHint (свойство) — указывает время в миллисекундах, через которое ваша служба должна сообщить свой статус. VCL по умолчанию ставит это свойство в 5000 (т.е. 5 секунд), хотя в системе по умолчанию этот параметр принимается равным 2000. Как разработчик службы, вы должны определить, как часто служба должна сообщать о своём статусе. Вы также должны вызывать ReportStatus не реже, чем вы указали в WaitHint. Если вы собираетесь выполнить какие-то длительные действия в обработчике события, то иногда проще вынести эти действия в отдельный поток, а в обработчике события сделать цикл ожидания завершения работы с периодическим вызовом ReportStatus раз в, скажем, WaitHint / 2 миллисекунд. Разумеется, цикл не должен крутиться вхолостую, а ждать наступления момента вызова ReportStatus или завершения работы.

Автор: papweilm 29.11.2022, 06:00
Модератор: Сообщение скрыто.

Автор: saiple 24.12.2022, 13:19
levitra 10 mg reviews <a href=" https://levitraoffer.com/# ">what is vardenafil 20mg</a> buy generic levitra online

Автор: saiple 28.12.2022, 18:33
what is levitra used for <a href=" https://levitraoffer.com/# ">levitra pills men</a> levitra 20 mg film coated tablets

Автор: saiple 31.12.2022, 22:58
levitra online purchase <a href=" https://levitrair.com/# ">vardenafil hcl 20mg tablet</a> levitra pills men

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