Application.ThreadException vs AppDomain.UnhandledException

Сначала немного фона: у меня есть многопоточное приложение WinForms, которое делает interop для родных dll. Это приложение иногда срабатывает с необработанным исключением, и мы пытаемся выяснить, почему это происходит. Чтобы облегчить это, я создаю глобальный обработчик исключений, и я планирую сгенерировать из него файл процесса dumpfile.

Теперь на вопрос: на данный момент у этого приложения есть обработчик для Application.ThreadException, но он по-прежнему падает с необработанным исключением. Я думаю о добавлении обработчика для AppDomain.UnhandledException, хотя я не уверен, что он поможет. Есть ли возможное необработанное исключение в этом сценарии, которое не будет улавливаться Application.ThreadException?

Ответ 1

Да, Application.ThreadException может захватывать только исключения, возникающие в потоке пользовательского интерфейса. В коде, который запускается из-за уведомлений Windows. Или в технических терминах, события, вызванные контуром сообщения. Большинство событий Winforms соответствуют этой категории.

То, что это не ловушка, - это исключения, возникающие в любом потоке, отличном от UI, например, рабочий поток, запущенный с Thread.Start(), ThreadPool.QueueUserWorkItem или метод BeginInvoke() делегата. Любое необработанное исключение в этих случаях прекратит приложение, AppDomain.UnhandledException - последний вздох.

Идя дальше вниз, аппаратные исключения, которые возникают в неуправляемом потоке с помощью собственного кода, который никогда не вызывал никакого управляемого вызова CLR, не могут быть обнаружены с помощью какого-либо механизма CLR. AccessViolation (код исключения 0xc0000005) является наиболее распространенной причиной смерти. Единственный способ уловить их - через API Windows, SetUnhandledExceptionFilter(). Это трудно понять.

Вы можете отключить Application.ThreadException с Application.SetUnhandledExceptionMode(). Который разумно делать, предоставляя пользователю параметр "Продолжить", не имеет большого смысла. Теперь все исключения в управляемых потоках ведут себя одинаково, используйте AppDomain.UnhandledException для их регистрации.

Ответ 2

Application.ThreadException будет поднят только для необработанных исключений в потоках пользовательского интерфейса WinForms (см. здесь.) Добавление обработчика для AppDomain.UnhandledException может помочь в этом случае (хотя и с некоторыми оговорками, как описано в разделе примечаний здесь.)

Ответ 3

Я настоятельно рекомендую вам использовать генерацию мини-дисков OS вместо своих собственных. Это происходит по нескольким причинам:

  • Генерирование мини-накопителя из одного и того же процесса крайне проблематично и не всегда возможно.
  • К моменту запуска ThreadException или UnhandledException стек исключений уже разворачивается. Генерирование minidump в этой точке просто укажет вам на обработчик, а не на источник исключения.

Если ваше приложение находится в поле, используйте WER. Если вы проводите внутреннее тестирование, используйте ProcDump. Вы также можете просто скопировать файл minidump, пока диалоговое окно отчета об ошибках активно.

P.S. Существуют некоторые исключительные условия - особенно при выполнении p/Invoke - где не работают ThreadException и UnhandledException.

P.P.S. Если у вас есть сценарий отладки, попробуйте включить "Помощники по отладке" , относящиеся к p/Invoke.