Как я могу создать глобальный обработчик исключений в DLL? - PullRequest
5 голосов
/ 06 июня 2011

Я работаю в DLL, которая иногда вызывает необработанные исключения. Я использую madExcept для обнаружения и отладки глючного кода, но когда я наконец разверну свою DLL, я хочу включить свой собственный глобальный обработчик исключений в DLL для регистрации исключений.

Итак, вопрос в том, как мне установить глобальный обработчик исключений в моей Delphi DLL?

Ответы [ 2 ]

10 голосов
/ 06 июня 2011

Что именно вы имеете в виду под «глобальным обработчиком исключений»?

В 32-разрядной версии Windows Структурная обработка исключений (SEH) находит обработчик путем обхода цепочки обработчиков исключений потока, в котором исключениепроизошло.Цепочка обработчика исключений представляет собой связанный список записей, заголовок которых находится в FS:[0];записи обычно размещаются в стеке, помещаются в каждый try и извлекаются при выходе из защищенного блока.Там есть процедура обратного вызова, на которую ссылается каждая запись исключения;Windows вызывает эту процедуру с деталями исключения во время фазы поиска, чтобы определить, собирается ли этот «уровень» цепочки «обрабатывать» исключение.Затем Windows раскручивает стек вызовов до этой точки, снова пройдя через цепочку исключений, вызывая каждый обратный вызов с другим значением, сообщая ему, что происходит раскручивание, пока не достигнет обработчика, который выбрал обработку исключения.Если обработчик не найден, процесс завершается, жестко, без уведомления.Обычно этого не происходит;ОС устанавливает собственный обработчик последнего шанса в нижней части стека (последний элемент в цепочке), и это обычно вызывает знакомое диалоговое окно «У этой программы возникла проблема».Но если что-то стало очень испорченным, или цепочка обработчика исключений была запутана, чтобы удалить его, то процесс идет тяжело.

Итак, из этого краткого обзора обработки исключений в Windows должно быть ясно, чтонет единого «глобального» обработчика, есть только список обработчиков, один список на поток (регистр FS является частью контекста потока);и обработчик «последнего шанса» - тот, который установлен самым ранним в стеке.Самый простой способ перехвата исключения, возникающего внутри вашей DLL, - это немедленно установить обработчик исключения в каждой точке входа.См. Ответ Мейсона, чтобы узнать, как это сделать (это с try / except);но имейте в виду, что если ваша DLL перезванивает куда-то еще (например, через процедуру обратного вызова), то вы можете ловить исключения, которые «не предназначены» для вас и не вызваны вашим кодом.(Неправильно ожидать, что исключения будут распространяться так же через сторонний код на уровне DLL, но это может произойти.)

10 голосов
/ 06 июня 2011

Понятие «глобальный обработчик исключений» на самом деле не существует в DLL, как это существует в VCL.Чтобы понять почему, помните, что исключения распространяются путем разматывания стека, пока они не смогут найти обработчик.VCL может установить глобальный обработчик исключений, потому что в приложении VCL все, что происходит (исключая запуск и завершение работы), будет иметь TApplication.Run где-то в стеке вызовов, и именно туда он помещает обработчик исключений.Поскольку ваша DLL не имеет единой центральной точки, подобной этой, вы не можете сделать это таким образом.

Что вы можете сделать, так это установить «центральную процедуру обработки исключений» в вашей DLL где-нибудь.Он должен принимать объект Exception в качестве параметра.Затем сделайте что-то подобное для всех ваших экспортируемых подпрограмм:

procedure MyExportedRoutine(param: integer);
begin
  try
    //do normal stuff
  except
    on E: Exception do
      CentralExeptionHandler(E);
  end;
end;

Это действительно лучшее, что вы можете сделать, если вы не используете COM.Если вы пишете COM DLL, пометьте свои методы интерфейса соглашением о вызовах safecall, и компилятор автоматически сгенерирует для вас код, который позаботится о распространении исключений.

...