Если вы перехватываете событие AppDomain.UnhandledException, то проблема не в том, что они могут перезванивать в фоновом потоке, а в том, что сторонняя библиотека явно проглатывает исключения, создаваемые обработчиками. Это библиотека с плохим поведением, но, поскольку вы пишете код обработчика событий, вы можете перехватить исключения в обработчике событий и принудительно закрыть приложение.
Поскольку стороннюю библиотеку нельзя остановить с помощью исключения, вы можете принудительно завершить поток, вызвав:
Thread.CurrentThread.Abort();
Thread.Abort()
обычно считается плохой практикой, но здесь это немного менее опасно, поскольку вы прерываете себя и, следовательно, не будете вводить исключение в потенциально неприятные места (вы также знаете, что поток не находится в неуправляемом контекст, поэтому он сразу прекратит работу.) Это все еще неприятный хак, но стороннее приложение не дает вам большого выбора. Исключение ThreadAbortException нельзя «остановить», поэтому сторонний код завершит свой поток, как только достигнет конца своих обработчиков исключений (даже если они попытаются его проглотить). Если сторонняя библиотека действительно противна, она может вызывать много кода в своем catch или, наконец, блоках, даже используя грязные трюки, чтобы остаться в живых, как запуск других потоков, но это должно быть довольно злонамеренным, чтобы сделать это.
Чтобы получить понятное поведение сообщения об ошибке, вы можете перенаправить Исключение в ваш поток пользовательского интерфейса, используя SynchronizationContext или Dispatcher, чтобы вызвать отображение вашего обработчика исключений (самый простой способ - просто перебросить исключение; я рекомендую встроить его как InnerException, так что вы не потеряете трассировку стека.)
Если вы действительно не доверяете библиотеке (и не хотите давать ей возможность остаться в живых даже через ее перехват и блоки наконец), вы можете явно выполнить маршалинг потока пользовательского интерфейса с помощью блокирующего вызова (для отображения вашего сообщения об ошибке) по-дружески), а затем позвоните Environment.FailFast()
, чтобы убить ваш процесс. Это особенно жесткий способ завершить работу (он не будет вызывать никакого кода очистки и буквально прерывает процесс как можно быстрее), но он сводит к минимуму возможность любых потенциально вредных побочных эффектов, если состояние приложения стало очень поврежденным. Здесь можно следить за тем, чтобы поток пользовательского интерфейса мог быть заблокирован каким-либо другим вызовом пользовательского интерфейса, связанным со сторонним кодом. Если это произойдет, приложение будет заблокировано. Опять же, это было бы довольно злонамеренно, так что вы, вероятно, можете игнорировать это.