Конференция "WinAPI" » Перехват исключений в службе
 
  • A.W.E.S.O.M.E - O 4000 (30.11.11 10:33) [0]
    У меня есть проект, написанная на Delphi. Проект включает одну службу, которая, кроме основного потока, имеет еще и дополнительный. Оба потока работают все время функционирования службы.
    Можно ли как-нибудь получить возможность централизованно перехвата всех исключений, которые возникнут в любом месте службы? В идеале — в любом месте запущенного exe (т.к. он может содержать несколько служб и имеет еще общий для всех служб поток, в котором вызывается Run()).

    Дело в том, что все исключения дополнительного потока Delphi «съедает», если их не обработал разработчик. Кроме того в основном потоке службы есть таймер. Я охватил OnStart и OnTimer блоками try/except. Но что если исключение вылезет внутри «фреймворка»? Т.е., например, внутри «процедуры», которая запускает OnTimer? Или внутри механизма, пускающего execute у потока? В общем, я хочу иметь возможность перехватывать все исключения. Желательно — централизованно.

    Заранее спасибо.

    PS: В Net вот есть такой механизм. Пусть и не буз своих заморочек (хотя скорее всего я просто его недопонял еще). А в Delphi потоки молча ловят исключения и у сервиса нет onexcept (хотя я могу запросто использовать ApplicationException, который просто не будет функционировать). «Жалоб нет, но как-то неаккуратно выглядит» ©
  • Сергей М. © (30.11.11 10:46) [1]
    Охвати в try..except тела каждого из обработчиков ServiceStart, ServiceStop, ServiceExecute каждого сервиса в составе своего ServiceApplication - этим ты будешь контролировать исключения в тредах, автоматически создаваемых твоим ServiceApplication.

    Для тредов, явно создаваемых тобой самим, либо охватывай в try..except тела Execute (при использовании TThread) либо обрабатывай Application.OnException.
  • A.W.E.S.O.M.E - O 4000 (30.11.11 11:11) [2]
    > [1] Сергей М. ©   (30.11.11 10:46)

    Тоесть охватывание try/except всех обработчиков (в т.ч. и Timer.OnTimer) и метода Execute дополнительного потока гарантирует то, что все исключения будут перехвачены?
    Среда не может выбросить исключение так сказать «между» этими процедурами?

    PS: у службы нет TServiceApplication.onException. В том числе и в Delphi XE. Не знаю, почему разработчики так сделали, но видимо, были какие-то причины. Хотя есть интересный метод в protected части (DoHandleException). Но раз его туда поместили, не думаю, что простое его переопределение в наследнике что-то даст.
  • Rouse_ © (30.11.11 11:12) [3]

    > Дело в том, что все исключения дополнительного потока Delphi
    > «съедает»

    Чего это съедает?
    TThread.FatalException по завершению нити просто смотри, там все будет...
  • Rouse_ © (30.11.11 11:16) [4]
    Зы ну и можно глобальный обработчик повесить через AddVectoredExceptionHandler
  • CRLF (30.11.11 11:23) [5]

    > через AddVectoredExceptionHandler
    Это что за зверь?
  • Сергей М. © (30.11.11 11:40) [6]
    > охватывание try/except всех обработчиков (в т.ч. и Timer.OnTimer) и метода Execute

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

    > у службы нет TServiceApplication.onException

    Так уж велика проблема сляпать его ручками по образу и подобию TApplication ?
  • Rouse_ © (30.11.11 11:42) [7]

    > CRLF   (30.11.11 11:23) [5]
    > Это что за зверь?

    Это замена стандартному SEH.
    http://msdn.microsoft.com/en-us/library/ms679274%28VS.85%29.aspx
    Работает начиная с ХР
  • CRLF (30.11.11 11:50) [8]

    > Rouse_ ©   (30.11.11 11:42) [7]
    Спасибо, почитаю.
  • A.W.E.S.O.M.E - O 4000 (30.11.11 11:58) [9]
    > Зы ну и можно глобальный обработчик повесить через AddVectoredExceptionHa
    > ndler

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

    try
     ...
     if a > 0 then rez := a
     else raise Exception('');
     ...
    except
     rez := 100;
    end;



    то  AddVectoredExceptionHandler сработает на это исключение точно так же, как и на любое другое...


    > достаточен перехват в верхнеуровневой ф-ции/процедуре

    А где эта функция? Ведь блок begin...end в файле проекта — это отдельный поток и до него не дойдет исключение из потоков служб. Или есть другая main функция для потока службы?


    > TThread.FatalException

    Спасибо. Про это не знал. А можно как-нибудь в begin...end завернуть Run в try/except и внутри except проверить FatalException для потока службы? Т.е. я могу как-нибудь получить доступ к объекту этого потока?
  • A.W.E.S.O.M.E - O 4000 (30.11.11 12:00) [10]
    > Спасибо. Про это не знал. А можно как-нибудь в begin...end
    > завернуть Run в try/except и внутри except проверить FatalException
    > для потока службы? Т.е. я могу как-нибудь получить доступ
    > к объекту этого потока?

    Что-то я запутанно написал. Поэтому уточню:

    try
     ...
     Application.Run;
    finally
     //Как тут проверить FatalException  для потока службы?
    end;
  • Сергей М. © (30.11.11 12:17) [11]
    > где эта функция?

    Для основного потока - это Application.Run

    Для дополнительного - это ServiceThread.Execute, в теле которого вызываются обработчики TService.OnStart/Stop/Execute
  • Сергей М. © (30.11.11 12:24) [12]
    try
    ...
    Application.Run;
    finally
    //Как тут проверить FatalException  для потока службы? тут уже никак - в этот момент потоки всех служб уже уничтожены
    end;
  • A.W.E.S.O.M.E - O 4000 (30.11.11 13:08) [13]
    > Для дополнительного — это ServiceThread.Execute, в теле
    > которого вызываются обработчики TService.OnStart/Stop/Execute

    У сервиса есть FServiceThread и соответствующее свойство, доступное только для чтения.
    Получается, что единственный выход — переписать TService и TServiceThread?
    Не думаю, что возьмусь за это, т.к. скорее всего, в итоге добавлю кучу глюков...
  • Сергей М. © (30.11.11 13:29) [14]

    > единственный выход — переписать TService и TServiceThread?


    Накой ?
    Все что нужно - завернуть в try..except тела обработчиков TService.OnStart/Stop/Execute
  • A.W.E.S.O.M.E - O 4000 (30.11.11 13:45) [15]
    > Накой ?
    > Все что нужно — завернуть в try..except тела обработчиков
    > TService.OnStart/Stop/Execute

    Даже если у меня OnStart активизирует таймер? Потом же OnStart завершается, Stop еще не приходит, Execute=nil, а таймер время от времени генерирует событие OnTimer, в котором и выполняется большая часть логики программы.
  • Сергей М. © (30.11.11 14:13) [16]

    > Execute=nil


    Ну так сделай не-nil..
    Там же в простейшем случае совсем незамысловатый цикл потребуется:

    while not Terminated do
     ProcessRequests(True);

    //  в дебрях этого метода вызывается обработчик твоего таймера

    Его и оберни в try..except
 
Конференция "WinAPI" » Перехват исключений в службе
Есть новые Нет новых   [134430   +4][b:0][p:0.001]