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

77

Wenn ich ein neues Projekt erstelle, tritt bei nicht behandelten Ausnahmen ein seltsames Verhalten auf. 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_LoadHandler den folgenden Code hinzu :

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

Ich würde erwarten, dass VS in der zweiten Zeile unterbrochen wird und eine nicht behandelte Ausnahmemeldung anzeigt. Was jedoch passiert, ist, dass die dritte Zeile nur ohne Nachricht übersprungen wird und die Anwendung weiter ausgeführt wird.

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

Hat jemand eine Idee was mit meinem Projekt los ist ???

Ich habe versucht, die Kontrollkästchen unter Debug-> Ausnahmen zu aktivieren. Aber dann bricht die Ausführung ab, wenn ich die Ausnahme in einem try-catchBlock behandle. das ist auch nicht was ich will. Wenn ich mich richtig erinnere, gab es in diesem Dialogfeld eine Spalte mit dem Namen "nicht behandelte Ausnahmen" oder ähnliches, die genau das tun würde, was ich will. In meinen Projekten gibt es jedoch nur eine Spalte ("Thrown").

Robert Hegner
quelle
selbes Problem hier! Form Last fängt bereits Ausdrücke intern ..
Pedro77

Antworten:

124

Dies ist ein unangenehmes Problem, das durch die wow64-Emulationsschicht verursacht wird, mit der 32-Bit-Code unter der 64-Bit-Version von Windows 7 ausgeführt werden kann. Es werden Ausnahmen im Code verschluckt, der als Reaktion auf eine vom 64-Bit-Fenstermanager generierte Benachrichtigung ausgeführt wird , wie die LoadVeranstaltung. Verhindern, dass der Debugger ihn sieht und eingreift. 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 hält es für das richtige und dokumentierte Verhalten, so mysteriös das klingt.

Es ist sicherlich dokumentiert, aber fast 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 verwendet, um die Fensterinstallation auszublenden. Wie jede Winforms, WPF oder MFC App. Das zugrunde liegende Problem ist, dass Microsoft nicht herausfinden konnte, wie Ausnahmen vom 32-Bit-Code zurück zum 64-Bit-Code geleitet werden, der die Benachrichtigung zurück zum 32-Bit-Code ausgelöst hat, der versucht, die Ausnahme zu behandeln oder zu debuggen.

Es ist nur ein Problem mit einem angehängten Debugger, Ihr Code wird wie gewohnt ohne einen bombardieren.

Projekt> Eigenschaften> Registerkarte Erstellen> Plattformziel = AnyCPU und deaktivieren Sie Bevorzugt 32-Bit. Ihre App wird jetzt als 64-Bit-Prozess ausgeführt, wodurch der Wow64-Fehlermodus beseitigt wird. Einige Konsequenzen: Deaktivieren Sie Bearbeiten + Fortfahren für VS-Versionen vor VS2013 und ist 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, an der Codezeile anzuhalten, die die Ausnahme auslöst.
  • Schreiben Sie try / catch in die LoadEreignisbehandlungsroutine und failfast in den catch-Block.
  • Verwendung Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException)in dem Main()Verfahren so , dass der Ausnahme - Trap in der Nachrichtenschleife nicht im Debug - Modus deaktiviert. Dies macht es jedoch schwierig, alle nicht behandelten Ausnahmen zu debuggen. Das ThreadExceptionEreignis ist ziemlich nutzlos.
  • Überlegen Sie, ob Ihr Code wirklich in die LoadEreignisbehandlungsroutine gehört . Es wird sehr selten benötigt, ist jedoch in VB.NET und einem Schwanenlied sehr beliebt, da es sich um das Standardereignis handelt und ein Doppelklick den Ereignishandler trivial hinzufügt. Sie benötigen nur dann wirklich,Load wenn Sie an der tatsächlichen Fenstergröße interessiert sind, nachdem Benutzereinstellungen und automatische Skalierung angewendet wurden. Alles andere gehört in den Konstruktor.
  • Update auf Windows 8 oder höher, sie haben dieses wow64-Problem gelöst.
Hans Passant
quelle
6
Ja, es gibt einen Connect-Artikel dafür. Viele von ihnen. Dieser ist wahrscheinlich der beste: connect.microsoft.com/VisualStudio/feedback/details/357311/…
Hans Passant
5
Und hier ist eine, die darauf hindeutet, dass sie nicht viel Ahnung haben, was los ist: connect.microsoft.com/VisualStudio/feedback/details/589858/…
Hans Passant
1
Ich habe überprüft, ob derselbe Fehler in einer Winforms-Anwendung beim OnFormClosed-Ereignis vorliegt. Und ich kann es nicht lösen, indem ich das App-Ziel auch auf x86 ändere. Aber zumindest habe ich eine Problemerklärung.
Ferpega
1
Eine andere Problemumgehung scheint zu sein Application.ThreadException. Das Einstellen scheint zu helfen - die Ausnahmen werden in der IDE und vom Debugger ausgelöst.
Tanascius
7
Windows 8 do dieses Problem. Nur zu deiner Information.
ThunderGr
10

Nach meiner Erfahrung wird dieses Problem nur angezeigt, wenn ein Debugger angeschlossen ist. Die Anwendung verhält sich im Standalone-Modus genauso: Die Ausnahme wird nicht verschluckt.

Mit der Einführung von KB976038 können Sie diese Funktion wieder wie erwartet ausführen . Ich habe den Hotfix nie installiert, daher gehe ich davon aus, dass er Teil von Win7 SP1 ist.

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

Nennen Sie es zu Beginn Ihrer Bewerbung:

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

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

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

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

Was ich nicht verstehe, ist, warum es dem Debugger bisher unmöglich war, überkreuzende Kernel-Modus-Stack-Frames zu verarbeiten, aber mit diesem Hotfix haben sie es irgendwie herausgefunden.

Jonathon Reinhart
quelle
Set/GetProcessUserModeExceptionPolicysind immer noch nicht auf MSDN dokumentiert und Kernel32.dll von Windows 8 exportiert sie nicht.
Martin
Gibt es nicht eine Möglichkeit, dasselbe zu tun, indem Sie die Registrierung bearbeiten oder so?
ThunderGr
1
Ich habe sie gelesen Ich habe auch den Kommentar gelesen, dass der Windows 8-Kernel diese Methoden nicht exportiert. Ich laufe zufällig unter Windows 8. Ich habe nur gefragt, nur für den Fall.
ThunderGr
1
Wenn Sie den Hotfix anwenden, auf den Sie verweisen, können Sie das Problem lösen, indem Sie die Registrierung wie beschrieben bearbeiten, anstatt die Methoden zu verwenden. Ich erinnere mich, dass ich dieses Problem zuvor auf einem Win7-Computer auf diese Weise gelöst hatte. Leider können Sie das in Win 8 nicht tun.
ThunderGr
1
@ThunderGr Danke, dass du darauf hingewiesen hast. Ich denke, ich sollte nicht nach dem Schlafengehen kommentieren :-)
Jonathon Reinhart
3

Kompilieren Sie, wie Hans erwähnt, die Anwendung und führen Sie die Exe ohne angehängten Debugger aus.

Für mich bestand das Problem darin, einen Klasseneigenschaftsnamen zu ändern, an den ein BindingSource-Steuerelement gebunden war. Ohne IDE konnte ich den Fehler sehen:

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

Das Problem wurde behoben, indem das BindingSource-Steuerelement so repariert wurde, dass es an den aktualisierten Eigenschaftsnamen gebunden wurde: Geben Sie hier die Bildbeschreibung ein

Jeremy Thompson
quelle
1

Ich benutze WPF und bin auf dasselbe Problem gestoßen. Ich hatte bereits Hans 1-3-Vorschläge ausprobiert, mochte sie aber nicht, weil das Studio nicht dort anhielt, wo der Fehler lag (daher konnte ich meine Variablen nicht anzeigen und das Problem erkennen).

Also habe ich Hans '4. Vorschlag ausprobiert. Ich war überrascht, wie viel von meinem Code 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 erledigt werden.

Dies hatte jedoch das gleiche Problem wie 1-3. Fehler, die während des ctor für WPF auftreten, werden in eine generische Xaml-Ausnahme eingeschlossen. (Eine innere Ausnahme hat den wirklichen Fehler, aber ich wollte wieder, dass das Studio nur an der eigentlichen Problemstelle kaputt geht).

Am Ende arbeitete ich für mich, um einen Thread zu erstellen, 50 ms 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 das Studio genau dort brechen, wo eine nicht erfasste Ausnahme auftritt.

Gabe Halsmer
quelle
0

Eine einfache Problemumgehung könnte sein, wenn Sie Ihren Init-Code in ein anderes Ereignis verschieben können, wie es Form_Shownspäter aufgerufen wurde Form_Load, und ein Flag verwenden, um den Startcode in der ersten angezeigten Form auszuführen:

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!

}
S. Serpooshan
quelle