简体   繁体   中英

WPF exception thrown in eventhandler is swallowed?

When I throw an exception in an eventhandler the exceptionhandler is not called?

Sample code of a stripped down example to start off with:

App.xaml

<Application x:Class="WpfApplication1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml"
             DispatcherUnhandledException="App_DispatcherUnhandledException" >
    <Application.Resources/>
</Application>

App.xaml.cs

using System.Windows;
using System.Windows.Threading;

namespace WpfApplication1
{
    public partial class App : Application
    {
        //This method is called when ButtonA is clicked, but not when ButtonB is
        //clicked (and a (random) file is selected ofcourse).
        void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
        {
            MessageBox.Show(e.Exception.Message, "An exception occurred", MessageBoxButton.OK, MessageBoxImage.Error);
            e.Handled = true;
        }
    }
}

MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button Content="Button A" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Click="ButtonA_Click"/>
        <Button Content="Button B" HorizontalAlignment="Left" Margin="90,10,0,0" VerticalAlignment="Top" Width="75" Click="ButtonB_Click"/>
    </Grid>
</Window>

MainWindow.xaml.cs

using Microsoft.Win32;
using System;
using System.Windows;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void ButtonA_Click(object sender, RoutedEventArgs e)
        {
            throw new Exception("Works!");
        }

        private void ButtonB_Click(object sender, RoutedEventArgs e)
        {
            var ofd = new OpenFileDialog();
            ofd.FileOk += (s, ce) => {
                throw new Exception("Does not work!?!?");
            };
            ofd.ShowDialog();
        }
    }
}

I already took a look at this question and this question but forcing either 32 or 64 bit or even "ANY CPU" doesn't work. Also, when setting any of these four (!) handlers up none of them get called when the exception is thrown in the event. Also this article didn't help.

I am running VS2012 (on Win8, x64), the project is using .Net Framework 4.5). What am I missing? Am I going crazy?

For clarity: I'm expecting a messagebox to be shown (which it does when I click ButtonA ), or, actually, the App_DispatcherUnhandledException method being called at all. But the method is not called (and thus the messagebox isn't shown) when I click ButtonB . The only difference between ButtonA and ButtonB is that the exception in " A " is not in an eventhandler and the exception in " B " is. And, ofcourse, I do select a file in the OpenFileDialog and click "Open" to select it. The debugger kicks in and points out the " Does not work!?!? " exception is thrown, then I continue execution and no messagebox is shown.

Also: I am pretty new to WPF, that might be part of the problem :P

Edit 1

For reference, here are two zipfiles demonstrating the exact problem:

  1. Simple (10Kb)
  2. Extended (10Kb)

On my computer, for both above projects, ButtonA causes a messagebox to be shown, ButtonB (after selecting a file) doesn't. Ever. Not even with or without turning on "debugging unmanaged code".

Edit 2

So, I ran the same code on another machine and found this out: On the other machine the debugger displays this:

其他机器上的例外情况

Note the Exception crossed a native/managed boundary title. When I try to resume execution (continue) the exception keeps popping up. My machine, when the debugger kicks in, shows:

在我的机器上例外

...and then, when I resume execution, the exception disappears in some kind of black hole; the main form is shown again and nothing happens.

This should have to do with this setting:

边界交叉异常设置

However, turning this option on/off doesn't help, even with restarting VS2012 and deleting temp files (and bin/obj directories from the project), restoring defaults etc .

So... I now know the exception, indeed, has to do with cross-boundaries between managed and unmanaged. Now I just need to figure out how to solve this problem so that I can throw the exception in the FileOk event (so that, eventually, my component can throw up in there too).

Ok, so I solved my problem.

Googling around, surfing SO etc. I eventually ended up here and here . It is now clear to me how the FileOk event is handled on another dispatcher and so the solution is simple:

private void ButtonB_Click(object sender, RoutedEventArgs e)
{
    var ofd = new OpenFileDialog();
    ofd.FileOk += (s, ce) => {
        this.Dispatcher.BeginInvoke((Action)(() =>
        {
            //We can throw:
            throw new Exception("Yay! This exception is now caught by the UnhandledException handler!");

            //or, alternatively, our component can do work that possibly throws:
            Component.DoFoo();
        }));
    };
    ofd.ShowDialog();
}

This ensures the exception is passed to the correct dispatcher and handled there. The App_DispatcherUnhandledException method is then correctly invoked and we can take it from there.

If you wire it up like this you will see that it is being handled
Still not sure why it eludes App_DispatcherUnhandledException

using System.ComponentModel;
//using Microsoft.Win32;


namespace UncaughtExceptionHandler
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            //AppDomain currentDomain = AppDomain.CurrentDomain;
            //currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
            InitializeComponent();
        }
        private void ButtonA_Click(object sender, RoutedEventArgs e)
        {
            throw new Exception("WTFA!?!?");
        }
        private void ButtonB_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog();
            ofd.FileOk += MyCanelEventHandler;
            //ofd.FileOk += (s, ce) =>
            //{
            //    //MessageBox.Show("Throwikng Exception WTF2!?!?");
            //    throw new Exception("WTF2!?!?");
            //};
            ofd.ShowDialog();
        }
        static void MyCanelEventHandler(Object sender, CancelEventArgs e)
        {
            MessageBox.Show("MyCanelEventHandler");
            throw new Exception("WTFCEH!?!?");
        }
    }
}

Debug 101 is get a call stack.
I got a call stack in 10 minutes.

OP made three invalid assumptions and even after a long discussion does not understand

  1. Exception was being swallowed
    It was not being swallowed it was just getting past his uncaught exception handler My code demonstrated that but OP did not follow
  2. Solution has no unmanned code
    Wrong again OpenFileDialog is unmanaged code
  3. Exception was being thrown from managed code
    Wrong again
    The exception was being thrown from the callback from unmanaged code

First line in the callback
Degbug 101 is get a call stack

UncaughtExceptionHandler.exe!UncaughtExceptionHandler.MainWindow.MyCanelEventHandler(object sender, System.ComponentModel.CancelEventArgs e) Line 55 C# comdlg32.dll!CFileOpenSave::_NotifyFileOkChangeCallback() + 0x18 bytes comctl32.dll!_DPA_EnumCallback@12() + 0x20 bytes
comdlg32.dll!CFileOpenSave::_NotifyFileOk() + 0x3d bytes
comdlg32.dll!CFileOpenSave::_CleanupDialog() + 0x46c2 bytes
comdlg32.dll!CFileOpenSave::_HandleOkAndClose() + 0x3a bytes
comdlg32.dll!CFileOpenSave::_OnCommandMessage() + 0xf432 bytes comdlg32.dll!CFileOpenSave::s_OpenSaveDlgProc() + 0x1f42 bytes user32.dll!_InternalCallWinProc@20() + 0x23 bytes
user32.dll!_UserCallDlgProcCheckWow@32() + 0xa9 bytes
user32.dll!_DefDlgProcWorker@20() + 0x7f bytes user32.dll!_DefDlgProcW@16() + 0x22 bytes

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM