wake-up-neo.net

VS2010 zeigt in einer WinForms-Anwendung unter einer 64-Bit-Version von Windows nicht behandelte Ausnahmemeldungen an

Wenn ich ein neues Projekt erstelle, bekomme ich bei nicht behandelten Ausnahmen ein merkwürdiges Verhalten. So kann ich das Problem reproduzieren:

1) Erstellen Sie eine neue Windows Forms-Anwendung (C #, .NET Framework 4, VS2010).

2) Fügen Sie dem Form1_Load-Handler den folgenden Code hinzu:

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

Ich würde erwarten, dass VS bricht und in der zweiten Zeile eine unbehandelte Ausnahmemeldung anzeigt. Was jedoch passiert ist, dass die dritte Zeile ohne Nachricht übersprungen wird und die Anwendung weiter läuft.

Ich habe dieses Problem nicht mit meinen bestehenden C # -Projekten. Ich denke also, dass meine neuen Projekte mit seltsamen Standardeinstellungen erstellt werden.

Hat jemand eine Idee was ist falsch an meinem Projekt ???

Ich habe versucht, die Kontrollkästchen in Debug-> Exceptions zu aktivieren. Aber dann wird die Ausführung unterbrochen, selbst wenn ich die Ausnahme in einem try-catch-Block behandele. was ich auch nicht will. Wenn ich mich recht erinnere, gab es in diesem Dialogfeld eine Spalte mit der Bezeichnung "unbehandelte Ausnahmen" oder ähnliches, die genau das tun würde, was ich möchte. In meinen Projekten gibt es jedoch nur eine Spalte ("geworfen").

75
Robert Hegner

Dies ist ein unangenehmes Problem, das durch die wow64-Emulationsebene verursacht wurde, die die Ausführung von 32-Bit-Code unter der 64-Bit-Version von Windows 7 ermöglicht. Es schluckt Ausnahmen im Code, der als Reaktion auf eine vom 64-Bit-Fenstermanager generierte Benachrichtigung ausgeführt wird wie das Ereignis Load. Verhindern, dass der Debugger sie sieht und eintritt. Dieses Problem ist schwer zu beheben, die Windows- und DevDiv-Gruppen bei Microsoft zeigen mit den Fingern hin und her. DevDiv kann nichts dagegen tun, Windows denkt, es sei das richtige und dokumentierte Verhalten, so geheimnisvoll es klingt.

Es ist sicherlich dokumentiert , aber gerade so gut wie niemand versteht die Konsequenzen oder hält es für vernünftiges Verhalten. Vor allem nicht, wenn die Fensterprozedur natürlich nicht sichtbar ist, wie in jedem Projekt, das Wrapper-Klassen zum Ausblenden der Fensterinstallationen verwendet. Wie jede Winforms-, WPF- oder MFC-App. Das zugrunde liegende Problem ist, dass Microsoft nicht herausfinden konnte, wie Ausnahmen von 32-Bit-Code an den 64-Bit-Code, der die Benachrichtigung ausgelöst hat, wieder an 32-Bit-Code übergeben werden, der versucht, die Ausnahme zu behandeln oder zu debuggen.

Es ist nur ein Problem mit einem angehängten Debugger, Ihr Code wird wie üblich ohne einen Bombenanschlag bombardiert. 

Projekt> Eigenschaften> Registerkarte Erstellen> Plattformziel = AnyCPU und deaktivieren Sie die Option 32-Bit bevorzugen. Ihre App wird jetzt als 64-Bit-Prozess ausgeführt, wodurch der wow64-Fehlermodus beseitigt wird. Bei einigen Konsequenzen werden Edit + Continue für VS-Versionen vor VS2013 deaktiviert und sind möglicherweise nicht immer möglich, wenn Sie von 32-Bit-Code abhängig sind.

Andere mögliche Problemumgehungen:

  • Debug> Ausnahmen> Aktivieren Sie das Kontrollkästchen Ausgelöst für CLR-Ausnahmen, um den Debugger zu zwingen, bei der Codezeile anzuhalten, die die Ausnahme auslöst.
  • Schreiben Sie try/catch in die Load-Ereignisbehandlungsroutine und failfast in den catch-Block.
  • Verwenden Sie Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException) in der Main()-Methode, damit der Ausnahmefall in der Nachrichtenschleife im Debug-Modus nicht deaktiviert wird. Dies macht es jedoch schwierig, alle nicht behandelten Ausnahmen zu debuggen, das Ereignis ThreadException ist ziemlich nutzlos.
  • Überlegen Sie, ob Ihr Code wirklich in die Load-Ereignisprozedur gehört. Es ist sehr selten, es zu benötigen, es ist jedoch in VB.NET und einem Swan-Song sehr beliebt, da es das Standardereignis ist und durch einen Doppelklick den Event-Handler trivial hinzugefügt wird. Sie brauchen really nur dann Load, wenn Sie nach der Anwendung der Benutzereinstellungen und der automatischen Skalierung an der tatsächlichen Fenstergröße interessiert sind. Alles andere gehört zum Konstruktor.
  • Update auf Windows 8 oder höher, dieses wow64-Problem wurde behoben.
119
Hans Passant

Nach meiner Erfahrung sehe ich dieses Problem nur, wenn ich einen angefügten Debugger ausgeführt habe. Die Anwendung verhält sich im Standalone-Modus gleich: Die Ausnahme wird nicht verschluckt.

Mit der Einführung von KB976038 können Sie das wieder so machen, wie Sie es erwarten würden. Ich habe den Hotfix nie installiert, daher gehe ich davon aus, dass er als Teil von Win7 SP1 kam.

Dies wurde in diesem Beitrag erwähnt:

Hier ist ein Code, der den Hotfix aktiviert:

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);
    }
}

Rufen Sie es zu Beginn Ihrer Bewerbung auf:

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

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

Ich habe (mit dem einfachen Beispiel unten) bestätigt, dass dies funktioniert, genau wie Sie es erwarten.

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

Was ich nicht verstehe, ist, warum es dem Debugger zuvor nicht möglich war, Kernel-Modus-Stack-Frames zu verarbeiten. Mit diesem Hotfix haben sie es irgendwie herausgefunden.

9

Wie Hans erwähnt, kompilieren Sie die Anwendung und führen Sie das Exe aus, ohne dass ein Debugger angeschlossen ist.

Für mich bestand das Problem darin, den Namen einer Class-Eigenschaft zu ändern, an die ein BindingSource-Steuerelement gebunden war. Laufen ohne die IDE Ich konnte den Fehler sehen:

Kann nicht an die Eigenschaft oder die Spalte SendWithoutProofReading in der .__ gebunden werden. Datenquelle. Parametername: dataMember

Problem behoben, durch das das BindingSource-Steuerelement an den aktualisierten Eigenschaftennamen gebunden wurde: enter image description here

3
Jeremy Thompson

Ich benutze WPF und bin auf das gleiche Problem gestoßen. Ich hatte schon Hans-1-3-Vorschläge ausprobiert, aber ich mochte sie nicht, weil Studio nicht dort aufhörte, wo der Fehler war (also konnte ich meine Variablen nicht sehen und sehen, was das Problem war). 

Also habe ich Hans 'vierten Vorschlag ausprobiert. Ich war überrascht, wie viel meines Codes ohne Probleme in den MainWindow-Konstruktor verschoben werden konnte. Ich bin mir nicht sicher, warum ich es mir zur Gewohnheit gemacht habe, so viel Logik in das Load-Ereignis zu integrieren, aber anscheinend kann viel davon im Ctor gemacht werden.

Dies hatte jedoch das gleiche Problem wie bei 1-3. Fehler, die beim ctor für WPF auftreten, werden in eine generische Xaml-Ausnahme eingebunden. (Eine innere Ausnahme hat den echten Fehler, aber ich wollte wieder, dass Studio an der eigentlichen Problemstelle ausfällt).

Was am Ende für mich gearbeitet hat, war, einen Thread zu erstellen, 50ms zu schlafen, zum Haupt-Thread zurückzukehren und das zu tun, was ich brauche ...

    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...

Auf diese Weise würde Studio genau dort brechen, wo eine nicht erfasste Ausnahme auftritt.

1
Gabe Halsmer

Eine einfache Problemumgehung könnte sein, wenn Sie Ihren Init-Code in ein anderes Ereignis wie Form_Shown verschieben können, das später als Form_Load aufgerufen wurde, und ein Flag zum Ausführen des Startcodes beim ersten angezeigten Formular verwenden:

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!

}
0
S.Serpooshan