VS2010 no muestra un mensaje de excepción no controlada en una aplicación WinForms en una versión de Windows de 64 bits

Resuelto Robert Hegner asked hace 13 años • 5 respuestas

Cuando creo un nuevo proyecto, obtengo un comportamiento extraño para las excepciones no controladas. Así es como puedo reproducir el problema:

1) cree una nueva aplicación de Windows Forms (C#, .NET Framework 4, VS2010)

2) agregue el siguiente código al Form1_Loadcontrolador:

int vara = 5, varb = 0;
int varc = vara / varb;
int vard = 7;

Esperaría que VS se rompa y muestre un mensaje de excepción no controlada en la segunda línea. Sin embargo, lo que sucede es que la tercera línea simplemente se omite sin ningún mensaje y la aplicación sigue ejecutándose.

No tengo este problema con mis proyectos C# existentes. Entonces supongo que mis nuevos proyectos se crean con algunas configuraciones predeterminadas extrañas.

¿Alguien tiene una idea de qué le pasa a mi proyecto?

Intenté marcar las casillas en Depurar->Excepciones. Pero luego las ejecuciones se interrumpen incluso si manejo la excepción en un try-catchbloque; que tampoco es lo que quiero. Si no recuerdo mal, había una columna llamada "excepciones no controladas" o algo así en este cuadro de diálogo, que haría exactamente lo que quiero. Pero en mis proyectos sólo hay una columna ("Lanzada").

Robert Hegner avatar Feb 08 '11 21:02 Robert Hegner
Aceptado

Este es un problema desagradable inducido por la capa de emulación wow64 que permite ejecutar código de 32 bits en la versión de 64 bits de Windows 7. Se traga excepciones en el código que se ejecuta en respuesta a una notificación generada por el administrador de ventanas de 64 bits. , como el Loadevento. Evitar que el depurador lo vea e intervenga. Este problema es difícil de solucionar, los grupos de Windows y DevDiv de Microsoft están señalando con el dedo hacia adelante y hacia atrás. DevDiv no puede hacer nada al respecto, Windows cree que es el comportamiento correcto y documentado, por misterioso que parezca.

Ciertamente está documentado , pero casi nadie entiende las consecuencias o piensa que es un comportamiento razonable. Especialmente no cuando el procedimiento de la ventana está oculto a la vista, por supuesto, como ocurre en cualquier proyecto que utiliza clases contenedoras para ocultar las tuberías de la ventana. Como cualquier aplicación Winforms, WPF o MFC. El problema subyacente es que Microsoft no pudo descubrir cómo hacer fluir las excepciones del código de 32 bits al código de 64 bits que activó la notificación al código de 32 bits que intenta manejar o depurar la excepción.

Es sólo un problema con un depurador adjunto, su código fallará como de costumbre sin uno.

Proyecto > Propiedades > pestaña Construir > Destino de plataforma = Cualquier CPU y desmarque Preferir 32 bits. Su aplicación ahora se ejecutará como un proceso de 64 bits, eliminando el modo de falla wow64. Algunas consecuencias: deshabilita Editar + Continuar para versiones de VS anteriores a VS2013 y es posible que no siempre sea posible cuando se depende de código de 32 bits.

Otras posibles soluciones:

  • Depurar > Excepciones > marque la casilla Lanzado para excepciones CLR para forzar al depurador a detenerse en la línea de código que genera la excepción.
  • Escriba try/catch en el Loadcontrolador de eventos y failfast en el bloque catch.
  • Úselo Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException)en el Main()método para que la captura de excepción en el bucle de mensajes no esté deshabilitada en el modo de depuración. Sin embargo, esto hace que todas las excepciones no controladas sean difíciles de depurar; el ThreadExceptionevento es bastante inútil.
  • Considere si su código realmente pertenece al Loadcontrolador de eventos. Es muy raro necesitarlo, sin embargo, es muy popular en VB.NET y en un canto de cisne porque es el evento predeterminado y un doble clic agrega trivialmente el controlador de eventos. Realmente solo lo necesita Loadcuando está interesado en el tamaño real de la ventana después de aplicar las preferencias del usuario y el escalado automático. Todo lo demás pertenece al constructor.
  • Actualice a Windows 8 o posterior, tienen este problema de wow64 solucionado.
Hans Passant avatar Feb 08 '2011 14:02 Hans Passant

En mi experiencia, solo veo este problema cuando lo ejecuto con un depurador adjunto. La aplicación se comporta igual cuando se ejecuta de forma independiente: la excepción no se acepta.

Con la introducción de KB976038 , puede hacer que esto vuelva a funcionar como esperaba. Nunca instalé la revisión, así que supongo que vino como parte de Win7 SP1.

Esto fue mencionado en esta publicación:

  • El caso de la excepción OnLoad que desaparece: excepciones de devolución de llamada en modo de usuario en x64

Aquí hay un código que habilitará la revisión:

public static class Kernel32
{
    public const uint PROCESS_CALLBACK_FILTER_ENABLED = 0x1;

    [DllImport("Kernel32.dll")]
    public static extern bool SetProcessUserModeExceptionPolicy(UInt32 dwFlags);

    [DllImport("Kernel32.dll")]
    public static extern bool GetProcessUserModeExceptionPolicy(out UInt32 lpFlags);


    public static void DisableUMCallbackFilter() {
        uint flags;
        GetProcessUserModeExceptionPolicy(out flags);

        flags &= ~PROCESS_CALLBACK_FILTER_ENABLED;
        SetProcessUserModeExceptionPolicy(flags);
    }
}

Llámelo al comienzo de su solicitud:

    [STAThread]
    static void Main()
    {
        Kernel32.DisableUMCallbackFilter();

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

He confirmado (con el ejemplo simple que se muestra a continuación) que esto funciona, tal como era de esperar.

protected override void OnLoad(EventArgs e) {
    throw new Exception("BOOM");   // This will now get caught.
}

Entonces, lo que no entiendo es por qué antes era imposible para el depurador manejar marcos de pila cruzados en modo kernel, pero con esta revisión, de alguna manera lo descubrieron.

Jonathon Reinhart avatar Aug 17 '2012 00:08 Jonathon Reinhart

Como menciona Hans, compila la aplicación y ejecuta el exe sin un depurador adjunto.

Para mí, el problema fue cambiar el nombre de una propiedad de Clase a la que estaba vinculado un control BindingSource. Al ejecutar sin el IDE pude ver el error:

No se puede vincular a la propiedad o columna SendWithoutProofReading en DataSource. Nombre del parámetro: miembro de datos

Arreglar el control BindingSource para vincularlo al nombre de propiedad actualizado resolvió el problema: ingrese la descripción de la imagen aquí

Jeremy Thompson avatar Mar 25 '2015 23:03 Jeremy Thompson

Estoy usando WPF y me encontré con el mismo problema. Ya había probado las sugerencias de Hans 1-3, pero no me gustaron porque Studio no se detenía en donde estaba el error (por lo que no podía ver mis variables y ver cuál era el problema).

Entonces probé la cuarta sugerencia de Hans. Me sorprendió la cantidad de código que podía trasladarse al constructor MainWindow sin ningún problema. No estoy seguro de por qué me acostumbré a poner tanta lógica en el evento Load, pero aparentemente gran parte de esto se puede hacer en el ctor.

Sin embargo, esto tenía el mismo problema que 1-3. Los errores que ocurren durante el ctor de WPF se incluyen en una excepción Xaml genérica. (una excepción interna tiene el error real, pero nuevamente quería que el estudio simplemente fallara en el punto del problema real).

Lo que terminó funcionando para mí fue crear un hilo, dormir 50 ms, volver al hilo principal y hacer lo que necesito...

    void Window_Loaded(object sender, RoutedEventArgs e)
    {
        new Thread(() =>
        {
            Thread.Sleep(50);
            CrossThread(() => { OnWindowLoaded(); });
        }).Start();
    }
    void CrossThread(Action a)
    {
        this.Dispatcher.BeginInvoke(a);
    }
    void OnWindowLoaded()
    {
        ...do my thing...

De esta manera, el estudio fallaría justo donde ocurre una excepción no detectada.

Gabe Halsmer avatar Feb 28 '2013 00:02 Gabe Halsmer