Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как правильно запускать сервис во время проэктирования? [D5, Win2k, WinXP]


Страницы:   1 2

TankMan ©   (2004-10-30 21:24:00) 

Пишу программку, которая работает как сервис, но вот проблема в том что когда я в процессе программирования хочу проверить работоспособность например некоторой функции, с помощью F9 пытаюсь ее запустить, но вот она тут же закрывается, приходится с помощью батника(C:\Delphi\HarDS\HarDS.exe /install /silent) запускать отдельно :(... но какая тогда к черту отладка :(...
Я впринципе сейчас как-то хило да бедно выкручиваюсь тем, что переименовываю HardS и запускаю его как сервис, и тогда когда из дельфи я запускаю проект, он запускается и висит в рабочем состоянии но почему-то не дольше минуты или пол-минуты :(...

Вобщем что-то я предысторией увлекся :)
Скажите Как нужно правильно работать с Дельфи при разработке сервисов?


TankMan   (2004-11-16 13:30:00) [1]

Ну раз впринципе правильно, то еще раз спасибо за информацию :)
Я принял к сведению все что ты сказал. Еще раз благодарю.


Digitman   (2004-11-15 08:22:00) [2]


> Я так понимаю


в принципе ты понял правильно.


>  Так чтоль?


так или не так, но исх.тексты даны Борландом для детального изучения реализованных им алгоритмов, а не для красоты.


TankMan   (2004-11-15 06:44:00) [3]

>>Digitman ©   (12.11.04 10:24) [20]
Тааак... спасибо за информацию, конечно....
Я так понимаю что если я сделаю так:
procedure THarDStarter.ServiceExecute(Sender: TService);
begin
 SetPriorityClass(GetCurrentprocess,IDLE_PRIORITY_CLASS);
 StartTimer.Enabled:=true;
 while not Terminated do
 begin
   ServiceThread.ProcessRequests(False);
   if bStop then break;
 end;
end;
...и где-то в программе присвою bStop:=true, то программа завершится корректно?

А если я сделаю так:
procedure THarDStarter.ServiceExecute(Sender: TService);
begin
 SetPriorityClass(GetCurrentprocess,IDLE_PRIORITY_CLASS);
 StartTimer.Enabled:=true;
 while true do
 begin
   ServiceThread.ProcessRequests(False);
   if bStop then break;
 end;
end;
То программа вообще никем не завершится кроме как мной(из самой программы)?

>> З.Ы. Ну как мене это все надоело
>модуль svcmgr.pas - перед носом, а изучить происходящее там - это не для нас, мы лучше будем покупать очередной дорогущий гросбух и ждать, что вот в нем-то уж нам всю эту кухню наконец-то разжуют

Так тогда зачем вообще какие-то кники выпускают по Delphi? По твоему мнению - прочитал книжку по Pascal-ю - и дерзай - пиши проги на дельфи, т.к. это всеравно тот же паскаль. Так чтоль?

У тебя у самого скорее всего есть книги по программированию в Delphi, и скорее всего там среди всего прочего есть рассмотрение вопроса - как правильно пользоватся TImage и TTimer? А чем TServiceThread хуже? Это же такой же класс, насколько я понимаю, почему его работу не описывают?


Erik1   (2004-11-12 11:44:00) [4]

Ты хоть один пример смотрел? По инету намоло примеров сервисов имеется. Для начала открой ..\Delphi5\Demos\Threads и посмотри как это делается. Пределай свой проект на основе треда, если бубуд вопросы тогда задавай. О то мечишся и нопонятно, что хочеш. А таймер тебе нафиг нужен, используй WaitFor... функции у них можно задать время ожидания. Вобщем учи мат. часть.


Digitman   (2004-11-12 10:24:00) [5]


> TankMan ©   (12.11.04 09:28) [19]


> ты предлагаешь более корректный способ(KillTimer-SetTimer)?


Я предлагаю обращаться к методам св-вам объекта-таймера в ТОМ ЖЕ треде, в котором он был создан. Почему - я уже объяснил тебе.


> как мне вызвать для сервиса OnStop?


Никак его не надо вызывать.

Это событие будет возбуждено автоматически, когда внешний по отношению к сервису процесс подаст запрос на завершение сервиса средствами Service Control Manager.

Все что тебе нужно сделать в обработчике этого события - немедленно закруглиться по хозяйству, освободив все занятые тобой ресурсы, и вернуть Stopped := True. Сервис будет остановлен.

Если исполнение внешней команды на завершение твоего сервиса по каким-то причинам невозможно в дан.момент, просто верни Stopped := False. Сервис продолжит работу.

Если ты обрабатываешь событие OnExecute, то сервис автоматически завершит работу (будет остановлен) после завершения работы пройедуры обработки этого события, при этом событие OnStop не возникнет, если конечно же во время обработки OnExecute никто извне не дал команду на останов/завершение сервиса.
В ходе достаточно длительной обработки события OnExecute ты обязан периодически проверять флаг Terminated и немедленно закругляться по хозяйству при обнаружении условия Terminated = True (условие №1). Кр.того в этом случае ты ответственен за обязательный периодический вызов метода ProcessRequests() (условие №2). Несоблюдение или несвоевременное соблюдение условий №№ 1,2 ведет к невозможности управления работой сервиса извне либо к ощутимым задержкам исполнения команд управления сервисом извне.

Если ты НЕ назначаешь обработчик и, соотв-но, НЕ обрабатываешь событие OnExecute, то ответственность за циклический вызов метода ProcessRequests() автоматически берет на себя алгоритм в теле метода TServiceThread.Execute, в рез-те чего твой сервис будет способен немедленно реагировать на команды сервис-менеджера, которые для тебя будут выглядеть в виде возбуждения событий OnPause, OnContinue, OnStop, OnShutdown.


> З.Ы. Ну как мене это все надоело


неужели)
модуль svcmgr.pas - перед носом, а изучить происходящее там - это не для нас, мы лучше будем покупать очередной дорогущий гросбух и ждать, что вот в нем-то уж нам всю эту кухню наконец-то разжуют


TankMan   (2004-11-12 09:28:00) [6]

>>Digitman
Не понимаю, ты говоришь "недопустимо",а ведь с таймером у меня вообще никаких проблем нет...т.е. ты предлагаешь более корректный способ(KillTimer-SetTimer)?Или так... к слову сказано?

Так и всетаки, я хотел бы узнать, как мне вызвать для сервиса OnStop? -я понял логическую "ошибку" завершения программы в моем случае...а вот onstop не могу вызвать и все...

З.Ы. Ну как мене это все надоело!!!! Заказал 2 книги по дельфи, одна из них По delphi 7 "Наиболее полное руководство" в подленнике (так и написано на обложке), 1200 страниц, вторая по Delphi5 - и НИЧЕГО про сервисы(!!!!), в обеих книгах(!),как так жить(?)..


Digitman   (2004-11-11 09:04:00) [7]


> А гдеж мне его еще понижать?


а зачем его вообще изменять ? чем он тебя не устраивает ?


> я создал новый проект Service Application - вот там окно
> появляется туда и положил StartTimer


там не просто окно появилось, там появился компонент TDataModule.

этот компонент создается в основном трэде сервис-процесса, поэтому и все компоненты, "брошенные" тобой на него, будут так же создаваться в осн.трэде, и StartTimer - не исключение.

При создании объекта класса TTimer создается невидимое окно, предназначенное для обработки сообщений WM_TIMER. Поскольку конструктор класса TTimer был вызван тобой в осн.трэде, то он и будет владельцем созданного в конструкторе окна. И события OnTimer впоследствии так же будут возбуждаться в осн.трэде.

При старте/стопе сервиса возбуждаются соотв-но события OnStart/OnStop. Возбуждаются они отнюдь не в осн.трэде, а в доп.трэде, ассоциированном с данным сервисом. В этих обработчиках ты пытаешься управлять старт/стопом таймера, обращаясь к его св-ву Enabled. Это недопустимо, поскольку таймер создан в ином трэде. При останове таймера вызывается ф-ция KillTimer(), при старте - SetTimer(), и обе эти ф-ции требуют первым параметром хэндл окна (то самое окно, которое было создано в ходе конструирования объекта), а соответствии с требованиями MS
This window must be owned by the calling thread


TankMan   (2004-11-11 07:37:00) [8]

>>Digitman
Чего то я совсем не могу разобратся... -а как вызвать onstop?
ServiceStop(MyService,true) не работает
а ServiceStop(MyService,bPar)
не вызывает onstop :(
Глупость наверное спрашиваю... :)
Но хотелось бы узнать :)

А еще попутный вопрос - у меня есть форма в этом проэкте, так вот в начале она не видимая, а в трее весит иконка, из менюшки ее вызываю frmMain.showmodal, она октрывается, но почему-то не активная :(... как сделать чтобы она была на переднем плане?


TankMan   (2004-11-11 07:11:00) [9]

>>Digitman
Digitman ©   (10.11.04 11:34) [15]
>зачем понижать приоритет процесса ? да еще и в Execute ?
А гдеж мне его еще понижать?

>в каком месте создается/уничтожается объект StartTimer ?
Ну вообще я создал новый проект Service Application - вот там окно появляется туда и положил StartTimer.Enabled, мне нужно что бы каждые 500 мс проверялось запускать процесс или нет. Шедулер можно сказать пытаюсь писать... да и экспириенс шоб до левел апа хватило ;)

>  while not Terminated do
>  begin
>    ServiceThread.ProcessRequests(False);
>  end;
А это я взял из примера... не помню какого :(...
А что он совсем не нужен?

>> И вот такой вот Stop
>а это-то нафига ?
...ммм... :)...
Я сейчас только что  осознал что похоже это универсальный закрыватель любого сервиса? Так?... если так... то действительно... зачем оно мене - щас сделаю...

Спасибо за информацию...


Digitman   (2004-11-10 11:34:00) [10]


> У меня вот что -
> procedure THarDStarter.ServiceExecute(Sender: TService);
> begin
> //  ShowMessage('Start executing.');
>  SetPriorityClass(GetCurrentprocess,IDLE_PRIORITY_CLASS);
>  StartTimer.Enabled:=true;
>  while not Terminated do
>  begin
>    ServiceThread.ProcessRequests(False);
>  end;


зачем понижать приоритет процесса ? да еще и в Execute ?
в каком месте создается/уничтожается объект StartTimer ?
зачем нужен цикл, крайне расточительно "пожирающий" процессорное время ?


> И вот такой вот Stop


а это-то нафига ?
чем Stopped := True не устроил ?
сервис и без твоих спец.усилий будет остановлен, как только ты вернешь Stopped := True в обработчике OnStop()


Alex Konshin   (2004-11-10 10:30:00) [11]

Да, если вы думаете, что я использовал стандартный отладчик для отладки сервиса, то заблуждаетесь. Я вообще не использую отладчик (и не только в случае Delphi), так как у меня частенько многопоточные приложения и надоело бороться с глюками самих отладчиков. Поэтому вся отладка по старинке - OutputDebugString и DebugView от Руссиновича (www.sysinternals.com). Он еще удобен тем, что позволяет ловить ODS удаленно - это упрощает отладку сетевых приложений.


Alex Konshin   (2004-11-10 10:22:00) [12]

>>Alex Konshin
Спасибо за помощь, но вот 2й файл почему-то не качается :(

Хм, неудивительно, ведь он DPR...
http://home.earthlink.net/~akonshin/files/FlarpService.dpr
Вообще-то это кусок из реального проекта, потому там есть лишнее, но все-таки я думаю из него ясно, как пользоваться тем классом.


TankMan   (2004-11-10 09:32:00) [13]

>>Ученик
Спасибо Попробую на работе...

>>Alex Konshin
Спасибо за помощь, но вот 2й файл почему-то не качается :(

>>Burmistroff
procedure TServicename.ServiceStart(Sender: TService; var Started: Boolean);
begin
Started:=true;
end;

procedure TServicename.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
Stopped:=true;
end;
А что за переменные Stopped Started ?
У меня вот что -
procedure THarDStarter.ServiceExecute(Sender: TService);
begin
//  ShowMessage('Start executing.');
 SetPriorityClass(GetCurrentprocess,IDLE_PRIORITY_CLASS);
 StartTimer.Enabled:=true;
 while not Terminated do
 begin
   ServiceThread.ProcessRequests(False);
 end;

И вот такой вот Stop

function ServiceStop(aMachine, aServiceName: String): Boolean;
var
 h_manager, h_svc: SC_Handle;
 ServiceStatus: 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, ServiceStatus)) then
     begin
       if (QueryServiceStatus(h_svc, ServiceStatus)) then
       begin
         while (SERVICE_STOPPED <> ServiceStatus.dwCurrentState) do
         begin
           dwCheckPoint := ServiceStatus.dwCheckPoint;
           Sleep(ServiceStatus.dwWaitHint);
           if (not QueryServiceStatus(h_svc, ServiceStatus)) then
             // couldn't check status
             break;
           if (ServiceStatus.dwCheckPoint < dwCheckPoint) then
             break;
         end;
       end;
     end;
     CloseServiceHandle(h_svc);
   end;
   CloseServiceHandle(h_manager);
 end;
 Result := (SERVICE_STOPPED = ServiceStatus.dwCurrentState);
end;


TankMan   (2004-11-10 09:25:00) [14]

Ну ничего себе... 8)..я так почитал и понял что я вообще ничего о сервисах и как их запускать, не знал :(... я не читал ничего по этому поводу... так просто ткнулся - заработало :)

>>Erik1
Не мог бы выслать примерчик такого проэкта? Мне нужно чтоб была одна форма с таймером а дальше я сам разберусь :)...
У меня в 3х моих книгах ничего хорошего не было написано про Сервисы...если мне не изменяет память так там вообще ничего про сервисы небыло сказано :)


Alex Konshin   (2004-11-09 07:14:00) [15]

Ну вот, смотрите http://home.earthlink.net/~akonshin/files/AcntService.pas

Оказывается, я там хитрю еще больше, чем думал:

// Реализация сервиса отличается от общепринятой:
//  обычно из ServiceMain стартуют нить, которая и будет выполнять полезную
//  работу, но нить ServiceMain стартует service manager и я подозреваю,
//  что именно поэтому по любому exception все рушится.
//  Поэтому я создаю нить еще перед запуском сервиса из главной(первой) нити процесса,
//  и она дожидается команды от ServiceMain нити.

На мой взгляд, это довольно удачное решение: мы таким образом гарантируем, что нить создана правильно с точки зрения механизма обработки исключений Delphi и заодно само приложение получается простым как валенок. Дело в том, что для корректной работы исключений нить должна быть создана через BeginThread.
Да, как этим пользоваться:
Нужно написать класс-наследник от TAcntService, в котором перекрыть DoEvent и Execute (если нужно). Там уже организован цикл ожидания событий, что типично для сервисов (ждем запроса - обрабатываем, и так по кругу). Смотрите пример dpr:
http://home.earthlink.net/~akonshin/files/FlarpService.pas
Приложение должно выдавать маленькое описание параметров при вызове его с аргументом "-?"

Эх, и давно это было...


Alex Konshin   (2004-11-08 23:33:00) [16]

Лично я писал сервисный модуль так, чтобы он мог работать и как сервис, и из командной строки (примерно как Apache webserver). Соответственно, больших проблем с отладкой у меня не было.
Сам проект при этом практически не изменился. IMHO я использовал  модифицированный чей-то класс для сервисов (тогда еще не было стандартного проекта для сервиса в Delphi).
Если не забуду, то когда дойду до дома расскажу подробнее.


Burmistroff   (2004-11-08 23:09:00) [17]

Ах да, чтобы не закрывался до подключения отладчика можно банальный Messagebox вставить.

Заодно проверь чтобы было:

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

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

procedure TServicename.ServiceStart(Sender: TService; var Started: Boolean);
begin
 Started:=true;
end;

procedure TServicename.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
 Stopped:=true;
end;


Burmistroff   (2004-11-08 23:02:00) [18]

Можно заинсталить сервис, потом (через консоль сервисов services.msc или net start) запускать его, затем в течении 20-30 секунд идешь в Delphi (сервис перед запуском должен был быть скомпилирован) и выбираешь Debugging | Attach to process. Выбираешь затем свой сервис и жмешь F9 (если не нажмешь, то через 20-30 секунд Windows закроет сервис, т.к. подумает что он не запустился).


GrayFace   (2004-11-08 14:28:00) [19]

TankMan ©   (05.11.04 6:53) [3]
"..and check Allow Service to Interact with Desktop."

и выбрать Разрешить сервису взаимодействовать с рабочим столом.


Erik1   (2004-11-08 10:25:00) [20]

Полезней для здоровя создать еще один проект включить туда свои модули, добавить форму, на нее кнопочку со стартом потока. Далее думаю обяснять ненужно. Есть подозрение, что ты невыделил работу сервиса в отдельный поток, ну чтоз переделать никогда непоздно!
 Для меня это главный агрумент организовать сервис в дополнительном потоке.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо