I spent some time playing with Whidbey and noted some AppDomain unload/termination behavior that is not entirely intuitive. These apply to both the full .NET framework as well as .NET Compact Framework 2.0.

The documentation resides at http://msdn2.microsoft.com/en-us/library/03yhawcy.

Here's a run-through of the scenarios where unload fails and an AppDomain tear-down occurs.

1) Thread blocked in native code.

Say that a thread in my AppDomain is blocked in a PInvoke call. Say Main() is running in AD1 and we create AD2 from here and the main thread in AD2 does a PInvoke that never returns. At this point if I try to unload AD2 from AD1, Thread.Abort on the blocked thread in AD2 doesn't return back and so the 10-second timeout kicks in. At this point AD2 is forcefully torn-down, we get a CannotUnloadAppDomainException in AD1. At this point if Main() in AD1 swallows this exception and returns, the application is still alive, because it still has a live thread in AD2.

2) Thread in a Constrained Execution Region (CER)

A CER is a region of code where

   a) The runtime is constrained from throwing out of band exceptions that would prevent the code from executing in its entirety.

   b) User code is constrained from executing code that would result in the throwing of out of band exceptions.

This includes ThreadAbortException handlers, finally clauses, finalizers etc. The AppDomain tear down occurs just like in "1)".