2016-05-25 6 views
7

Ich habe eine WinForm Anwendung in C# geschrieben, wo ich einen try-catch Block in der Program.cs setzen, in dem Programmeintrag, die static void Main Methode, gleich zu Beginn der Anwendung wie folgt aus:Kann C# WinForm static void Haupt nicht abfangen Ausnahme?

using System; 
using System.IO; 
using System.Windows.Forms; 

namespace T5ShortestTime { 
    static class Program { 
     /// <summary> 
     /// The main entry point for the application. 
     /// </summary> 
     [STAThread] 
     static void Main() { 
      try { 
       Application.EnableVisualStyles(); 
       Application.SetCompatibleTextRenderingDefault(false); 
       Application.Run(new T5ShortestTimeForm()); 
      } catch (Exception e) { 
       string errordir = Path.Combine(Application.StartupPath, "errorlog"); 
       string errorlog = Path.Combine(errordir, DateTime.Now.ToString("yyyyMMdd_HHmmss_fff") + ".txt"); 
       if (!Directory.Exists(errordir)) 
        Directory.CreateDirectory(errordir);     
       File.WriteAllText(errorlog, e.ToString());    
      } 
     } 
    } 
} 

Wie Sie sehen können , die Application wird in einen try-catch Block gesteckt und im catch Block ist das einzige, was es tut, eine Fehlerprotokolldatei zu erstellen.

Jetzt, so weit so gut. Meine Anwendung läuft gut und wenn ein Absturz auftritt, sollte der letzte Exception vom try-catch Block erfasst und in der Fehlerprotokolldatei gespeichert werden.

Allerdings, wie ich mein Programm für eine Weile ausführen, bekomme ich eine unbehandelte Ausnahme (null Referenz). Was mich überrascht ist, dass die Ausnahme keine Fehlerprotokolldatei erstellt.

Nun this post zeigt, dass es möglicherweise durch ThreadException oder HandleProcessCorruptedStateExceptions (die beiden upvoted Antworten) verursacht wird, aber mein Fall zeigt eine einfache null Ausnahme Referenz:

Problem signature: 
    Problem Event Name: CLR20r3 
    Problem Signature 01: T5ShortestTime.exe 
    Problem Signature 02: 2.8.3.1 
    Problem Signature 03: 5743e646 
    Problem Signature 04: T5ShortestTime 
    Problem Signature 05: 2.8.3.1 
    Problem Signature 06: 5743e646 
    Problem Signature 07: 182 
    Problem Signature 08: 1b 
    Problem Signature 09: System.NullReferenceException 
    OS Version: 6.3.9600.2.0.0.272.7 
    Locale ID: 1033 
    Additional Information 1: bb91 
    Additional Information 2: bb91a371df830534902ec94577ebb4a3 
    Additional Information 3: aba1 
    Additional Information 4: aba1ed7202d796d19b974eec93d89ec2 

Read our privacy statement online: 
    http://go.microsoft.com/fwlink/?linkid=280262 

If the online privacy statement is not available, please read our privacy statement offline: 
    C:\Windows\system32\en-US\erofflps.txt 

Warum das wäre?

+2

So erstellen Sie keinen globalen Ausnahme-Handler. Suchen Sie rechts im Bereich "Verknüpft" nach dieser Seite. Die angenommene Antwort sagt dir was zu tun ist. – jmcilhinney

+0

@jmcilhinney meinst du 'ThreadException'? – Ian

+0

In dem Beispiel gibt es // Starten Sie einen neuen Thread, getrennt von Windows Forms, der eine Ausnahme auslöst. 'private void button2_Click (Objekt Absender, System.EventArgs e) { ThreadStart newThreadStart = neue ThreadStart (newThread_Execute); newThread = neuer Thread (newThreadStart); newThread.Start(); } 'die absichtlich Ausnahme in einem neuen Thread behandeln. Aber kann das eine 'Null'-Referenz-Ausnahme (wie in meinem Fall) anstelle von 'ThreadException' erzeugen (soll dieser Typ sein - oder?)? – Ian

Antwort

5

die letzte Ausnahme sollte erfaßt werden durch den Try-Catch-Block

, was passieren wird nicht. Außer in einem Fall, wenn Sie Ihr Programm mit einem angehängten Debugger ausführen. Man hat sich also gewundert, dass es funktionieren würde, jeder beginnt sein Programm mit F5 für eine Weile.

Application.Run() hat einen Back-Stop in seinem Code, der Ereignisse auslöst, try/catch-em-all, die das Application.ThreadException-Ereignis auslösen, wenn ein Ereignishandler eine unbehandelte Ausnahme auslöst. Dieser Back-Stop ist wirklich, wirklich notwendig, vor allem auf der x64-Version von Windows 7. Very Bad Things happen, wenn es keine Ausnahme Handler gibt. Dieser Backstop ist jedoch nicht vorhanden, wenn Sie mit dem Debugger arbeiten, wodurch unbehandelte Ausnahmen zu schwer zu debuggen sind.

Also wenn Sie debuggen dann Ihre fangen Klausel wird ausgeführt. Unbehandelte Ausnahmen zu schwer zu debuggen. Wenn Sie ohne Debugger laufen, wird Ihre Fangklausel nicht ausführen und Ihr Programm wird abstürzen, genau wie Sie beschrieben haben. Unbehandelte Ausnahme zu schwierig zu debuggen.

Also tun Sie es nicht so. Wie Application.Run() unbehandelte Ausnahmen behandelt, wird mit der Application.SetUnhandledExceptionMode() -Methode konfiguriert. Ihnen wird diese Version besser gefallen:

Mit diesem Code können Sie unbehandelte Ausnahmen problemlos debuggen. Der Debugger.IsAttached-Test stellt sicher, dass der Debugger immer stoppt, wenn ein Event-Handler umfällt. Ohne einen Debugger deaktiviert es dann das Application.ThreadException-Ereignis (es ist ziemlich nutzlos) und bevorzugt alle Ausnahmen zu hören. Einschließlich der in Arbeiterfäden erhobenen.

Sie sollten dem Benutzer eine Warnung geben, damit das Fenster nicht einfach spurlos verschwindet. Ich wollte MessageBox empfehlen, habe aber bemerkt, dass this bug momentan wieder unter Windows 10 ist. Seufz.

+0

Danke für die Erklärung, das sollte die Antwort sein. Eine letzte Frage, Sie sagen, dass es besonders schlecht für Windows 7 x64 ist, verwende ich Windows 10 x64. Macht das einen Unterschied? In Ihrem Post haben Sie angegeben, "Update auf Windows 8 oder höher, sie haben dieses Problem wow64 gelöst." - Ich gehe davon aus, dass dies auch für Windows 10 gilt, stimmt das? – Ian

+0

Win10 hat dieses Problem nicht, es ist sehr spezifisch für Win7. –

+0

Ok, danke. Dann werde ich Frieden im Sinn haben ...;) Ich bemerke auch, dass das 'Dispose' immer noch * nach * der 'Ausnahme' genannt wird. Ich implementiere den 'SetUnhandledExceptionMode' in' ThrowException' und teste es mit 'throw new System.Exception()'. Überraschenderweise erzeugt das Programm * zwei * Fehlerprotokolldateien anstelle von * eins *. Die eine ist die 'System.Exception' und die andere ist die' Exception' im 'Dispose' - und die im' Dispose' genannte wird * später * erzeugt. Warum ist das so? Wird das eigentlich erwartet, dass das 'Dispose' noch * nach * einer fatalen Ausnahme aufgerufen wird? – Ian

2

ThreadException ist kein Ausnahmetyp wie (NullReferenceException). Es ist, dass:

Mit diesem Ereignis können Sie Ihre Windows-Anwendung sonst nicht behandelte Ausnahmen behandeln Formulare, die in Windows Forms auftreten Threads

Dies bedeutet, dass es Ausnahmen in Threads anders als der Haupt-Thread verarbeitet.

So müssen Sie abonnieren: AppDomain.CurrentDomain.UnhandledException auch, um die Ausnahmen im Hauptthread (Unabhängig von der Art der Ausnahme zum Beispiel NullReference, IndexOutOfRange, etc ..) zu handhaben.

2

Ok, am Ende implementiere ich Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException) als Beispiel von Hans Passant für VB.Net in this post.Hier habe ich meine eigenen Code + Fehlerprotokollierung für C#:

static void Main() { 
    Application.EnableVisualStyles(); 
    Application.SetCompatibleTextRenderingDefault(false); 
    if (!System.Diagnostics.Debugger.IsAttached) { 
     Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException); 
     AppDomain.CurrentDomain.UnhandledException += LogUnhandledExceptions; 
    } 
    Application.Run(new T5ShortestTimeForm()); 
} 

private static void LogUnhandledExceptions(object sender, UnhandledExceptionEventArgs e) { 
    Exception ex = (Exception)e.ExceptionObject; 
    string errordir = Path.Combine(Application.StartupPath, "errorlog"); 
    string errorlog = Path.Combine(errordir, DateTime.Now.ToString("yyyyMMdd_HHmmss_fff") + ".txt"); 
    if (!Directory.Exists(errordir)) 
     Directory.CreateDirectory(errordir); 
    File.WriteAllText(errorlog, ex.ToString()); 
    Environment.Exit(System.Runtime.InteropServices.Marshal.GetHRForException(ex)); 
} 

Auch scheint es, wie die Quelle der Verwirrung hier ist, dass es tatsächlich zweiExceptions vermehrt auftreten:

Die erste war jeder Ausnahme von der Anwendung selbst:

System.Exception: Exception of type 'System.Exception' was thrown. 
    at T5ShortestTime.T5ShortestTimeForm..ctor() in C:\Test.cs:line 45 
    at T5ShortestTime.Program.Main() in C:\Test.cs:line 19 
    at ... 

und die zweiten tritt während der Dispose der Form Komponenten, die eine weitere Ausnahme erzeugt, und es ist die null Referenz Ausnahme:

System.NullReferenceException: Object reference not set to an instance of an object. 
    at T5ShortestTime.T5ShortestTimeForm.Dispose(Boolean disposing) 
    at System.ComponentModel.Component.Finalize() 

Also, wenn ich die Ausnahme in meiner app zu testen, kommt der NullReferenceException die letzte, in der Dispose.

enter image description here

Ich schaffe es nur, dies zu erfassen, nachdem ich die UnhandledExceptionMode-ThrowException oben gesetzt.

Verwandte Themen