std :: set_terminate для DLL? - PullRequest
       22

std :: set_terminate для DLL?

2 голосов
/ 08 марта 2019

У меня есть DLL, которая будет загружена другим сторонним приложением.

Я пытаюсь выяснить, могу ли я перехватить какие-либо / все исключения, сгенерированные моей собственной DLL.

Если бы я отвечал за код приложения, я бы использовал std :: set_terminate в main (), чтобы настроить функцию обработки ошибок по всем параметрам.Но так как моя DLL будет внутри чужого приложения, я не могу вызвать std :: set_terminate в main ().

Есть ли способ для меня создать такое переопределение, которое просто применяет мой собственный код, безделать что-то неприятное, например, связывать каждую из функций моего приложения внутри блока try / catch или что-то в этом роде?

1 Ответ

4 голосов
/ 08 марта 2019

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

Цитирование из Стандарты кодирования C ++: 101 Правила, руководящие указания и рекомендации от HerbСаттер и Андрей Александреску:

Пункт 62: Не допускайте распространения исключений через границы модуля.

Не бросайте камни в сад соседа:Нет универсального бинарного стандарта для обработки исключений в C ++.Не позволяйте исключениям распространяться между двумя частями кода, если вы не контролируете параметры компилятора и компилятора, используемые для сборки обеих сторон;в противном случае модули могут не поддерживать совместимые реализации для распространения исключений.Как правило, это сводится к следующему: не позволяйте исключениям распространяться через границы модуля / подсистемы.

Когда вы имеете дело с DLL, в отличие от статической библиотеки, у вас нет никакойгарантии.Сторонним приложением, которое потребляет вашу DLL, является сторонний модуль (соседский сад).У вас нет гарантии, что оба модуля будут скомпилированы с одинаковыми параметрами компилятора и компилятора, поэтому вы не знаете, будут ли они обрабатывать исключения одинаково.На самом деле, вы даже не знаете, будут ли оба модуля написаны на C ++, поэтому позволить распространять исключения C ++ прямо сейчас.Существуют способы, с помощью которых вы можете успешно распространять исключения через границы модулей с помощью структурированной обработки исключений Windows (SEH), но это не следует делать.

Помимо технических проблем и проблем с реализацией, бросание исключений из DLL просто создает плохиеинтерфейс.Клиентское приложение не должно обрабатывать исключения из подпрограмм вашей DLL.Исключения составляют детали реализации: вы должны обрабатывать их внутренне.Если вам нужно указать успех или неудачу, верните код ошибки.Они могут быть легко обработаны с помощью любого языка, который может потреблять вашу DLL, от C до BASIC до Python.

Ваше предлагаемое решение состоит в том, чтобы в основном подключить глобальный необработанный обработчик исключений, который бы перехватывалвсе исключения, выданные вашей DLL до , пересекают границу модуля.Это на самом деле не существует.В DLL нет глобального обработчика исключений.Исключения распространяются путем раскручивания (повышения) стека вызовов, пока они не найдут подходящий обработчик.Если обработчик отсутствует, они будут распространяться вплоть до точки входа (main), а если не обрабатываться там, они приведут к завершению приложения, и операционная система представит «дружественный» диалог.Поэтому в приложении легко установить обработчик необработанных исключений.Для DLL нет такого эквивалента, потому что у DLL нет собственной единственной центральной функции main.Вместо этого он имеет набор точек входа : экспортированные функции, которые вызываются клиентским приложением.Таким образом, ваши необработанные обработчики исключений должны находиться в этих точках входа.

Каждая точка входа будет иметь свой собственный обработчик исключений.Вы можете в основном обернуть всю точку входа в большую попытку, если хотите.Таким образом, все ваши внутренние функции реализации могут создавать безрассудные исключения, но все они будут захвачены в точках входа, прежде чем им будет разрешено распространяться за пределы модуля.

Подумайте окаждая точка входа (экспортируемая функция) предоставляется вашей DLL как ее main функция , так как это в основном то, что она есть.Функция DllMain (как ее обычно называют в Windows) совершенно иная.Вы настолько сильно ограничены в том, что вам разрешено делать там, что вы никогда не должны вызывать код, который может вызвать исключение.

В качестве дополнительного пункта, вы, вероятно, не хотите вызывать abort или std::terminate из кода в DLL в любом случае, так как это прекратит весь процесс , включая клиентское приложение. Когда вы гость в чужом доме , , вам не следует звонить в компанию по сносу домов, чтобы уничтожить их дом . Записывайте свое исключение внутренне, но делайте все возможное, чтобы поддерживать согласованное внешнее состояние, и , а не сбой клиентского приложения только из-за внутренней ошибки.

...