Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2007.02.18;
Скачать: CL | DM;

Вниз

Обработка искл. ситуаций в WinNT Service   Найти похожие ветки 

 
Прогер   (2006-12-22 08:30) [0]

Глобальная переменная TApplication для EXE предусматривает обработчик (событие) OnException, с помощью которого я протоколирую все возникающие исключительные ситуации. Но это в приложении (EXE). А как быть с сервисом?


 
Сергей М. ©   (2006-12-22 08:50) [1]

А оч просто.

Тела всех назначенных тобой обработчиков событий заключай в try..except


 
Прогер   (2006-12-22 08:54) [2]

Да муторно, знаете ли, батенька... :)

Можно, конечно, и так:


program proDgstSenderService;

uses
 SvcMgr,
 uSender in "uSender.pas" {srvcSender: TService},
 uProc in "..\..\_Gnrl\uProc.pas",
 uFuncDgstSender in "..\uFuncDgstSender.pas",
 uConst in "..\uConst.pas",
 uRAR in "..\..\_Gnrl\uRAR.pas";

{$R *.RES}

begin
try
 Application.Initialize;
 Application.CreateForm(TsrvcSender, srvcSender);
 Application.Run;
except
... // протоколирование в файл
end
end.


Однако, может кто подскажешь более эстетичное решение?


 
Сергей М. ©   (2006-12-22 09:08) [3]


> муторно, знаете ли, батенька


А сервисы, уважаемый, вообще муторная штука)

Здесь надо понимать, что обработчики основных сервисных событий OnStart/Stop/Execute выполняются в контекстах соответствующих доп.потоков.
Одно и то же сервис-приложение может создать более чем один сервис-объект, и каждый из этих объектов создаст свой доп.поток, в котором соотв.сервис и будет "крутиться по хозяйству". Эти доп.потоки независимы друг от друга, обработка исключений в каждом из них возлагается на сам поток.
Тот код, что ты привел в [2], будет обрабатывать искл-я, возникающие лишь в основном потоке процесса сервис-приложения.


 
oxffff ©   (2006-12-22 09:27) [4]


>Прогер   (22.12.06 08:54) [2]
> Да муторно, знаете ли, батенька... :)
>
> Можно, конечно, и так:


А разве батенька так можно?

Ты посмотри реализацию RUN

procedure TApplication.Run;
begin
 FRunning := True;
 try
   AddExitProc(DoneApplication);
   if FMainForm <> nil then
   begin
     case CmdShow of
       SW_SHOWMINNOACTIVE: FMainForm.FWindowState := wsMinimized;
       SW_SHOWMAXIMIZED: MainForm.WindowState := wsMaximized;
     end;
     if FShowMainForm then
       if FMainForm.FWindowState = wsMinimized then
         Minimize else
         FMainForm.Visible := True;

     repeat
       try
         HandleMessage;
       except
         HandleException(Self);
       end;
     until Terminated;

   end;
 finally
   FRunning := False;
 end;
end;

До твоего супер обработчика дойдет только, если HandleException создаст
исключение.

А для 99.99999% случаев твой вариант батенька ошибочный.


 
oxffff ©   (2006-12-22 09:31) [5]

А вообще батенька открой синенькую книжку Рихтера.
И читай до посинения.


 
Сергей М. ©   (2006-12-22 09:42) [6]


> oxffff ©   (22.12.06 09:27) [4]


Это из другой оперы.

А текущая опера - это TServiceApplication, и реализация метода Run у него, мягко говоря, иная, хотя концептуально не отличается - организован тот же цикл ожидания/выборки/диспетчеризации сообщений.


 
Прогер   (2006-12-22 09:43) [7]


procedure TServiceApplication.Run;

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

var
 ServiceStartTable: TServiceTableEntryArray;
 ServiceCount, i, J: Integer;
 StartThread: TServiceStartThread;
begin
 AddExitProc(DoneServiceApplication);
 if FindSwitch("INSTALL") then
   RegisterServices(True, FindSwitch("SILENT"))
 else if FindSwitch("UNINSTALL") then
   RegisterServices(False, FindSwitch("SILENT"))
 else
 begin
   Forms.Application.OnException := OnExceptionHandler;
   ServiceCount := 0;
   for i := 0 to ComponentCount - 1 do
     if Components[i] is TService then Inc(ServiceCount);
   SetLength(ServiceStartTable, ServiceCount + 1);
   FillChar(ServiceStartTable[0], SizeOf(TServiceTableEntry) * (ServiceCount + 1), 0);
   J := 0;
   for i := 0 to ComponentCount - 1 do
     if Components[i] is TService then
     begin
       ServiceStartTable[J].lpServiceName := PChar(Components[i].Name);
       ServiceStartTable[J].lpServiceProc := @ServiceMain;
       Inc(J);
     end;
   StartThread := TServiceStartThread.Create(ServiceStartTable);
   try
     while not Forms.Application.Terminated do
       Forms.Application.HandleMessage;
     Forms.Application.Terminate;
     if StartThread.ReturnValue <> 0 then
       FEventLogger.LogMessage(SysErrorMessage(StartThread.ReturnValue));
   finally
     StartThread.Free;
   end;
 end;
end;



> А вообще батенька открой синенькую книжку Рихтера.

Быть может, добрые люди подскажут мне, где её скачать? Спасибо.


 
Сергей М. ©   (2006-12-22 09:45) [8]


> где её скачать?


Кажись, на сайте у Анатолия Подгорецкого (С) она есть.


 
oxffff ©   (2006-12-22 09:55) [9]


> Сергей М. ©   (22.12.06 09:42) [6]
>
> > oxffff ©   (22.12.06 09:27) [4]
>
>
> Это из другой оперы.
>
> А текущая опера - это TServiceApplication, и реализация
> метода Run у него, мягко говоря, иная, хотя концептуально
> не отличается - организован тот же цикл ожидания/выборки/диспетчеризации
> сообщений.


Благодарю за поправку.


  try
    while not Forms.Application.Terminated do
      Forms.Application.HandleMessage;
    Forms.Application.Terminate;
    if StartThread.ReturnValue <> 0 then
      FEventLogger.LogMessage(SysErrorMessage(StartThread.ReturnValue));
  finally
    StartThread.Free;
  end;


Обработчик приведенный [2] сработает только тогда сервис уже "отвалится".


> Сергей М. ©   (22.12.06 09:45) [8]
>
> > где её скачать?
>
>
> Кажись, на сайте у Анатолия Подгорецкого (С) она есть.


GOOGLE
программирование серверных приложений djvu


 
Сергей М. ©   (2006-12-22 10:02) [10]


> Прогер   (22.12.06 08:54) [2]


Могу предложить "извращенный" способ глобального перехвата искл-й в сервис-процессе, хотя ты вряд ли его потянешь.

Суть метода заключается в перехвате либо вызова метода TEventLogger.LohMessage либо непосредственно WinAPI-ф-ции ReportEvent()

Впрочем, наверно есть более простой и документированный способ получения от системы уведомлений о событиях записи приложением инф-ции в сист.лог. Спроси у Игоря Шевченко (с), он, думаю, подскажет куда копать.


 
Прогер   (2006-12-22 10:40) [11]


> бработчик приведенный [2] сработает только тогда сервис
> уже "отвалится".


Смысл в том, чтобы протоколировать все исключительные ситуации, у которых нет "локального" try...except.


 
Сергей М. ©   (2006-12-22 10:51) [12]


> Прогер   (22.12.06 10:40) [11]


Что значит "проконтролировать" ?
Если просто вести протокол, так он и так уже ведется объектом Application, без необходимости твоего явного вмешательства. Инф-ция о необработанных исключениях исправно записывается в системный лог, там ты все это и увидишь.


 
oxffff ©   (2006-12-22 11:02) [13]


> Прогер   (22.12.06 10:40) [11]
>
> > бработчик приведенный [2] сработает только тогда сервис
>
> > уже "отвалится".
>
>
> Смысл в том, чтобы протоколировать все исключительные ситуации,
>  у которых нет "локального" try...except.


Так если нет локального "try...except".
управление выйдет за RUN, а перед еще и вызовет StartThread.Free;
Ты только запротоколируешь "падение сервиса".


 
Прогер   (2006-12-22 11:34) [14]


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


В журнале такая вот запись. Как так?

Сбой при запуске службы "имя" из-за ошибки: "имя" не является приложением Win32.


 
Сергей М. ©   (2006-12-22 11:38) [15]

А это не твой сервис такое исключение выдал. До его запуска дело вообще не дошло, судя по тексту в записи.


 
Прогер   (2006-12-22 11:45) [16]


> А это не твой сервис такое исключение выдал.

Боюсь, что мой. Только вот почему?

Раньше писал сервисы на Win2000, работало. Сейчас (первый раз) для WinXP. Создал "пустой" сервис - та же ошибка в системном журнале. В чём дело, понять не могу.


 
Сергей М. ©   (2006-12-22 11:51) [17]


> Боюсь, что мой


Не надо гадать.

Если сервис-приложение стартует, то ты поймаешь брейкпойнт на первой же его строчке.


 
Сергей М. ©   (2006-12-22 11:56) [18]

Более того, если бы ошибка была именно в твоем коде, в лог была бы записана строчка вида "Service failed on ...", а не та что ты наблюдаешь.


 
Прогер   (2006-12-22 12:05) [19]

С точками останова в сервисе проблема. Не успеваю к процессу подключиться. Поэтому отладку произвожу либо догадками, либо на основе протокола (локальные try...except).

Само сообщение "...не является приложением Win32" наводит на плохую мысль об ошибке, допущенной компилятором. Хотя с ключами -install, -uninstall отрабатывает с соответствующими сообщениями. Сервисы самой ОС, от антивируса и другие (не мои) работат без проблем.


 
Прогер   (2006-12-22 12:08) [20]

После попытки запуска сервиса появляется сообщение:

---------------------------
Службы
---------------------------
Не удалось запустить службу A123Service1 на Локальный компьютер.

Ошибка 193: 0xc1
---------------------------
ОК  
---------------------------

А в системном журнале: "... не явл-ся прил. Win32".


 
Сергей М. ©   (2006-12-22 12:18) [21]


> Не успеваю к процессу подключиться


см. стандартную справку "Debugging service applications"


> Само сообщение "...не является приложением Win32" наводит
> на плохую мысль об ошибке, допущенной компилятором


С трудом в это верится.

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


 
Прогер   (2006-12-22 12:21) [22]

Установил сервис на другой компьютер (тоже WinXP SP2 rus) - работает!


 
Сергей М. ©   (2006-12-22 12:24) [23]

Ну вот)
Все, оказывается, расчудесно работает.
А ты, понимаешь ли, развел бодягу про исключения)


 
Прогер   (2006-12-22 12:25) [24]


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


В Delphi7 Создать - ServiceAppl. Изменения: страрт вручную, отображаемое в консоли имя сервиса, OnStart (Started:= True;), OnStop (Stopped = True;). Ну мелочь в общем. Функционала никакого - просто запуск и останов.

Реестр не смотрел, после запуска с -install появляется сообщение "Service installed succ".


 
Прогер   (2006-12-22 12:27) [25]


> А ты, понимаешь ли, развел бодягу про исключения)


Окей, всё прекрасно. На чужом компьютере. А что же на моём? Куда копать-то... прям не знаю. Винду переустанавливать не охота...


 
Сергей М. ©   (2006-12-22 12:27) [26]


> Прогер   (22.12.06 12:25) [24]


Ну это уже не существенно, раз на другой машине все работает.


 
Сергей М. ©   (2006-12-22 12:30) [27]


> Прогер   (22.12.06 12:27) [25]


Попробуй программно стартовать свой сервис.

см. StartService() и пр. ф-ции для обеспечения работы оной.

Возможно код отказа, возвращенный по GetLasError при возврате ф-цией False, прояснит ситуацию.


 
Прогер   (2006-12-22 13:37) [28]


> Возможно код отказа, возвращенный по GetLasError при возврате
> ф-цией False, прояснит ситуацию


Код 193

{ %1 is not a valid Windows NT application. }
 ERROR_BAD_EXE_FORMAT = 193;


 
Сергей М. ©   (2006-12-22 13:44) [29]

Жуть какая) ...

Все-таки загляни в реестр, проверь правильность регистр.записей для этого сервиса


 
Прогер   (2006-12-22 13:46) [30]


> Все-таки загляни в реестр, проверь правильность регистр.
> записей для этого сервиса


Ещё бы понимать, что должно быть прописано в реестре :)

В общем, на днях переустанавлю ОС. Вот хохма будет, если ошибка сохраниться! :)


 
BiN ©   (2006-12-22 13:47) [31]


> Сергей М. ©   (22.12.06 13:44) [29]
>
> Жуть какая) ...
>
> Все-таки загляни в реестр, проверь правильность регистр.
> записей для этого сервиса

Думаю, именно в этом и дело. Т.к. борланд почему-то не следует рекомендации msdn:

lpBinaryPathName
[in] ... If the path contains a space, it must be quoted so that it is correctly interpreted.


 
BiN ©   (2006-12-22 13:48) [32]


> Прогер   (22.12.06 13:46) [30]
>
>
> Ещё бы понимать, что должно быть прописано в реестре :)

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\<Имя службы>\ImagePath


 
Сергей М. ©   (2006-12-22 13:56) [33]


> BiN ©   (22.12.06 13:47) [31]


Ну это легко проверить, разместив ехе-файл сервис-приложения по идентичному пути на той машине, где сервис успешно до этого стартовал.

Другой вопрос, почему система выдает такую идиотскую ошибку ?

Впрочем, это не новость. Схожая ситуация наблюдается при попытке загрузки заведомо существующего dll-модуля по заведомо корректному пути: если ф-ция DllMain() вернула не 0, система кричит, мол, указанный файл по указанному пути не найден, что есть очевидная ерунда.


 
BiN ©   (2006-12-22 14:06) [34]


> Сергей М. ©   (22.12.06 13:56) [33]
>
> Другой вопрос, почему система выдает такую идиотскую ошибку
> ?
>
> Впрочем, это не новость. Схожая ситуация наблюдается при
> попытке загрузки заведомо существующего dll-модуля по заведомо
> корректному пути: если ф-ция DllMain() вернула не 0, система
> кричит, мол, указанный файл по указанному пути не найден,
>  что есть очевидная ерунда.

Странно. У меня вот выдала "System Error.  Code: 1114.
A dynamic link library (DLL) initialization routine failed".


 
Прогер   (2006-12-22 14:08) [35]


> HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\<Имя
> службы>\ImagePath


Указан полный путь поиска EXE-файла с сервисом. Если всю строку взять в двойные кавычки - ЗАПУСКАЕТСЯ!!!


 
Прогер   (2006-12-22 14:11) [36]

Большое прогерское СПАСИБО за обсуждение темы!



Страницы: 1 вся ветка

Текущий архив: 2007.02.18;
Скачать: CL | DM;

Наверх




Память: 0.57 MB
Время: 0.035 c
2-1170354770
Jeeb
2007-02-01 21:32
2007.02.18
Номенклатурная база данных


2-1170232968
Lera
2007-01-31 11:42
2007.02.18
Теккстовый файл


15-1170163084
DevilDevil
2007-01-30 16:18
2007.02.18
FastMem для C++Builder


15-1169247208
Shumer
2007-01-20 01:53
2007.02.18
протокол ModBus


3-1164347417
Ольга
2006-11-24 08:50
2007.02.18
Дополнительный запрос в всплывающем меню