2011-02-08 8 views
74

Cuando creo un nuevo proyecto, obtengo un comportamiento extraño para las excepciones no controladas. Esta es la forma en que puedo reproducir el problema:VS2010 no muestra mensaje de excepción no controlada en una aplicación de WinForms en una versión de Windows de 64 bits

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

2) añadir el siguiente código al controlador de Form1_Load:

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

Supongo que VS se rompe y muestra 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 salta sin ningún mensaje y la aplicación sigue ejecutándose.

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

¿Alguien tiene una idea de lo que está mal con mi proyecto?

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

+0

mismo problema aquí! La carga de formulario ya capta excpections internamente. – Pedro77

Respuesta

114

Este es un problema desagradable inducido por la capa de emulación wow64 que permite que el código de 32 bits se ejecute en la versión de 64 bits de Windows 7. Traga excepciones en el código que se ejecuta en respuesta a una notificación generada por el 64 Administrador de ventana de bit, como el evento Load. Impedir que el depurador lo vea y al intervenir. Este problema es difícil de solucionar, los grupos de Windows y DevDiv en Microsoft apuntan 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 suene.

Sin duda es documented 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 en cualquier proyecto que use clases de contenedor para ocultar la plomería de la ventana. Como cualquier aplicación Winforms, WPF o MFC. El problema subyacente es que Microsoft no pudo descifrar cómo hacer que las excepciones del código de 32 bits vuelvan al código de 64 bits que desencadenó la notificación de nuevo al código de 32 bits que intenta manejar o depurar la excepción.

Es solo un problema con un depurador conectado, su código se encenderá como de costumbre sin uno.

Project> Properties> Build tab> Platform target = AnyCPU y deshabilita Prefer 32-bit. Su aplicación ahora se ejecutará como un proceso de 64 bits, eliminando el modo de falla wow64. Algunas consecuencias, deshabilita Editar + Continuar para las versiones de VS anteriores a VS2013 y es posible que no siempre sea posible cuando tiene una dependencia en el código de 32 bits.

Otras soluciones posibles:

  • Test> Excepciones> marque la casilla lanzado para excepciones CLR para forzar el depurador se detenga en la línea de código que produce la excepción.
  • Escribir try/catch en el controlador de eventos Load y failfast en el bloque catch.
  • Use Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException) en el método Main() para que la excepción trampa en el bucle de mensajes no se deshabilite en el modo de depuración.Sin embargo, esto hace que todas las excepciones no controladas sean difíciles de depurar, el evento ThreadException es bastante inútil.
  • Considere si su código pertenece realmente en el controlador de eventos Load. Es muy raro que lo necesite, sin embargo es muy popular en VB.NET y una canción de cisne porque es el evento predeterminado y un doble clic agrega trivialmente el controlador de eventos. Solo Realmente necesita Load cuando está interesado en el tamaño real de la ventana después de aplicar las preferencias del usuario y la autoescala. Todo lo demás pertenece al constructor.
  • Actualice a Windows 8 o posterior, tienen este problema wow64 resuelto.
+0

¿Tiene alguna referencia para este error? ¿Conectar artículo, tal vez? –

+6

Sí, hay un artículo de Connect para él. Muchos de ellos. Esta es probablemente la mejor: https://connect.microsoft.com/VisualStudio/feedback/details/357311/silent-exceptions-on-x64-development-machines –

+5

Y aquí hay una que sugiere que no tienen mucha idea ¿Qué está pasando ?: https://connect.microsoft.com/VisualStudio/feedback/details/589858/form-load-event-unhandled-exception-not-caught-from-inside-visual-studio-but-caught-when- app-started-outside-visual-studio –

9

En mi experiencia, solo veo este problema cuando estoy ejecutando un depurador conectado. La aplicación se comporta igual cuando se ejecuta de forma independiente: la excepción no se ingiere.

Con la introducción de KB976038, puede hacer que esto funcione como era de esperar. Nunca instalé la revisión, así que supongo que fue parte de Win7 SP1.

Esto fue mencionado en este post:

Aquí hay un código que permitirá 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); 
    } 
} 

Llame al comienzo de su aplicación:

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

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

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

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

lo tanto, lo que no entiendo, es por eso que antes era imposible para el depurador de manejar cruzar marcos de pila de modo de núcleo, pero con esta revisión, que de alguna manera lo descubrió.

+0

'Set/GetProcessUserModeExceptionPolicy' aún no están documentados en MSDN, y Kernel32.dll de Windows 8 no los exporta. – Martin

+0

¿No hay una manera de hacer lo mismo editando el registro o algo así? – ThunderGr

+1

Los he leído. También leí el comentario de que el kernel de Windows 8 no exporta estos métodos. Por casualidad corro en Windows 8. Solo preguntaba, por las dudas. – ThunderGr

1

Estoy usando WPF y encontré este mismo problema. Ya había probado las sugerencias de Hans 1-3, pero no me gustaron porque el estudio no se detuvo donde estaba el error (así que no pude ver mis variables y ver cuál era el problema).

Así que probé la cuarta sugerencia de Hans. Me sorprendió ver cuánto de mi código podía moverse al constructor MainWindow sin ningún problema. No estoy seguro de por qué tuve el hábito de poner tanta lógica en el evento Load, pero aparentemente gran parte de esto se puede hacer en el ctor.

Sin embargo, esto tuvo el mismo problema que 1-3. Los errores que ocurren durante el ctor para WPF se envuelven en una excepción Xaml genérica. (Una excepción interna tiene el error real, pero nuevamente quería que el estudio se rompa en el lugar del problema real).

Lo que terminó trabajando para mí fue la creación de un hilo, 50 ms de sueño, el envío de nuevo a 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 se rompería estudio justo donde se produce una excepción no capturada .

3

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

Para mí, el problema era cambiar un nombre de propiedad de Clase al que estaba obligado un control BindingSource. Correr sin el IDE que era capaz de ver el error:

Cannot bind to the property or column SendWithoutProofReading on the DataSource. Parameter name: dataMember

Fijación del control de BindingSource para enlazar con el nombre actualizado propiedad ha resuelto el problema: enter image description here

0

Una solución alternativa sencilla podría ser si se puede mover el código de inicio a otro evento como Form_Shown como el que llama a más tardar , y usar una bandera para ejecutar código de inicio en la primera forma que se muestra:

bool firstLoad = true; //flag to detect first form_shown 

private void Form1_Load(object sender, EventArgs e) 
{ 
    //firstLoad = true; 
    //dowork(); //not execute initialization code here (postpone it to form_shown) 
} 

private void Form1_Shown(object sender, EventArgs e) 
{ 
    if (firstLoad) //simulate Form-Load 
    { 
     firstLoad = false; 

     dowork(); 
    } 
} 

void dowork() 
{ 
    var f = File.OpenRead(@"D:\NoSuchFile756.123"); //this cause an exception! 

} 
Cuestiones relacionadas