4

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:

Exception on other machine

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:

Exception on my machine

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

Boundary crossed exception settings

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

Community
  • 1
  • 1
RobIII
  • 8,488
  • 2
  • 43
  • 93
  • You are sure the Exception is thrown? I use an event handler to throw an exception to test my App_DispatcherUnhandledException and it is caught. Try just straight up throwing an exception in the event handler. – paparazzo Oct 02 '13 at 15:32
  • I am running the exact code shown in the question; as you can see an exception is thrown in the `FileOk` event. – RobIII Oct 02 '13 at 15:34
  • I think we're having a misunderstanding. I **am** throwing an exception in the (`FileOK`(!)) eventhandler. The exception is thrown "in line 'one'" in the eventhandler (in `MainWindow.xaml.cs`). There is no other code in the (`FileOK`(!)) eventhandler. Next, I want the `App_DispatcherUnhandledException` eventhandler to be called since it is an unhandled exception. For demonstrational purposes I simply show a messagebox but ofcourse there has to be done a bit more eventually (like logging etc). The problem is the `App_DispatcherUnhandledException` is never called as (I think) it should be. – RobIII Oct 02 '13 at 15:46
  • Don't get me wrong; I do appreciate the feedback / comments. In the actual project the `FileOk` event is used to load a file using an external component; this component throws an exception when the file is 'invalid'. I want to be able to catch/log/handle that exception but my exceptionhandler is not called. When I click ButtonA (which invokes `ButtonA_Click`) the exceptionhandler is called and my messagebox is shown. When I click ButtonB (which invokes `ButtonB_Click`) nothing happens (apart from VS2012's debugger kicking in ofcourse, as it does for ButtonA as well). – RobIII Oct 02 '13 at 15:47
  • 3
    ...it seems @Blam has deleted one (or more?) comments so that is why I seem to be talking to myself here... – RobIII Oct 02 '13 at 15:57
  • My guess is that dll is unmanaged code and you are not catching exceptions from unmanaged code. Is debugging of unmanaged code turned on. I deleted comments cause you did not answer the question. Clearly I can see the code. In debug do you see the exception thrown? – paparazzo Oct 02 '13 at 15:57
  • It is managed code. But don't mind the external component or the debugging settings for (un)managed code, the **exact** example above doesn't work either!? – RobIII Oct 02 '13 at 15:59
  • Might [this](http://msdn.microsoft.com/en-us/library/system.windows.application.dispatcherunhandledexception.aspx) be relevant? _"DispatcherUnhandledException is raised by an Application for each exception that is unhandled by code **running on the main UI thread**."_. – CodeCaster Oct 02 '13 at 16:00
  • I think it is, but, as the question states, the other three (out of four(!)) methods for setting up exceptionhandlers do not work either? – RobIII Oct 02 '13 at 16:01
  • If it is managed code then why the reference to using Microsoft.Win32;? – paparazzo Oct 02 '13 at 16:01
  • Because of the OpenFileDialog... – RobIII Oct 02 '13 at 16:01
  • You are sure OpenFileDialog is managed code? – paparazzo Oct 02 '13 at 16:02
  • Does it matter? The exception is thrown in managed code? I have posted a zipfile for you to take a look at [here](http://www.filedropper.com/wpfapplication1). – RobIII Oct 02 '13 at 16:04
  • Rather than insist that is not the problem. Here is an idea. Try turning on debugging of unmanaged code. – paparazzo Oct 02 '13 at 16:08
  • It is on ([screenshot to prove it](http://i.imgur.com/hLsW9cT.png)). And apart from the debugger, why isn't the `App_DispatcherUnhandledException` not called then? What does that setting have to do with the method being called for ButtonA but not for ButtonB? Did you try [the project](http://www.filedropper.com/wpfapplication1) I posted? [Here is the project again](http://www.filedropper.com/showdownload.php/wpfapplication1_2) with all Exception handlers implemented I could find ([these four for example](http://stackoverflow.com/a/1472562/215042)) – RobIII Oct 02 '13 at 16:31
  • Again, to be clear: no messagebox is shown, ever, when clicking ButtonB and selecting a file. But a messagebox(es) is shown when clicking ButtonA. Also, all posted zipfiles (projects) may or may not have "debug unmanaged code" turned on, but switching it on/off in any of the projects doesn't change a thing (and still no messagebox(es) shown). – RobIII Oct 02 '13 at 16:32

2 Answers2

5

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.

Community
  • 1
  • 1
RobIII
  • 8,488
  • 2
  • 43
  • 93
-1

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

paparazzo
  • 44,497
  • 23
  • 105
  • 176
  • [The anonymous function I'm using could also be used to throw in a Messagebox](https://gist.github.com/anonymous/a9302883236eb354316d) like you did in `MyCanelEventHandler` (sic), but, indeed, the exception is not passed to `App_DispatcherUnhandledException` (nor do [any other methods of catching unhandled exceptions](http://www.filedropper.com/wpfapplication1_2) seem to work). Which is, exactly, my problem. You didn't change anything substantial in this answer (though, again, I appreciate your thinking with me). Also, I don't see your answer 'handling' the exception, only throwing it. – RobIII Oct 02 '13 at 17:37
  • Did you run it. (For me) there is an additional message box (compared to your solution) showing Exception("WTFCEH!?!?") as .NET runtime handled it as an unhandled exception. Does not fix it but it is a clue. It does address the title of where it got swallowed. – paparazzo Oct 02 '13 at 17:50
  • I did run it. I see the additional messagebox (did you [see my equivalent](https://gist.github.com/anonymous/a9302883236eb354316d)?). However, the exception is NOT caught*; you merely pointed the FileOk event to the `MyCanelEventHandler` (which has nothing to do with canceling anything, you might as well call it `Foo`). At that point there is no exception in sight (which is correct). The exception is thrown in the eventhandler (your `MyCanelEventHandler` method or my anonymous function). IRL my component would throw there. But the exception is never caught/"uncatchable" -> exactly my problem. – RobIII Oct 02 '13 at 18:08
  • Ergo: You didn't change anything substantial, except that you refactored the anonymous method to `MyCanelEventHandler` and used `System.Windows.Forms.OpenFileDialog` instead of `Microsoft.Win32.OpenFileDialog` (for which the `System.Windows.Forms`-one is merely a wrapper). See * in previous comment => Actually, at that point there is no exception in sight, it is thrown one line later... Also I apologize for posting this many comments, SO should allow longer comments :P – RobIII Oct 02 '13 at 18:11
  • Hmmm, as they say: '*assumptions are the mother of all ...*', I might have jumped the gun on stating the OpenFileDialog in `System.Windows.Forms` is a wrapper for the OpenFileDialog in `Microsoft.Win32` ([source](http://www.thomasclaudiushuber.com/blog/2008/04/12/vistas-savefiledialog-and-openfiledialog-in-wpf/)), but changing the one to the other doesn't help either; the exception is still not passed to the desired exceptionhandler. I am currently going thru the links provided [here](http://stackoverflow.com/a/12316177/215042) to see if anything in there points me in the right direction. – RobIII Oct 02 '13 at 18:21
  • Unfortunately these links seem to bother about theme/looks and not about other (possible) bugs. Tough luck on that one :( – RobIII Oct 02 '13 at 18:25
  • So it does not go to the "desired" uncaught event handler. There are several types of uncaught events. You are so focused on it needs to behave like you expect it to that it gets in the way of finding a a solution. Good luck. I am done. – paparazzo Oct 02 '13 at 21:12
  • `So it does not go to the "desired" uncaught event handler.` Are you serious? It goes to NONE of the exception handlers (I've shown 4 methods for Pete's sake). I don't know about you but I do like [DRY](http://riii.nl/umsgf) and not have logging, exception handling etc. sprinkled all over the place everywhere I use a OpenFileDialog. How am I supposed to handle unhandled exceptions in the FileOk event then? I can't even throw an own exception in that event since it will silently dissapear!? The application *should* crash instead of keep on running in an undefined state. – RobIII Oct 02 '13 at 22:04
  • `You are so focused on it needs to behave like you expect it to that it gets in the way of finding a a solution.` Oh no, I'm not. I'm focused on solving my problem in a sane way. I don't care if I need to catch the exception using another method of exception handling. As mentioned in the question and several times in the comments, [none of these methods](http://riii.nl/5dgb7) seem to work. I'm 99% sure I make a mistake somewhere. You, or anyone, show me where I go wrong and I'll gladly implement the *correct* way. But you seem to come up with nothing either (no sane way at least). – RobIII Oct 02 '13 at 22:16
  • No you have tried 1 uncaught expectation handler. There are other types of uncaught exceptions and I am done trying to help you. – paparazzo Oct 03 '13 at 12:07
  • I tried [**four**](http://www.filedropper.com/wpfapplication1_2) and have pointed that out several times and is also mentioned in my question. If you know of any more methods than those four: let me know! Maybe you should read more carefully and/or [follow the links](http://i.imgur.com/RKvE6Sn.png) I keep providing. And yes, even [in the first revision](http://stackoverflow.com/posts/19140593/revisions) of the question I mentioned these four methods and when I started adding zipfiles I also added one demonstrating those 4 methods. – RobIII Oct 03 '13 at 12:33
  • With [my solution](http://stackoverflow.com/a/19157224/215042) the exception no longer "eludes App_DispatcherUnhandledException" and I didn't have to stuff unrelated code in the FileOk event as you suggested. I also now **understand why** the exception was "eluding" the handler and as a result of that I managed to come up with a sane solution (executing code in the FileOk event on the correct dispatcher) instead of your workaround. I appreciate you trying to help me (and even that I pointed out several times!) but in the end you did nothing to help me towards a (decent) solution. I'm done too. – RobIII Oct 03 '13 at 12:50
  • You have one uncaught exception handler - App_DispatcherUnhandledException. – paparazzo Oct 03 '13 at 12:50
  • [**FOUR**](http://www.filedropper.com/wpfapplication1_2) dammit! `App_DispatcherUnhandledException`, `CurrentDomain_UnhandledException`, `TaskScheduler_UnobservedTaskException` and (commented out since I don't want to catch EVERY firstchance exception) `CurrentDomain_FirstChanceException`. I don't keep linking to [**this answer**](http://stackoverflow.com/a/1472562/215042) for nothing... – RobIII Oct 03 '13 at 12:53
  • Links are not shown IN your code - not clear to me what you tired. Note in comment 4 I guessed had to do with unmanaged code and you totally dismissed it. Now you have come back to you think it has to do the unmanaged code. – paparazzo Oct 03 '13 at 14:18
  • I did not only add links to zipfiles demonstrating all these methods, I also mentioned them in the question and many comments that I had tried all four methods and EACH time I linked to the corresponding questions/comments. I described perfectly that none of the methods worked as intended. Also: I didn't dismiss your suggestion, I said the exception thrown was a MANAGED exception (as you can see in the code where it says "throw...", that is CLEARLY in the "managed" side of code). What WASN'T clear was that the FileOk event was called by unmanaged code causing this problem. – RobIII Oct 03 '13 at 14:22
  • I'm quoting you [here](http://riii.nl/pksp5): "My guess is that dll is unmanaged code" -> **The DLL** (my component) is **managed** code, that is why I said the code was managed. Also, my demonstation code in the question AND both zipfiles contained no unmanaged code whatsoever so it was pretty safe to rule that out. It was [myself (**here**)](http://riii.nl/37f69) that came up with the possibility that the FileOk event might be raised from unmanaged code. – RobIII Oct 03 '13 at 14:24
  • Really comdlg32.dll is managed code? When I turn on debug unmanaged code this is the first line in the call stack comdlg32.dll!CFileOpenSave::_NotifyFileOkChangeCallback() + 0x18 byte. When I turn off debug unmanged code the call stack just says external. Really Win32 is managed code? How would be referring to YOUR dll when your posted solution is a WPF .exe? THAT dll is OpenFileDialog. – paparazzo Oct 03 '13 at 14:43
  • Who said anything about comdlg32.dll? And, as [my screenshot proved](http://riii.nl/k574t) I had "debug unmanaged code" on (and also see `Edit 2` in the question; there's another setting you need enabled). But hey, I'm pretty much done with you trying to convince yourself you were right. The "answer" you posted had exactly zero value, was way off-track and your comments weren't helpful either. Your constant whining and beating around the bush don't help either. You never, once, mentioned the dispatcher or even pointed in that general direction. I'll accept my own answer tomorrow. Bye. – RobIII Oct 03 '13 at 14:51
  • Exactly, I am been talking about comdlg32.dll all along and you have not been listening. You repeatedly state the solution has no unmanaged code and that is not correct. The call stack points to a callback from unmanaged code. – paparazzo Oct 03 '13 at 15:28
  • `I am been talking about comdlg32.dll all along`. WHAT? [**This**](http://riii.nl/ttsfk) comment is the first and only one mentioning comdlg32 (and then the responses to that comment). Search (CTRL+F that is) the page for it if you don't believe me. Stop beating around the bush and trying to convince me or others that you were correct. You don't even seem to grasp the difference between my anonymous function and your 'solution' (which is none, functionally speaking) nor understand exceptionhandling. Comment all you want; I'm definitely done. – RobIII Oct 03 '13 at 15:54
  • Read again. "If it is managed code then why the reference to using Microsoft.Win32;?" "You are sure OpenFileDialog is managed code?" OpenFileDialog is in comdlg32. I know what an anonymous function is. By factoring it that was I was able to get to the call stack. – paparazzo Oct 03 '13 at 16:01