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


Автор: Litta 15.3.2011, 17:25
Приветствую!
Сделал Службу для WinXP. Что происходит - В службе работает таймер и через определенные промежутки времени проверяет определённые данные, если всё ок - запускается exe-шник (через CreateProcess), выполяет свою работу и гасится, если условиям не соответствует - ничего и не запускается. Всё работает нормально, без проблем.
Возникла потребность проделать аналогичную штуку с другим exe файлом, т.е. так же через определённые промежутки времени проверять свои условия и если ок - запускать файл, а нет - так нет.
Т.к. обе операции относятся к одной теме - делать вторую службу не очень хочется. Решил реализовать всё в одной - разместил второй таймер, по которому выполяются аналогичные действия со вторым exe файлом.
Все в принципе тоже работает, но есть проблема! Если исполнение первого exe проходит достаточно быстро, что не нужно парится о "успел/не успел выполнить", то со вторым файлом время может растянуться.
Сделал так:
Код

         OStartEn := CreateProcess(nil,
         CmdStr,
         nil, 
         nil,
         False, 
         CREATE_NEW_CONSOLE or 
         NORMAL_PRIORITY_CLASS,
         nil, 
         nil,
         OStartupInfo, 
         OProcessInfo);
         if OStartEn then
          begin
           WaitForSingleObject(OProcessInfo.hProcess, INFINITE);
           CloseHandle(OProcessInfo.hThread);
           CloseHandle(OProcessInfo.hProcess);
           OStartEn := False;
          end;

Все работает, но из-за WaitForSingleObject, срабатывающей во втором таймере, события первого таймера выполняются только после окончания её работы.
Подскажите, как сделать так, что бы каждый таймер жил своей жизнью, вне зависимости от того, что происходит в другом?

Автор: MetalFan 15.3.2011, 19:32
Лучший вариант: Отказаться от таймеров. Использовать потоки.
Худший:
Вместо WaitForSingleObject(OProcessInfo.hProcess, INFINITE)
написать нечто подобное:
Код

  while WaitForSingleObject(OProcessInfo.hProcess, 500) = WAIT_TIMEOUT do
     Application.ProcessMessages;

вместо Application.ProcessMessages  возможно понадобится цикл из PeekMessage-DispatchMessage

Автор: Litta 15.3.2011, 19:54
Вот как раз нашел вариант про
Код

while WaitForSingleObject(OProcessInfo.hProcess, 500) = WAIT_TIMEOUT do


Только именно Application.ProcessMessages не проходит в службе!
Можно по-подробней о предлагаемом Вами цикле? Я просто со службами и вобще в системном программинге не очень специализируюсь  smile 

Автор: MetalFan 15.3.2011, 22:17
Ну как-то так наверное:
Код

  while PeekMessage(AMsg, 0, 0, 0, PM_REMOVE ) <> 0 do
    DispatchMessage(AMsg);


А вообще лучше отказаться от TTimer'а в службе (о нем ведь речь?).

Автор: Litta 16.3.2011, 11:59
Да, речь о нём.
Попробовал следующее:
Код

OStartEn := CreateProcess(nil,
CmdStr,
nil,
nil,
False,
CREATE_NEW_CONSOLE or
NORMAL_PRIORITY_CLASS,
nil,
nil,
OStartupInfo,
OProcessInfo);
if OStartEn then
 begin
   while PeekMessage(AMsg, 0, 0, 0, PM_REMOVE) do
     begin
       if AMsg.Message = wm_Quit then Halt(AMsg.WParam);
       TranslateMessage(AMsg);
       DispatchMessage(AMsg);
      end;
     TerminateProcess(OProcessInfo.hProcess, 0);
     CloseHandle(OProcessInfo.hThread);
     CloseHandle(OProcessInfo.hProcess);
     OStartEn := False;
    end;

Но теперь второй экзешник даже не успевает запустится, может что не так написал? Или этот способ тут не прокатит ведь программа то не висит?

Автор: MetalFan 16.3.2011, 12:39
Цитата(Litta @  16.3.2011,  11:59 Найти цитируемый пост)
Попробовал следующее:

а где WaitForSingleObject???

Автор: Litta 16.3.2011, 13:13
Пардон, ступил  smile 
Написал так:
Код

OStartEn := CreateProcess(nil,
CmdStr,
nil,
nil,
False,
CREATE_NEW_CONSOLE or
NORMAL_PRIORITY_CLASS,
nil,
nil,
OStartupInfo, 
OProcessInfo);
if OStartEn then
 begin
   while (WaitForSingleObject(OProcessInfo.hProcess, 100)<>WAIT_OBJECT_0) do
     begin
       while PeekMessage(AMsg, 0, 0, 0, PM_REMOVE) do
         begin
           if AMsg.Message = wm_Quit then Halt(AMsg.WParam);
           TranslateMessage(AMsg);
           DispatchMessage(AMsg);
         end;
     end;
   TerminateProcess(OProcessInfo.hProcess, 0);
   CloseHandle(OProcessInfo.hThread);
   CloseHandle(OProcessInfo.hProcess);
   OStartEn := False;
 end;

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

ЗЫ: а как такую задачу решить с помощью потоков? Мне нужно через определённые промежутки времени проверять параметры и если ок - запускать файлы (что б не висели в памяти лишним грузом, а запускались лишь тогда, когда это нужно). Соответственно проверку параметров запускаю в таймерах через определенные промежутки времени, ну и в таймере уже создаю процесс если параметры соответствующие. А какая логика должна быть в использовании в службе вместо таймеров - потоков (в них я тож просто не особо шарю, отсюда и вопрос, было бы интересно разобраться)?

Автор: MetalFan 16.3.2011, 14:04
Цитата(Litta @  16.3.2011,  13:13 Найти цитируемый пост)
<>WAIT_OBJECT_0

не рекомендую так писать... так как в общем случае цикл будет вечен в случае ошибки.
Я ранее писал, что надо проверять на соответствие WAIT_TIMEOUT, в случае завершения ожидания или ошибки - выход из цикла.
Цитата(Litta @  16.3.2011,  13:13 Найти цитируемый пост)
if AMsg.Message = wm_Quit then Halt(AMsg.WParam);

Не уверен, что эта строчка имеет смысл в службе, да и Halt делать совсем жестоко.
в TranslateMessage в данном случае нет необходимости.
TerminateProcess - зачем???

По поводу потоков - здесь на форуме есть отличная статья по ним в разделе WinApi.
В твоем случае можно было бы вообще обойтись без потоков и таймеров.
Просто в цикле отмерять нужный промежуток времени с пом.GetTickCount.

Автор: Litta 16.3.2011, 14:26
Цитата

Я ранее писал, что надо проверять на соответствие WAIT_TIMEOUT, в случае завершения ожидания или ошибки - выход из цикла.


Но я так понимаю, что в этом случае я должен знать приблизительно сколько времени требуется для правильной работы проги и выставлять соответствующее WaitForSingleObject(OProcessInfo.hProcess, 5000) ?
Но время работы будет варьироваться и надежней с точки зрения не повреждения данных (а прога пишет данные в таблицы) дать ей завершится самой (естесственно внутри расставлены все Try except, а в конце работы вобще Application.Terminate), или я не правильно понял значение WAIT_TIMEOUT?

Автор: MetalFan 16.3.2011, 16:32
Litta, зачем нужно знать, сколько времени надо для работы??? просто поменять условие продолжения цикла с <> WAIT_OBJECT_0 на = WAIT_TIMEOUT.

Автор: Litta 16.3.2011, 17:17
Именно про это я и написал - что не правильно понял про WAIT_TIMEOUT  smile 
Изменил, ещё раз большое спасибо!

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