Необработанный обработчик исключений в .NET 1.1

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

Я добавил обработчики в Application.ThreadException и AppDomain.CurrentDomain.UnhandledException, которые действительно вызывают. Моя проблема в том, что стандартное диалоговое окно ошибки CLR по-прежнему отображается (до вызова обработчика исключений).

Джефф рассказывает об этой проблеме в своем блоге здесь и здесь. Но там нет решения. Так что же является стандартным способом в .NET 1.1 для обработки необработанных исключений и отображения удобного диалогового окна?

Ответ Джеффа был помечен как правильный ответ, поскольку предоставленная им ссылка содержит наиболее полную информацию о том, как сделать то, что требуется.

Ответ 1

О, в Windows Forms вы определенно должны быть способны заставить его работать. Единственное, что вы должны следить за событиями, происходящими на разных потоках.

У меня есть старая статья Code Project, которая должна помочь:

Удобная обработка исключений

Ответ 2

AppDomain.UnhandledException - это событие, а не глобальный обработчик исключений. Это означает, что к моменту его создания ваше приложение уже отправляется в канализацию, и вы ничего не можете с этим поделать, за исключением очистки и регистрации ошибок.

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

Не существует одноточечного решения этой ошибки. Вам нужно поставить реальный обработчик исключений (блок catch) вверх по течению от всех мест, где возникает эта ошибка, и перенаправить его (например) на метод/класс глобального обработчика, который будет определять, безопасно ли просто сообщать и продолжать, на основе тип исключения и/или контент.

Изменить: можно отключить (= взломать) механизм отчетности об ошибках, встроенный в Windows, поэтому обязательное диалоговое окно "сбой и запись" не отображается, когда ваше приложение опускается. Однако это становится эффективным для всех приложений в системе, а не только для ваших собственных.

Ответ 3

Необработанное поведение исключения в приложении .NET 1.x Windows Forms зависит от:

  • Тип потока, который выбрал исключение
  • Было ли это при обработке оконных сообщений
  • Был ли прикреплен отладчик к процессу
  • Настройка реестра DbgJitDebugLaunchSetting
  • Флаг jitDebugging в App.Config
  • Если вы переопределите обработчик исключений Windows Forms
  • Выполнял ли вы событие исключения CLR
  • Фаза луны

По умолчанию необработанные исключения:

  • Если исключение происходит в основном потоке при пересылке оконных сообщений, оно перехватывается обработчиком исключений Windows Forms.
  • Если исключение происходит в основном потоке при пересылке оконных сообщений, это прекратит процесс приложения, если он не будет перехвачен обработчиком исключений Windows Forms.
  • Если исключение встречается в ручном, потоковом потоке или потоке финализатора, он проглатывается CLR.

Точками контакта для необработанного исключения являются:

  • Обработчик исключений Windows Forms.
  • Переключатель реестра JIT-debug DbgJitDebugLaunchSetting.
  • Событие исключительной ошибки CLR.

Встроенная обработка исключений Windows Form делает по умолчанию следующее:

  • Захватывает необработанное исключение, когда:
    • исключение находится в основном потоке, и отладчик не подключен.
    • Исключение возникает при обработке оконных сообщений.
    • jitDebugging = false в App.Config.
  • Показывает диалог для пользователя и предотвращает завершение приложения.

Вы можете отключить последнее поведение, установив jitDebugging = true в App.Config. Но помните, что это может быть ваш последний шанс прекратить действие приложения. Таким образом, следующим шагом, чтобы поймать необработанное исключение, является регистрация для события Application.ThreadException, например:

Application.ThreadException += new
Threading.ThreadExceptionHandler(CatchFormsExceptions);

Обратите внимание на параметр реестра DbgJitDebugLaunchSetting в разделе HKEY_LOCAL_MACHINE\Software.NetFramework. Это одно из трех значений, о которых я знаю:

  • 0: показывает диалоговое окно пользователя с запросом "отладка или завершение".
  • 1: разрешает исключение для CLR для обработки.
  • 2: запускает отладчик, указанный в разделе реестра DbgManagedDebugger.

В Visual Studio перейдите в меню "Инструменты" → "Параметры" → "Отладка → JIT", чтобы установить этот ключ в 0 или 2. Но значение 1 обычно лучше всего подходит для конечного пользователя. Обратите внимание, что этот раздел реестра действует до события незавершенного исключения CLR.

Это последнее событие - ваш последний шанс зарегистрировать необработанное исключение. Он срабатывает до того, как ваши блоки finally завершатся. Вы можете перехватить это событие следующим образом:

AppDomain.CurrentDomain.UnhandledException += new
System.UnhandledExceptionEventHandler(CatchClrExceptions);

Ответ 4

Это консольное приложение или приложение Windows Forms? Если это консольное приложение .NET 1.1, это, к сожалению, задумано - это подтверждается разработчиком MSFT во втором сообщении в блоге, на которое вы ссылались:

Кстати, на моей машине 1.1 пример из MSDN имеет ожидаемый результат; просто вторая строка не появляется, пока вы не подключите отладчик (или нет). В v2 мы перевернули вещи так, что событие UnhandledException срабатывает до того, как подключается отладчик, что, по-видимому, является тем, чего большинство людей ожидают.

Похоже, что .NET 2.0 делает это лучше (слава богу), но, честно говоря, у меня никогда не было времени, чтобы вернуться и проверить.

Ответ 5

Это приложение Windows Forms. Исключения, которые пойманы Application.ThreadException, работают нормально, и я не получаю уродливое исключение .NET(OK для завершения, Cancel для отладки, кто придумал это?).

Я получал некоторые исключения, которые не были пойманы этим, и в итоге я попал в событие AppDomain.UnhandledException, которое вызывало проблемы. Я думаю, что я поймал большинство этих исключений, и теперь я показываю их в нашем хорошем окне ошибок.

Поэтому я просто должен надеяться, что нет никаких других обстоятельств, которые могли бы вызвать исключения, которые не будут улавливаться обработчиком Application.ThreadException.