Как SetUnhandledExceptionFilter работает в приложениях .NET WinForms? - PullRequest
10 голосов
/ 24 октября 2008

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

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

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

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

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

Спасибо, Dave

// 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: %X\n",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 %d\n",ret);

   return ret;
}



#pragma managed

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


   };
}

Ответы [ 3 ]

9 голосов
/ 26 октября 2008

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

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

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

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

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

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

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

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

4 голосов
/ 26 сентября 2009

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

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);

Вот фон:

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

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

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

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

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

Если ваша цель - создать мини-дампы и затем использовать их, вам нужно будет использовать средства отладки для Windows, sos.dll. Вам нужно будет производить мини-дампы MiniDumpWithFullMemory.

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

2 голосов
/ 24 октября 2008

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...