Frage VS2010 zeigt in einer WinForms-Anwendung in einer 64-Bit-Version von Windows keine unbehandelte Ausnahmebedingungsnachricht an


Wenn ich ein neues Projekt erstelle, bekomme ich ein merkwürdiges Verhalten für unbehandelte Ausnahmen. So kann ich das Problem reproduzieren:

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

2) füge den folgenden Code hinzu Form1_Load Handler:

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

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

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

Hat jemand eine Idee was mit meinem Projekt nicht stimmt ???

Ich habe versucht, die Kontrollkästchen in Debug-> Exceptions zu überprüfen. Aber dann bricht die Ausführung ab, selbst wenn ich die Ausnahme in einem Fall behandle try-catch Block; was ich auch nicht will. Wenn ich mich richtig erinnere, gab es in diesem Dialogfeld eine Spalte namens "unbehandelte Ausnahmen" oder etwas ähnliches, was genau das machen würde, was ich will. Aber in meinen Projekten gibt es nur eine Spalte ("Geworfen").


75
2018-02-08 14:00


Ursprung


Antworten:


Dies ist ein unangenehmes Problem, das durch die wow64-Emulationsschicht verursacht wird, die 32-Bit-Code auf der 64-Bit-Version von Windows 7 ausführen lässt. Es schluckt Ausnahmen im Code, der als Reaktion auf eine vom 64-Bit-Fenstermanager generierte Benachrichtigung ausgeführt wird , wie Load Veranstaltung. Verhindern, dass der Debugger sie erkennt und eingibt. Dieses Problem lässt sich nur schwer beheben, die Windows- und DevDiv-Gruppen bei Microsoft zeigen Finger vor und zurück. DevDiv kann nichts dagegen tun, Windows denkt, dass es das richtige und dokumentierte Verhalten ist, mysteriös wie das klingt.

Es ist sicherlich dokumentiert aber so ziemlich niemand versteht die Folgen oder hält es für vernünftiges Verhalten. Vor allem dann nicht, wenn die Fensterprozedur natürlich nicht sichtbar ist, wie in jedem Projekt, das Wrapper-Klassen verwendet, um die Fenster zu verbergen. Wie jede Winforms-, WPF- oder MFC-App. Zugrunde liegendes Problem ist, dass Microsoft nicht herausfinden konnte, wie Ausnahmen von 32-Bit-Code zurück zu dem 64-Bit-Code, der die Benachrichtigung ausgelöst hat, an 32-Bit-Code gesendet werden, der versucht, die Ausnahme zu behandeln oder zu debuggen.

Es ist nur ein Problem mit einem Debugger verbunden, dein Code wird wie üblich ohne einen bombardieren.

Projekt> Eigenschaften> Registerkarte Erstellen> Platform target = AnyCPU und deaktivieren Sie 32-Bit bevorzugen. Ihre App wird nun als 64-Bit-Prozess ausgeführt, wodurch der wow64-Fehlermodus beseitigt wird. Einige Konsequenzen, es deaktiviert Edit + Continue für VS-Versionen vor VS2013 und ist möglicherweise nicht immer möglich, wenn Sie eine Abhängigkeit von 32-Bit-Code haben.

Andere mögliche Problemumgehungen:

  • Debug> Exceptions> Aktivieren Sie das Kontrollkästchen "Thrown" für CLR-Exceptions, um den Debugger an der Codezeile zu stoppen, die die Exception ausgelöst hat.
  • Schreibe Versuch / Fang in der Load Event-Handler und Failfast im Catch-Block.
  • Benutzen Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException)in dem Main() Methode, damit die Ausnahme-Trap in der Nachrichtenschleife im Debug-Modus nicht deaktiviert wird. Dies macht jedoch alle unbehandelten Ausnahmen schwer zu debuggen, die ThreadException Das Ereignis ist ziemlich nutzlos.
  • Überlegen Sie, ob Ihr Code wirklich in die. Gehört Load Ereignishandler. Es ist sehr selten, es zu brauchen, aber es ist sehr populär in VB.NET und einem Schwanenlied, weil es das Standardereignis ist und ein Doppelklick trivialerweise den Ereignishandler hinzufügt. Du nur immer Ja wirklich brauchen Load Wenn Sie sich für die tatsächliche Fenstergröße interessieren, nachdem Benutzereinstellungen und Autoscaling angewendet wurden. Alles andere gehört in den Konstruktor.
  • Update auf Windows 8 oder höher, sie haben dieses Problem gelöst wow64.

117
2018-02-08 14:04



Meiner Erfahrung nach sehe ich dieses Problem nur, wenn ich mit einem angehängten Debugger laufe. Die Anwendung verhält sich im Standalone-Modus genauso: Die Ausnahme wird nicht verschluckt.

Mit der Einführung von KB976038, können Sie dies so ausführen, wie Sie es erwarten würden. Ich habe das Hotfix nie installiert, also nehme ich an, dass es als Teil von Win7 SP1 kam.

Dies wurde in diesem Post 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 an:

    [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 das so funktioniert, wie Sie es erwarten.

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

Also, was ich nicht verstehe, ist, warum es dem Debugger vorher unmöglich war, Kernel-Modus-Stack-Frames zu umgehen, aber mit diesem Hotfix haben sie es irgendwie herausgefunden.


9
2017-08-17 00:07



Wie Hans erwähnt, kompilieren Sie die Anwendung und führen Sie die Exe ohne einen angehängten Debugger aus.

Bei mir änderte das Problem den Namen einer Klasseneigenschaft, an die ein BindingSource-Steuerelement gebunden war. Ohne die IDE konnte ich den Fehler sehen:

Kann nicht an die Eigenschaft oder Spalte binden SendWithoutProofReading auf der   Datenquelle. Parametername: dataMember

Durch das Binden des BindingSource-Steuerelements zum Binden an den aktualisierten Eigenschaftsnamen wurde das Problem behoben: enter image description here


3
2018-03-25 23:49



Ich benutze WPF und lief auf dasselbe Problem. Ich hatte bereits Hans 1-3 Vorschläge ausprobiert, aber mochte sie nicht, weil Studio nicht an dem Punkt anhalten würde, wo der Fehler war (also konnte ich meine Variablen nicht sehen und sehen, was das Problem war).

Also habe ich den vierten Vorschlag von Hans 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 angewöhnt habe, so viel Logik in das Load-Ereignis zu bringen, aber anscheinend kann viel davon im ctor erledigt werden.

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

Was am Ende für mich funktionierte, war einen Thread zu erstellen, 50ms zu schlafen, zurück zum Haupt-Thread zu versenden und 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 abgefangene Ausnahme auftritt.


1
2018-02-28 00:01



Ein einfacher Work-Around könnte sein, wenn Sie Ihren Init-Code in ein anderes Event wie z Form_Shown die später anrief als Form_Loadund verwenden Sie eine Markierung, 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!

}

0
2018-01-07 12:19