c# - ¿Cómo funciona SetUnhandledExceptionFilter en aplicaciones.NET WinForms?
debugging clrdump (3)
Estoy trabajando en un proyecto para mejorar nuestras capacidades de depuración de producción. Nuestro objetivo es producir de manera confiable un minivolcado en cualquier excepción no controlada, ya sea que la excepción se administre o no, y si se produce en un subproceso administrado o no administrado.
Utilizamos la excelente biblioteca ClrDump para esto actualmente, pero no proporciona las características exactas que necesitamos, y me gustaría entender los mecanismos detrás del filtrado de excepciones, así que me propuse probar esto por mí mismo.
Comencé siguiendo este artículo de blog para instalar un manejador SEH mismo: http://blogs.microsoft.co.il/blogs/sasha/archive/2007/12.aspx . Esta técnica funciona para aplicaciones de consola, pero cuando intento lo mismo desde una aplicación de WinForms, mi filtro no recibe ninguna variedad de excepciones no administradas.
¿Qué puede hacer ClrDump que no estoy haciendo? ClrDump produce volcados en todos los casos, por lo que su filtro de excepción todavía se debe llamar ...
Nota: soy consciente de las capacidades de ADPlus, y también hemos considerado utilizar las claves de registro de AeDebug ... Estas también son posibilidades, pero también tienen sus compensaciones.
Gracias, 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_);
}
};
}
SetUnhandledExceptionFilter instala un controlador que se invoca cuando un Win32-excpetion alcanza la parte superior de una pila de llamadas de subprocesos sin ser procesado.
En muchos lenguajes de ejecución, incluidas las excepciones de idioma administrado, se implementan usando excepciones de Win32. Sin embargo, el tiempo de ejecución administrado tendrá un bloque __try __catch (...) de nivel superior en la parte superior de cada hilo que atrapará cualquier win32 a las excepciones de tiempo de ejecución y las procesará sin permitirles escapar al controlador de nivel superior de Win32.
El conocimiento del tiempo de ejecución específico sería necesario para inyectar un controlador en este nivel porque nunca se permitirá que las excepciones escapen al controlador TheadProc de Win32.
Si desea que las excepciones de subprocesos de la GUI funcionen igual que las que no son GUI, para que se manejen de la misma manera, puede hacer esto:
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
Aquí está el fondo:
En una aplicación GUI administrada, de forma predeterminada, las excepciones que se originan en el hilo de la GUI son manejadas por lo que está asignado a la Application.ThreadException, que puede personalizar de esta manera:
Application.ThreadException +=
new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Excepciones que se originan en los otros subprocesos son manejadas por AppDomain.CurrentDomain.UnhandledException, que puede personalizar de esta manera:
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(Program.CurrentDomain_UnhandledException);
Asignar a UnHandledException funciona exactamente como llamar a Win32 SetUnhandledExceptionFilter.
Si su objetivo es crear minivolcados y luego usarlos, necesitará usar herramientas de depuración para Windows, sos.dll. Tendrá que producir minivolcados MiniDumpWithFullMemory.
Y luego, incluso entonces, probablemente no tendrás todo lo que quieras. System.Diagnostics.StackTrace para obtener la pila de llamadas administradas de llamadas.
Windows Forms tiene un controlador de excepciones integrado que hace lo siguiente de forma predeterminada:
- Captura una excepción administrada no controlada cuando:
- sin depurador adjunto, y
- la excepción ocurre durante el procesamiento del mensaje de ventana, y
- jitDebugging = false en App.Config.
- Muestra el diálogo al usuario y evita la finalización de la aplicación.
Puede desactivar el primer comportamiento configurando jitDebugging = true en App.Config. Esto significa que su última oportunidad para detener la finalización de la aplicación es atrapar la excepción no controlada registrándose para el evento Application.ThreadException, por ejemplo, en C #:
Application.ThreadException += new Threading.ThreadExceptionHandler(CatchFormsExceptions);
Si decide no detectar la excepción no controlada aquí, deberá verificar y / o cambiar la configuración del registro DbgJitDebugLaunchSetting en HKLM / Software.NetFramework. Esto tiene uno de los tres valores que conozco:
- 0: muestra el cuadro de diálogo del usuario que pregunta "depurar o finalizar".
- 1: deja pasar la excepción a través de CLR.
- 2: inicia el depurador especificado en la clave de registro DbgManagedDebugger.
En Visual Studio, vaya a Herramientas> Opciones> Depuración> JIT para establecer esta clave en 0 o 2. Pero un valor de 1 es generalmente lo que desea en la máquina de un usuario final. Tenga en cuenta que esta clave de registro se aplica antes del evento de excepción CLR no controlada que usted discute.
Luego puede establecer el filtro de excepción nativo que discutió.