Как работает SetUnhandledExceptionFilter in.NET приложения WinForms?

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

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

Я начал, следуя этой статье в блоге, чтобы установить обработчик SEH самостоятельно:http://blogs.microsoft.co.il/blogs/sasha/archive/2007/12.aspx. Этот метод работает для консольных приложений, но когда я пробую то же самое из приложения WinForms, мой фильтр не вызывается для каких-либо различных неуправляемых исключений.

что может делать ClrDump, чего я не делаю? ClrDump создает дампы во всех случаях, поэтому его фильтр исключений надо еще позвонить...

примечание: Я знаю о возможностях ADPlus, и мы также рассмотрели использование разделов реестра AeDebug... Это тоже возможности, но есть и компромиссы.

спасибо, Дэйв!--2-->

// Code adapted from <http://blogs.microsoft.co.il/blogs/sasha/archive/2007/12.aspx>
LONG WINAPI MyExceptionFilter(__in struct _EXCEPTION_POINTERS *ExceptionInfo)
{
   printf("Native exception filter: %Xn",ExceptionInfo->ExceptionRecord->ExceptionCode);

   Beep(1000,1000);
   Sleep(500);
   Beep(1000,1000);

   if(oldFilter_ == NULL)
   {
      return EXCEPTION_CONTINUE_SEARCH;
   }

   LONG ret = oldFilter_(ExceptionInfo);
   printf("Other handler returned %dn",ret);

   return ret;
}



#pragma managed

namespace SEHInstaller
{
   public ref class SEHInstall
   {
   public:
      static void InstallHandler()
      {    
         oldFilter_ = SetUnhandledExceptionFilter(MyExceptionFilter);
         printf("Installed handler old=%xn",oldFilter_);
      }


   };
}

3 ответов


Windows Forms имеет встроенный обработчик исключений, который по умолчанию выполняет следующие действия:

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

вы можете отключить первое поведение, установив jitDebugging = true в приложение.Конфиг. Это означает, что ваш последний шанс остановить завершение приложения-поймать необработанное исключение, зарегистрировавшись в приложении событий.ThreadException, например, в C#:

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

Если вы решили не ловить необработанное исключение здесь, то вам нужно будет проверить и/или изменить параметр реестра DbgJitDebugLaunchSetting в разделе HKLM\Software.NetFramework. Это имеет одну из трех ценностей, из которых я в курсе:

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

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

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


Если вы хотите, чтобы ваши исключения потока GUI работали так же, как ваши-не GUI, так что они обрабатываются одинаково, вы можете сделать это:

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);

вот фон:

в приложении manged GUI по умолчанию исключения, возникающие в потоке GUI, обрабатываются тем, что назначено приложению.ThreadException, который вы можете настроить следующим образом:

Application.ThreadException += 
    new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);

исключения, которые возникают в других потоках, обрабатываются домен приложений.CurrentDomain.UnhandledException, который вы можете настроить следующим образом:

AppDomain.CurrentDomain.UnhandledException += 
    new UnhandledExceptionEventHandler(Program.CurrentDomain_UnhandledException);

назначение UnHandledException работает точно так же, как вызов Win32 SetUnhandledExceptionFilter.

Если вы хотите создать минидампы, а затем использовать их, вам нужно будет использовать инструменты отладки для Windows, sos.файл DLL. Вам нужно будет произвести minidumps MiniDumpWithFullMemory.

и тогда, даже тогда, у вас, вероятно, не будет всего, что вы могли бы хотеть. Система.Диагностика.StackTrace, чтобы получить стек управляемых вызовов вызова.


SetUnhandledExceptionFilter устанавливает обработчик, который вызывается, когда Win32-excpetion достигает верхней части callstack потоков без обработки.

во многих языковых средах выполнения, включая управляемые, языковые исключения реализуются с использованием исключений Win32. Но управляемая среда выполнения будет иметь верхний уровень __try _ _ catch(...) блок в верхней части каждого потока, который будет ловить любые исключения win32 для выполнения и обрабатывать их, не позволяя им бежать на верхний уровень Win32 обработчик.

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