I can't catch exceptions in an Invoked delegate - c#

I have a delegate which is attached to an event in the Excel interop component. The goal is to update a winforms control with updated info from Excel. Since I'm changing Control properties I need to use Invoke:
public delegate void DataGridViewUpdate(object[,] data);
...
excel.InteractiveEdit( delegate(object[,] data) {
Invoke(new Common.DataGridViewUpdate(back_from_excel), new object[] { data });
});
...
private void back_from_excel(object[,] data) {
// datagridview updating code
// an exception is thrown here !
}
(This code is in the Form class that I'm updating so it's Invoking on this)
Basically my problem is that when an exception occurs in the back_from_excel(object[,] data) method, the debugger doesn't catch it. I know the delegate is running in the correct UI thread because I have no problems manipulating form controls.
Specifically what happens is that when back_from_excel hits an unhandled exception, it stops executing at that point. The rest of the application continues running and is responsive. The debugger doesn't pause. The output pane shows:
A first chance exception of type 'System.NullReferenceException' occurred in My Application.exe
A first chance exception of type 'System.NullReferenceException' occurred in System.Windows.Forms.dll
It doesn't give me any hints about which line caused the problem, just that it's somewhere in the .exe.
My question is: am I doing the Invoke thing right? It seems kind of strange to have delegate - Invoke - delegate chained together like that, but I do need to pass a delegate that Invokes a delegate. Is my problem in Visual Studio rather than in C#? If so how do I get the debugger re-attached to that UI thread?

A "first chance exception" indicates that an exception was thrown, but that it was caught at some point. Since you're passing a delegate to the InteractiveEdit method, that method can easily swallow any exceptions produced by the delegate.
By default, Visual Studio will only catch exceptions that don't get caught. If you want to catch all exceptions, regardless of whether they are caught, you need to configure Visual Studio to break on all exceptions. See this link for details on how to do this.

Related

SEHException when debugger is attached

This problem is rather complicated and I'm not sure about how to tackle it. I get the following exception when I start my application.
[FATAL] Unhandled exception. EXCEPTION OCCURRED:System.Runtime.InteropServices.SEHException External component has thrown an exception. Boolean CloseHandle(IntPtr)
[FATAL] Last Win32 error code: 00000006; Last HRESULT: 80070006
This only occurs when I run the debugger. If I start the application without a debugger, then it never throws an SEHException. As another fact, when I continue it does pop up again in Visual Studio and then exits the application.
I have now managed to narrow it down to this:
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
InternalDispatcher = new WpfDispatcher(dispatcher);
It does occur right after the constructor call of WpfDispatcher.
internal WpfDispatcher([NotNull] Dispatcher dispatcher)
{
_dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
}
I don't see why this happens, though. The WpfDispatcher-class is only a wrapper which allows me to use either WinForm or WPF to dispatch, depending on the selected compatibility mode.
And why is this only happening with an attached debugger? The code exists for a long time already and this started to happen only recently...
Is there any way to narrow it down? I just don't get why this happens.
PS: Just checked the threads when this happens and it seems like this exception originates from the GC Finalizer Thread:
Not Flagged > 4628 2 Worker Thread GC Finalizer Thread mscorlib.dll!Microsoft.Win32.SafeHandles.SafeFileHandle.ReleaseHandle Highest
PS2: Activating the native debugger, I get this (slightly) more detailed exception:
Exception thrown at 0xFE58917A in Lab.Wpf.exe: 0xC0000008: An invalid handle was specified.

Can I create a global exception handler in C# that lets the code continue running afterward?

In .NET, the default exception handler will let the user continue running the program. However, I'd like to have a global exception handler that saves the stack trace to an "errorlog.txt" file so the user can send it to me and doesn't have to remember to click "Details" and copy it out of the dialog (and remove all the useless crap about loaded assemblies and such). But when I do this, the code doesn't know how to continue, so all I can do is exit the app. Is there any way to have the best of both worlds? (Yes, I know what I'm asking for is essentially "On Error Resume Next" with logging, but I really think it would be useful!)
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
If you bind yourself to this event when the application starts, you should be able to catch any Unhandled Exception your application throws, and save it to a file. (Use the Exception object part of the UnhandledExceptionEventArgs. I do not believe it is possible to resume from where the error Occurred.
You can write a global exception handler method that you call in every catch block, which writes the stack trace where ever you want to save it. But you'd need to write try . . . catch blocks for every operation that needs them and call the exception handler in each.
You can also call that global exception handler method in the MyApplication.UnhandledException handler for all unhandled events. But when control gets to that method in that case, the program is not going to continue running.
In a Winform app you can attach an handler to the Application.ThreadException event (make sure you do before calling Application.Run()). This will get rid of the standard exception dialog (the one with the "details" button) and give you the power to display / log anything you want.
However, remember that this will work ONLY for exceptions thrown within the UI thread. Exceptions raised from a background thread won't be reachable from your handler. These can still be caught by AppDomain.UnhandledException handler, though.
in main constructor, put this and will do it globally:
AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) =>
{
MessageBox.Show(eventArgs.Exception.ToString());
};
(Note: as said in comments, this might not be thread-safe).
No that does not exist, exceptions are a flow control construct, so On Error Resume Next is not possible.
You could do your operation in a loop and on an exception, retry your logic.
KandallFrey is right however, you shouldn't use exceptions as flow control, use them only in exceptional cases.
I use My.Application.UnhandledException to open a dialog form where the user can save every information about the exception.
When the form is closed I call e.ExitApplication = False.
At my firm, I've built an exception handling framework which has served me well for 7 years now. Every assembly references the DLL, and every method in each assembly has a try-catch block. In the catch, I basically have to make one decision based on the question "where do I want my exception handling framework to intervene, i.e. to log the exception data externally and inform the user of the problem?". In most cases, the answer to this question is that I want it to intervene in cases where the method is called externally, e.g. if it's inside an event handler or other delegate. So here is some example code:
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Try
Method1()
Catch ex As Exception
BSExceptionHandler.ProcessException(BSExceptionHandler.GetBSException(ex, BSExceptionHandler.GetThisMethodName))
End Try
End Sub
Private Sub Method1()
Try
method2()
Catch ex As Exception
Throw BSExceptionHandler.GetBSException(ex, BSExceptionHandler.GetThisMethodName)
End Try
End Sub
Private Sub method2()
Try
Dim x As Integer = CInt("x") 'exception thrown here.
Catch ex As Exception
Throw BSExceptionHandler.GetBSException(ex, BSExceptionHandler.GetThisMethodName)
End Try
End Sub
When Throw BSExceptionHandler.GetBSException(ex, BSExceptionHandler.GetThisMethodName) is called for the first time in Method2(), the original exception is wrapped inside a BSException, and the original method name is stored as well (more on that later). Any subsequent calls to BSExceptionHandler.GetBSException(ex, BSExceptionHandler.GetThisMethodName), e.g. in Method1(), will recognize that the exception is already of type BSException and just throw that instead of re-wrapping it. Ultimately, it reaches the "top" of the call stack (not really the top, just the point at which I've decided I want to process the exception through my framework -- i.e. log it, inform the user, etc.) -- in this case, in Button1_Click -- and then BSExceptionHandler.ProcessException(BSExceptionHandler.GetBSException(ex, BSExceptionHandler.GetThisMethodName)) is called.
What my framework does in ProcessException is to determine the type of reporting configured on the system. This is defaulted to "simple", which means the user gets a very general and minimally-intrusive dialog box indicating a problem has occurred and instructing them to contact the IT department. However, there is an optional registry setting which will set the reporting type to either "verbose" or to "email". I use "verbose" on my development machine, because it includes all the exception info in the dialog box so I don't have to go look at the log. The "email" option is used on servers where I have applications running when there is no user logged on; in that case, the error information is emailed to the IT department to alert them of the issue.
The other thing that happens from here, regardless of the reporting type, is that the error information is recorded to the Windows event log. Here is an example:
SILENT: No
ROOT ASSEMBLY: C:\Users\roryap\AppData\Local\Temporary Projects\WindowsApplication1\bin\Debug\WindowsApplication1.exe
DESCRIPTION: BromsunExceptionHandling.BSException: Calling Method 'WindowsApplication1.Form1.method2()' produced 'System.FormatException' exception with message 'Conversion from string "x" to type 'Integer' is not valid.'.
CALLING METHOD: WindowsApplication1.Form1.method2()
STACK TRACE: at Microsoft.VisualBasic.CompilerServices.Conversions.ToInteger(String Value)
at WindowsApplication1.Form1.method2() in C:\Users\roryap\AppData\Local\Temporary Projects\WindowsApplication1\Form1.vb:line 32
CALL STACK: WindowsApplication1.Form1.method2()
WindowsApplication1.Form1.Method1()
WindowsApplication1.Form1.Button1_Click(sender As System.Object, e As System.EventArgs)
SOURCE: Microsoft.VisualBasic
TARGET SITE: Int32 ToInteger(System.String)
EXTRA INFO:
When the user reports the issue to IT, all IT has to do is check their event log to get the error info. Furthermore, the application does not exit; it continues running because it never allows the exception to bubble up outside of the point where you've chosen to process the exception with the handling framework. Once it's handled by the framework, it's done.
While there are a few downsides to this approach, I have found it to be an extremely robust system and it has saved me many many hours of blind troubleshooting over the years. I have created snippets so that all I have to do is create a try-catch block then type the snippet shortcut -- e.g. "pbs" or "tbs" -- into the catch-block and hit the tab key to populate the appropriate exception handling method. Therefore, it's quite painless to use this framework in every method. I've even modified my VS project templates to always reference and include the framework so I don't have to do that for every new project.
So, regarding the GetThisMethodName() function: this method uses System.Diagnostics.StackTrace, System.Diagnostics.StackFrame, and System.Reflection.MethodBase to figure out the name of the method where the original exception was wrapped inside the BSException.
For me works this solution:
In WebApiConfig.cs add:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Services.Replace(typeof(IExceptionLogger), new UnhandledExceptionLogger());
...
}
Create new file UnhandledExceptionLogger.cs:
public class UnhandledExceptionLogger : ExceptionLogger
{
public override void Log(ExceptionLoggerContext context)
{
File.AppendAllText("log.txt", context.Exception.ToString());
}
}

Evasive exceptions and "a function evaluation has timed out"

Background
In my utilities library (Shd.dll) I have a class called AsyncOperation. To put it simply, it's a base class for types that encapsulate a potentially long running operation, executes it on a background thread, and it supports pause/resume, cancellation and progress reporting. (It's like a BackgroundWorker, just knows more things.)
In the user code you can use it like this:
class MyOperation : AsyncOperation
{
public MyOperation() : base(null, AsyncOperationOptions.Cancelable | AsyncOperationOptions.Pausable) {}
protected override void RunOperation(AsyncOperationState operationState, object userState)
{
...
operationState.ThrowIfCancelled();
}
}
var op = new MyOperation();
op.Start();
...
op.Cancel();
operationState.ThrowIfCancelled() does exactly what its name suggests: if Cancel() was called earlier by another thread, it throws an internal exception (AsyncOperationCancelException), which is then handled by the AsyncOperation type, like this:
private void _DoExecute(object state)
{
// note that this method is already executed on the background thread
...
try
{
operationDelegate.DynamicInvoke(args); // this is where RunOperation() is called
}
catch(System.Reflection.TargetInvocationException tiex)
{
Exception inner = tiex.InnerException;
var cancelException = inner as AsyncOperationCancelException;
if(cancelException != null)
{
// the operation was cancelled
...
}
else
{
// the operation faulted
...
}
...
}
...
}
This works perfectly. Or so I thought for the past year, while I was using this in numerous scenarios.
The actual problem
I'm building a class that uses System.Net.WebClient to upload potentially large number of files via FTP. This class is built using the AsyncOperation base class as described above.
For accurate progress reports, I use WebClient.UploadFileAsync(), which complicates the code, but the relevant parts look like this:
private ManualResetEventSlim completedEvent = new ManualResetEventSlim(false);
private void WebClient_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
{
...
if (OperationState.IsCancellationRequested)
{
_GetCurrentWebClient().CancelAsync();
}
}
private void WebClient_UploadFileCompleted(object sender, UploadFileCompletedEventArgs e)
{
...
_UploadNextFile();
}
private void _UploadNextFile()
{
if (OperationState.IsCancellationRequested || ...)
{
this.completedEvent.Set();
return;
}
...
}
protected override void RunOperation(AsyncOperationState operationState, object userState)
{
...
_UploadNextFile();
this.completedEvent.Wait();
operationState.ThrowIfCancelled(); // crash
...
}
As you can see, I marked the line where the crash occurs. What exactly happens is that when execution hits that line (I put a break point right over it, so I know this is the exact line), Visual Studio 2010 freezes for about 15 seconds, and then the next thing I see is the source code of AsyncOperationState.ThrowIfCancelled():
public void ThrowIfCancelled()
{
if(IsCancellationRequested)
{
throw new AsyncOperationCancelException();
}
} // this is the line the debugger highlights: "An exception of type AsyncOperationCancelException' occured in Shd.dll but was unhandled by user code."
I tried putting breakpoints to where the exception should have been caught, but the execution never reaches that catch {} block.
The other weird this is that at the end it also writes the following: "Function evaluation disabled because a previous function evaluation timed out." I Googled this problem, and tried everything that was suggested (disabled implicit property evaluation, removed all breakpoints), but nothing helped so far.
Here are two screenshots that illustrate the problem:
http://dl.dropbox.com/u/17147594/vsd1.png
http://dl.dropbox.com/u/17147594/vsd2.png
I'm using .NET 4.0. Any help would be very much appreciated.
When the Visual Studio debugger is attached to an application, it gets notified whenever an exception is thrown, before the running code gets the chance to handle it. This is called a first-chance exception, and VS can be configured to break execution when a certain exception type is thrown.
You can specify debugger behavior for each exception type separately using the Exceptions window (Debug menu). By default, all exceptions have the "User-unhandled" checkbox checked, meaning that only unhandled exceptions will break execution. Setting the "Thrown" checkbox for a certain exception type forces VS to break execution even if the exception will be handled, but only for that exception type (not for derived types). If a handler exists, once you resume execution (by pressing F5), the exception will be caught normally.
I would guess that your custom exception was added to the list of exceptions in the Exceptions window (which you can check by using the Find button inside the window).
[Edit]
According to my tests, it also happens when DynamicInvoke is used in .NET 4, regardless of the Exceptions window setting. Yesterday I was using VS2008 and I couldn't reproduce it, but it does seem like odd behavior now.
This is the test I tried (sorry for the brief formatting, but it's fairly simple):
Action<int> a = i => { throw new ArgumentException(); };
// When the following code is executed, VS2010 debugger
// will break on the `ArgumentException` above
// but ONLY if the target is .NET 4 (3.5 and lower don't break)
try { a.DynamicInvoke(5); }
catch (Exception ex)
{ }
// this doesn't break
try { a.Invoke(5); }
catch (Exception ex)
{ }
// neither does this
try { a(5); }
catch (Exception ex)
{ }
My only guess is that exception handling done inside InvokeMethodFast (which is an InternalCall method) has somehow changed. DynamicInvoke code has changed between versions 4 and prior, but there is nothing which would indicate why VS2010 debugger is unable to see that there is an exception handler inside that method call.
“a function evaluation has timed out”
You don't have a real problem, this is a debugger artifact. It is triggered by the way the debugger evaluates watch expressions. When you start a .NET program with the debugger attached, the program will have a dedicated thread, solely for use by the debugger. Whenever the debugger needs to evaluate a watch expression, it uses that thread to execute the expression code. The result is then displayed in the watch window.
Which works very well and gives the debugger a lot of capabilities. Including calling a method in your program when a breakpoint is active. Rather necessary, a lot of object values you'd be interested in are exposed as properties. Which are implemented as methods in the generated code.
That debugger thread can however cause trouble. An obvious case is where you try to evaluate a property that takes a lock. If you break execution at a stage where that lock is owned by another thread then the debugger thread is going to hit a brick wall. It trundles for a while, notices that the debugger thread isn't completing, then gives up and displays "a function evaluation has timed out" as the watch value. It also remembers that it failed, any watches you try later will produce "Function evaluation disabled because a previous function evaluation timed out". Necessarily so, the debugger thread is still stuck in a rut.
Similar kind of problem in your code. The probable scenario there is that the thread you need to get the operation completed got suspended by the debugger break. The only decent advice to give here is to be careful with your watch expressions.
If your try catch logic is running on a different thread than the code that actually throws the exception, then the catch block will never execute.
Consider the following sample:
class Program
{
static void Main(string[] args)
{
try
{
Thread thread = new Thread((s) =>
{
throw new Exception("Blah");
});
thread.Start();
}
catch (Exception ex)
{
Console.WriteLine("Exception caught: {0}", ex);
}
Console.ReadKey();
}
}
The catch block of course does not execute since the exception was thrown on a different thread.
I'm suspecting that you could be experiencing something similar. If you want your catch block to execute, it must be on the same thread that the error is being thrown on.
Good luck!

C#: Why is my background worker thread signaling done when it isn't?

C#, using VS2010 and I've got something that makes no sense.
At startup my program needs to load several hundred k from text files. After ensuring the loading code was working fine I threw it in a background thread. So long as this is run from within the IDE everything's fine but when it's run standalone the thread says it's done when it isn't. This of course goes boom.
The trigger code:
BackgroundWorker Background = new BackgroundWorker();
Background.RunWorkerCompleted += new RunWorkerCompletedEventHandler(DatabaseLoaded);
Background.DoWork += new DoWorkEventHandler(delegate { Database.Load(); });
Background.RunWorkerAsync();
and the stuff that's going boom is in DatabaseLoaded().
I put some messageboxes to trace what's going on: The first and last lines of the Load() method and the first line of DatabaseLoaded().
In the IDE this triggers as I expect: Load() beginning, Load() done, DatabaseLoaded(). However, when run standalone I get Load() beginning, DatabaseLoaded() and then the unhandled exception box (the loader hasn't even gotten to build empty tables, let alone fill them.)
Am I nuts or is Microsoft?
RunWorkerCompleted will be invoked in case of an error (such as an unhandled exception in Database.Load()). Check the Error property of the RunWorkerCompletedEventArgs.
There's probably an exception thrown from Database.Load(). BackgroundWorker catches any unhandled exception before triggering the RunWorkerCompleted event. Check the RunWorkerCompletedEventArgs.Error property in DatabaseLoaded.

C# Time of finally execution

Take this code:
using System;
namespace OddThrow
{
class Program
{
static void Main(string[] args)
{
try
{
throw new Exception("Exception!");
}
finally
{
System.Threading.Thread.Sleep(2500);
Console.Error.WriteLine("I'm dying!");
System.Threading.Thread.Sleep(2500);
}
}
}
}
Which gives me this output:
Unhandled Exception: System.Exception: Exception!
at OddThrow.Program.Main(String[] args) in C:\Documents and Settings\username
\My Documents\Visual Studio 2008\Projects\OddThrow\OddThrow\Program.cs:line 14
I'm dying!
My question is: why does the unhandled exception text occur before the finally's? In my mind, the finally should be excuted as the stack unwinds, before we even know that this exception is unhandled. Note the calls to Sleep() - these occur after the unhandled exception is printed, as if it was doing this following:
Unhandled exception text/message
Finally blocks.
Terminate application
According to the C# standard, §8.9.5, this behaviour is wrong:
In the current function member, each try statement that encloses the throw point is examined. For each statement S, starting with the innermost try statement and ending with the outermost try statement, the following steps are evaluated:
If the try block of S encloses the throw point and if S has one or more catch clauses, the catch clauses are examined in order of appearance to locate a suitable handler for the exception. The first catch clause that specifies the exception type or a base type of the exception type is considered a match. A general catch clause (§8.10) is considered a match for any exception type. If a matching catch clause is located, the exception propagation is completed by transferring control to the block of that catch clause.
Otherwise, if the try block or a catch block of S encloses the throw point and if S has a finally block, control is transferred to the finally block. If the finally block throws another exception, processing of the current exception is terminated. Otherwise, when control reaches the end point of the finally block, processing of the current exception is continued.
If an exception handler was not located in the current function member invocation, the function member invocation is terminated. The steps above are then repeated for the caller of the function member with a throw point corresponding to the statement from which the function member was invoked.
If the exception processing terminates all function member invocations in the current thread, indicating that the thread has no handler for the exception, then the thread is itself terminated. The impact of such termination is implementation-defined.
Where am I going wrong? (I've got some custom console error messages, and this is in-the-way. Minor, just annoying, and making me question the language...)
The standard's statements about the order of execution are correct, and not inconsistent with what you are observing. The "Unhandled exception" message is allowed to appear at any point in the process, because it is just a message from the CLR, not actually an exception handler itself. The rules about order of execution only apply to code being executed inside the CLR, not to what the CLR itself does.
What you've actually done is expose an implementation detail, which is that unhandled exceptions are recognised by looking at a stack of which try{} blocks we are inside, rather than by actually exploring all the way to the root. Exceptions may or may not be handled by looking at this stack, but unhandled exceptions are recognised this way.
As you may be aware, if you put a top-level try{}catch{} in your main function, then you will see the behaviour you expect: each function's finally will be executed before checking the next frame up for a matching catch{}.
I could be way off base in the way I'm reading things...but you have a try finally block without a catch.
Juding by the description you posted, since the Exception is never caught, it bubbles up to the caller, works it's way up through the stack, is eventually unhandled, the call terminates, and then the finally block is called.
The output is actually from the default CLR exception handler. Exception Handlers occur before the finally block. After the finally block the CLR terminates because of the unhandled exception (it can't terminate before, as c# guarantees [1] that the finally clause is called).
So I'd say it's just standard behaviour, exception handling occurs before finally.
[1] guranteed during normal operation at least in absence of internal runtime errors or power outage
To add more into the mix, consider this:
using System;
namespace OddThrow
{
class Program
{
static void Main()
{
AppDomain.CurrentDomain.UnhandledException +=
delegate(object sender, UnhandledExceptionEventArgs e)
{
Console.Out.WriteLine("In AppDomain.UnhandledException");
};
try
{
throw new Exception("Exception!");
}
catch
{
Console.Error.WriteLine("In catch");
throw;
}
finally
{
Console.Error.WriteLine("In finally");
}
}
}
}
Which on my system (Norwegian) shows this:
[C:\..] ConsoleApplication5.exe
In catch
In AppDomain.UnhandledException
Ubehandlet unntak: System.Exception: Exception!
ved OddThrow.Program.Main() i ..\Program.cs:linje 24
In finally
Although not completely expected, the program does behave as it should. A finally block is not expected to be run first, it is only expected to be run always.
I adjusted your sample:
public static void Main()
{
try
{
Console.WriteLine("Before throwing");
throw new Exception("Exception!");
}
finally
{
Console.WriteLine("In finally");
Console.ReadLine();
}
}
In this case you will get the nasty unhandled exception dialog, but afterwards the console will output and wait for input, thus executing the finally, just not before windows itself catches the unhandled exception.
A try/finally without a catch will use the default handler which does exactly what you see. I use it all the time, e.g., in cases where handling the exception would be covering an error but there's still some cleanup you want to do.
Also remember that output to standard error and standard out are buffered.
The try-catch-finally blocks are working exactly as you expected if they are caught at some point. When I wrote a test program for this, and I use various nesting levels, the only case that it behaved in a way that matched what you described was when the exception was completely unhandled by code, and it bubbled out to the operating system.
Each time I ran it, the OS was what created the error message.
So the issue is not with C#, it is with the fact that an error that is unhandled by user code is no longer under the control of the application and therefore the runtime (I believe) cannot force an execution pattern on it.
If you had created a windows form application, and wrote all your messages to a textbox (then immediately flushing them) instead of writing directly to the console, you would not have seen that error message at all, because it was inserted into the error console by the calling application and not by your own code.
EDIT
I'll try to highlight the key part of that. Unhandled exceptions are out of your control, and you cannot determine when their exception handler will be executed. If you catch the exception at some point in your application, then the finally blocks will be executed before the lower-in-the-stack catch block.
To put a couple of answers together, what happens is that as soon as you have a Unhandled Exception a UnhandledExceptionEvent is raised on the AppDomain, then the code continues to execute (i.e. the finally). This is the MSDN Article on the event
Next try:
I believe this case isn't mentioned in the c# standard and I agree it seems to almost contradict it.
I believe the internal reason why this is happening is somewhat like this:
The CLR registers its default exception handler as SEH handler into FS:[0]
when you have more catches in your code, those handlers are added to the SEH chain. Alternatively, only the CLR handler is called during SEH handling and handles the CLR exception chain internally, I don't know which.
In your code when the exception is thrown, only the default handler is in the SEH chain. This handler is called before any stack unrolling begins.
The default exception handler knows that there are no exception handler registered on the stack. Therefore it calls all registered UnhandledException handler first, then prints its error message and marks the AppDomain for unloading.
Only after that stack unrolling even begins and finally blocks are called according the c# standard.
As i see it, the way the CLR handles unhandled exception isn't considered in the c# standard, only the order in which finallys are called during stack unrolling. This order is preserved. After that the "The impact of such termination is implementation-defined." clause takes effect.

Categories