dotnet clr:
Hi, Does Application.Exit() apply only to the AppDomain in which it is called? Is it the same as in WPF – a single Application object per AppDomain? Generally speaking, what is the relationship between an Application object and AppDomain objects? Regards,
One AppDomain per application. One or more AppDomains in a Process. WPF doesn't change this as WPF is still a .NET application and is still run by the CLR. Application.Exit will kill the application you are calling it on and therefore the AppDomain it is running in. [quoted text, click to view] "Sunny S" <SunnyS@discussions.microsoft.com> wrote in message news:4D3C4E0C-2C92-4015-9E3A-E03120928532@microsoft.com... > Hi, > > Does Application.Exit() apply only to the AppDomain in which it is called? > Is it the same as in WPF - a single Application object per AppDomain? > Generally speaking, what is the relationship between an Application object > and AppDomain objects? > > Regards, > > Sunny S.
[quoted text, click to view] Scott M. <smar@nospam.nospam> wrote: > One AppDomain per application. One or more AppDomains in a Process. > > WPF doesn't change this as WPF is still a .NET application and is still run > by the CLR. > > Application.Exit will kill the application you are calling it on and > therefore the AppDomain it is running in.
As far as I'm aware, Application.Exit just stops the UI message loop on the current thread. It doesn't try to do anything to the AppDomain. A quick experiment *appears* to show that you can't run a WinForms message loop on the same thread twice, but I could just be missing something. If you create a new thread for each one though, you can call Application.Exit in the same AppDomain multiple times perfectly reasonably: using System; using System.Drawing; using System.Windows.Forms; using System.Threading; public class Test { static void Main() { for (int i=0; i < 5; i++) { Thread t = new Thread(ShowUI); t.SetApartmentState(ApartmentState.STA); t.Start(i); t.Join(); } } static void ShowUI(object state) { Form form = new Form { Size = new Size(200, 200), Text = "Form #"+state }; Button b = new Button { Text = "Die!", Location = new Point(5, 5) }; b.Click += (s, e) => { Application.Exit(); }; form.Controls.Add(b); Application.Run(form); } } -- Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
[quoted text, click to view] "Sunny S" <SunnyS@discussions.microsoft.com> wrote in message news:4D3C4E0C-2C92-4015-9E3A-E03120928532@microsoft.com... > Hi, > > Does Application.Exit() apply only to the AppDomain in which it is called? > Is it the same as in WPF – a single Application object per AppDomain? > Generally speaking, what is the relationship between an Application object > and AppDomain objects? > > Regards, > > Sunny S.
Application.Exit() is a Forms API, WPF does not run a message loop so A.E makes no sense in WPF. Willy.
[quoted text, click to view] Willy Denoyette [MVP] wrote: > Application.Exit() is a Forms API,
That is true. [quoted text, click to view] > so A.E makes no sense in WPF.
That may be strictly true, but try this on for size: ---8<--- using System; using System.Windows; using System.Threading; using System.Runtime.InteropServices; using System.Windows.Controls; public class App { [DllImport("user32.dll")] static extern void PostQuitMessage(int nExitCode); static Button MakeQuitButton() { Button result = new Button(); result.Content = "Quit"; result.Click += (s,e) => PostQuitMessage(0); return result; } [STAThread] static void Main() { new Application().Run(new Window() { Content = MakeQuitButton() }); } } --->8--- [quoted text, click to view] > WPF does not run a message loop
This is empirically false: ---8<--- ntkrnlpa.exe!KiSwapContext+0x2f ntkrnlpa.exe!KiSwapThread+0x8a ntkrnlpa.exe!KeWaitForSingleObject+0x1c2 ntkrnlpa.exe!KiSuspendThread+0x18 ntkrnlpa.exe!KiDeliverApc+0x124 ntkrnlpa.exe!KiSwapThread+0xa8 ntkrnlpa.exe!KeWaitForSingleObject+0x1c2 win32k.sys!xxxSleepThread+0x192 win32k.sys!xxxRealInternalGetMessage+0x418 win32k.sys!NtUserGetMessage+0x27 ntkrnlpa.exe!KiFastCallEntry+0xfc ntdll.dll!KiFastSystemCallRet USER32.dll!NtUserGetMessage+0xc WindowsBase.ni.dll+0x5e623 WindowsBase.ni.dll!ResetValue+0xd WindowsBase.ni.dll!get_SourceProperty+0x1 WindowsBase.ni.dll!.ctor+0xe WindowsBase.ni.dll!ConvertToString+0x21 WindowsBase.ni.dll!ConvertToString+0x2 PresentationFramework.ni.dll!AlignContent+0x7b mscorwks.dll!CallDescrWorkerWithHandler+0xa3 mscorwks.dll!MethodDesc::CallDescr+0x19c mscorwks.dll!MethodDesc::CallTargetWorker+0x1f mscorwks.dll!MethodDescCallSite::Call_RetArgSlot+0x18 mscorwks.dll!ClassLoader::RunMain+0x263 mscorwks.dll!Assembly::ExecuteMainMethod+0xa6 mscorwks.dll!SystemDomain::ExecuteMainMethod+0x43f mscorwks.dll!ExecuteEXE+0x59 mscorwks.dll!_CorExeMain+0x15c mscoree.dll!_CorExeMain+0x2c KERNEL32.dll!BaseProcessStart+0x23 --->8--- NtUserGetMessage is there, clear as day. -- Barry --
[quoted text, click to view] "Barry Kelly" <barry.j.kelly@gmail.com> wrote in message news:n0ldv3ldnahq7cs5gubq2qqi3fp3fs99aq@4ax.com... > Willy Denoyette [MVP] wrote: > >> Application.Exit() is a Forms API, > > That is true. > >> so A.E makes no sense in WPF. > > That may be strictly true, but try this on for size: > > ---8<--- > using System; > using System.Windows; > using System.Threading; > using System.Runtime.InteropServices; > using System.Windows.Controls; > > public class App > { > [DllImport("user32.dll")] > static extern void PostQuitMessage(int nExitCode); > > static Button MakeQuitButton() > { > Button result = new Button(); > result.Content = "Quit"; > result.Click += (s,e) => PostQuitMessage(0); > return result; > } > > [STAThread] > static void Main() > { > new Application().Run(new Window() > { > Content = MakeQuitButton() > }); > } > } > --->8--- >
Well here you are calling PostQuitMessage which doesn't really do what it's supposed to do, also System.Windows.Forms.Application.Exit doesn't do what it has to do here (in a WPF based app.). Take a look at the messages using Spyxx.exe, you'll see that none of the API's are sending WM_QUIT message to your application. A.E does not terminate the UI thread whereas PostQuitMessage simply terminates the UI thread and as such the application. If you are looking for the equivalent of A.E in WPF, then take a look at Application.Shutdown, PostQuitMessage shouldn't be used at all. [quoted text, click to view] >> WPF does not run a message loop > > This is empirically false: >
Well, above is quite confusing, I should have been more explicit. Every Windows Application, no matter what the UI framework used , will have at least one top level window, this is also true for WPF based application. A minimal WPF application has at least one single Window (HWND) that is used as a *host* or wrap WPF. This top level Window, with it's associated message loop and WndProc, receives/handles all Windows messages for the application, WPF itself is not HWND based, Windows messages are translated (when appropriate) into CLR events that get routed to the the WPF Visuals. This top level HWND isn't exposed and accessible like it is in other frameworks like Windows.Forms, you can't override WndProc for instance,you shouldn't even assume such Window is present. Note also that the WPF core registers Windows messages that aren't know to Windows.Forms and vice-versa, that's why there is an WPF/Forms interop layer in the form of the HwndHost control. Willy.
[quoted text, click to view] Willy Denoyette [MVP] wrote: > "Barry Kelly" <barry.j.kelly@gmail.com> wrote: > > > Willy Denoyette [MVP] wrote: > > > >> Application.Exit() is a Forms API, > > > > That is true. > Well here you are calling PostQuitMessage which doesn't really do what it's > supposed to do
PostQuitMessage posts WM_QUIT to the current thread's message queue. This is no different in a WPF application than in any other Windows application. WM_QUIT causes GetMessage to return 0. WindowsBase.dll, System.Windows.Threading.Dispatcher::PushFrameImpl() contains the message loop which calls GetMessage. It exits the loop when GetMessage returns 0. It's a pretty simple stack from there on out to exit the application, provided you don't have extra code after the Application.Run() call. ---8<--- |> 0:000> !clrstack |> OS Thread Id: 0x1c68 (0) |> ESP EIP |> 0012f358 56d8e623 MS.Win32.UnsafeNativeMethods.GetMessageW(System.Windows.Interop.MSG ByRef, System.Runtime.InteropServices.HandleRef, Int32, Int32) |> 0012f36c 56d6197e System.Windows.Threading.Dispatcher.GetMessage(System.Windows.Interop.MSG ByRef, IntPtr, Int32, Int32) |> 0012f3b8 56d617e3 System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame) |> 0012f408 56d616c7 System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame) |> 0012f424 56d6162d System.Windows.Threading.Dispatcher.Run() |> 0012f430 5533dce0 System.Windows.Application.RunInternal(System.Windows.Window) |> 0012f45c 5533db15 System.Windows.Application.Run(System.Windows.Window) |> 0012f46c 00c5010d App.Main() --->8--- [quoted text, click to view] >, also System.Windows.Forms.Application.Exit doesn't do what > it has to do here (in a WPF based app.).
I never said it did. [quoted text, click to view] > Take a look at the messages using > Spyxx.exe, you'll see that none of the API's are sending WM_QUIT message to > your application.
Did you look at the window messages or the thread messages? WM_QUIT isn't normally sent to the windows, just the thread message queue. SpyXX on my system crashes when it tries to hook WPF thread messages, but WinDbg shows the thread message queue calls just fine (as indicated above). [quoted text, click to view] > PostQuitMessage simply terminates the UI thread and as such the application.
No it doesn't. It posts a message to the thread message queue and then returns to its caller immediately. This can be verified in the debugger, or simply by adding code to the appropriate places in a sample application: ---8<--- using System; using System.Windows; using System.Threading; using System.Runtime.InteropServices; using System.Windows.Controls; public class App { [DllImport("user32.dll")] static extern void PostQuitMessage(int nExitCode); static Button MakeQuitCButton() { Button result = new Button(); result.Content = "Quit"; result.Click += (s,e) => { Console.WriteLine("Before Quit message"); PostQuitMessage(0); Console.WriteLine("After Quit message"); }; return result; } [STAThread] static void Main() { Console.WriteLine("Before Application.Run"); new Application().Run(new Window() { Content = MakeQuitCButton() }); Console.WriteLine("After Application.Run"); } } --->8--- This shows the following on my machine, after I press the Quit button: ---8<--- Before Application.Run Before Quit message After Quit message After Application.Run --->8--- [quoted text, click to view] > If you are looking for the equivalent of A.E in WPF, then take a look at > Application.Shutdown, PostQuitMessage shouldn't be used at all.
I agree with you, one should use Application.Shutdown. You end up missing out a whole load of app teardown logic if you use PostQuitMessage. [quoted text, click to view] > >> WPF does not run a message loop > > > > This is empirically false: > > Well, above is quite confusing, I should have been more explicit. > Every Windows Application, no matter what the UI framework used , will have > at least one top level window, this is also true for WPF based application. > A minimal WPF application has at least one single Window (HWND) that is used > as a *host* or wrap WPF.
I never asserted that WPF was based on windows all the way down to each control - that would limit its functionality and performance quite severely, and you wouldn't get all the scene graph possibilities with transforms, composing in accelerated hardware etc, without undesirable clipping. Not even non-WPF applications use windows all the way down, including IE, Firefox, etc. See also e.g. TGraphicControl in Delphi (mouse-only input), etc. WPF is in no way new or original in this respect. You did, however, appear to assert that WPF applications don't have a message loop, which is nonsense. [quoted text, click to view] > This top level Window, with it's associated message loop and WndProc, > receives/handles all Windows messages for the application,
There will be at least as many HWNDs as there are separate top-level windows for that application on the desktop, each one with an appropriate WNDPROC. -- Barry --
[quoted text, click to view] "Barry Kelly" <barry.j.kelly@gmail.com> wrote in message news:4djkv39krr67nr7f3fjttfi86581in3gpm@4ax.com... > Willy Denoyette [MVP] wrote: > >> "Barry Kelly" <barry.j.kelly@gmail.com> wrote: >> >> > Willy Denoyette [MVP] wrote: >> > >> >> Application.Exit() is a Forms API, >> > >> > That is true. > >> Well here you are calling PostQuitMessage which doesn't really do what >> it's >> supposed to do > > PostQuitMessage posts WM_QUIT to the current thread's message queue. > This is no different in a WPF application than in any other Windows > application. WM_QUIT causes GetMessage to return 0. >
Well, It doesn't post a WM_QUIT message to the UI's thread queue when run on Vista (both RTM and SP1), of course it does post WM_QUIT when called in a Windows.Forms based application (or any non managed windows app.). [quoted text, click to view] > WindowsBase.dll, System.Windows.Threading.Dispatcher::PushFrameImpl() > contains the message loop which calls GetMessage. It exits the loop when > GetMessage returns 0. > > It's a pretty simple stack from there on out to exit the application, > provided you don't have extra code after the Application.Run() call. > > ---8<--- > |> 0:000> !clrstack > |> OS Thread Id: 0x1c68 (0) > |> ESP EIP > |> 0012f358 56d8e623 > MS.Win32.UnsafeNativeMethods.GetMessageW(System.Windows.Interop.MSG ByRef, > System.Runtime.InteropServices.HandleRef, Int32, Int32) > |> 0012f36c 56d6197e > System.Windows.Threading.Dispatcher.GetMessage(System.Windows.Interop.MSG > ByRef, IntPtr, Int32, Int32) > |> 0012f3b8 56d617e3 > System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame) > |> 0012f408 56d616c7 > System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame) > |> 0012f424 56d6162d System.Windows.Threading.Dispatcher.Run() > |> 0012f430 5533dce0 > System.Windows.Application.RunInternal(System.Windows.Window) > |> 0012f45c 5533db15 System.Windows.Application.Run(System.Windows.Window) > |> 0012f46c 00c5010d App.Main() > --->8--- > >>, also System.Windows.Forms.Application.Exit doesn't do what >> it has to do here (in a WPF based app.). > > I never said it did. > >> Take a look at the messages using >> Spyxx.exe, you'll see that none of the API's are sending WM_QUIT message >> to >> your application. > > Did you look at the window messages or the thread messages? WM_QUIT > isn't normally sent to the windows, just the thread message queue. >
I know that. [quoted text, click to view] > SpyXX on my system crashes when it tries to hook WPF thread messages, > but WinDbg shows the thread message queue calls just fine (as indicated > above). >
SpyXX has some troubles to enumerate "managed" processes when run on 32bit, and may fail to inject the hook into a managed process on Vista32. The only combination I found working reliably is: spyxx.exe 64-bit on Vista64 running with debug privileges. Beware that once SpyXX has failed to run, it will probably fail until after reboot. [quoted text, click to view] >> PostQuitMessage simply terminates the UI thread and as such the >> application. > > No it doesn't. >
It terminates the application without posting a WM_QUIT message on Vista, instead it sends a private registered message (amongs a bunch of others) to the dispatcher which finally terminates the session and returns from Run. [quoted text, click to view] > It posts a message to the thread message queue and then returns to its > caller immediately. >
It doesn't post a WM_QUIT message on Vista. This is different from Windows Forms which posts a WM_QUIT message (amongs other messages to the UI thread's queue). [quoted text, click to view] > This can be verified in the debugger, or simply by adding code to the > appropriate places in a sample application: > > ---8<--- > using System; > using System.Windows; > using System.Threading; > using System.Runtime.InteropServices; > using System.Windows.Controls; > > public class App > { > [DllImport("user32.dll")] > static extern void PostQuitMessage(int nExitCode); > > static Button MakeQuitCButton() > { > Button result = new Button(); > result.Content = "Quit"; > result.Click += (s,e) => > { > Console.WriteLine("Before Quit message"); > PostQuitMessage(0); > Console.WriteLine("After Quit message"); > }; > return result; > } > > [STAThread] > static void Main() > { > Console.WriteLine("Before Application.Run"); > new Application().Run(new Window() > { > Content = MakeQuitCButton() > }); > Console.WriteLine("After Application.Run"); > } > } > --->8--- > > This shows the following on my machine, after I press the Quit button: > > ---8<--- > Before Application.Run > Before Quit message > After Quit message > After Application.Run > --->8--- >
Oh, but I never said that the Click handler wasn't called! I only said that there was no WM_QUIT message posted, sure I should have mentioned "when run on VISTA!" Note also that the CLR stack looks somewhat different when run on Vista-64, the unmanaged stack is also quite different from what you get on Vista32 and XP. OS Thread Id: 0x1af4 (0) Child-SP RetAddr Call Site 000000000064e520 000006422da9f1c1 DomainBoundILStubClass.IL_STUB(System.Windows.Interop.MSG ByRef, Int32, Int32, Int32, Boolean ByRef) 000000000064e6e0 000006422da9efef System.Windows.Threading.Dispatcher.GetMessage(System.Windows.Interop.MSG ByRef, IntPtr, Int32, Int32) 000000000064e790 000006422da9eefe System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame) 000000000064e860 000006422a5cc061 System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame) 000000000064e8c0 000006422a5cbd4d System.Windows.Application.RunInternal(System.Windows.Window) 000000000064e930 0000064280150187 System.Windows.Application.Run(System.Windows.Window) 000000000064e980 000006427f67ba32 App.Main() Unmanaged stack.. 0:000> kb RetAddr : Args to Child : Call Site 00000000`772dd0ce : 0000988e`36afa07e 00000000`006c8bc0 00000000`00000000 00000000`00000000 : USER32!ZwUserGetMessage+0xa 000007fe`fde8589e : 00000000`006c8bc0 00000000`00000001 00000000`00000000 00000642`7f88d142 : USER32!GetMessageW+0x34 00000642`7f679b67 : 00000000`0051ebc0 00000000`006c8bc0 0000988e`37354ec0 00000642`7f3d6ac0 : MSCTF!CThreadInputMgr::GetMessageW+0x42 *** WARNING: Unable to verify checksum for C:\Windows\assembly\NativeImages_v2.0.50727_64\WindowsBase\3fd6671f329e84b22e22624974ade4a3\WindowsBase.ni.dll 00000642`2da9fc23 : 00000000`1b473cc0 00000000`006c8bc0 00000000`006c8bc0 00000642`2dd2a780 : mscorwks!DoCLRToCOMCall+0x177 00000642`2da9f1c1 : 00000000`0051f190 00000000`0051e9c1 00000000`0051eab8 00000000`0051ebc0 : WindowsBase_ni!GetLocalizedFailureCodeMessage+0xad
[quoted text, click to view] Willy Denoyette [MVP] wrote: > "Barry Kelly" <barry.j.kelly@gmail.com> wrote in message > news:4djkv39krr67nr7f3fjttfi86581in3gpm@4ax.com... >> Willy Denoyette [MVP] wrote: >> >>> "Barry Kelly" <barry.j.kelly@gmail.com> wrote: >>> >>>> Willy Denoyette [MVP] wrote: >>>> >>>>> Application.Exit() is a Forms API, >>>> >>>> That is true. >> >>> Well here you are calling PostQuitMessage which doesn't really do >>> what it's >>> supposed to do >> >> PostQuitMessage posts WM_QUIT to the current thread's message queue. >> This is no different in a WPF application than in any other Windows >> application. WM_QUIT causes GetMessage to return 0. >> > > Well, It doesn't post a WM_QUIT message to the UI's thread queue when > run on Vista (both RTM and SP1), of course it does post WM_QUIT when > called in a Windows.Forms based application (or any non managed > windows app.).
Barry has this one exactly right. PostQuitMessage is a Win32 function, it couldn't care less whether your app is WPF or WinForms or MFC or whatever. It posts WM_QUIT and returns. I don't know how you can get any clearer than this: http://msdn2.microsoft.com/en-us/library/ms644945(VS.85).aspx "The PostQuitMessage function posts a WM_QUIT message to the thread's message queue and returns immediately; the function simply indicates to the system that the thread is requesting to quit at some time in the future."
[quoted text, click to view] Willy Denoyette [MVP] wrote: > "Ben Voigt [C++ MVP]" <rbv@nospam.nospam> wrote in message > news:uOlihGYmIHA.484@TK2MSFTNGP06.phx.gbl... >> Willy Denoyette [MVP] wrote: >>> "Barry Kelly" <barry.j.kelly@gmail.com> wrote in message >>> news:4djkv39krr67nr7f3fjttfi86581in3gpm@4ax.com... >>>> Willy Denoyette [MVP] wrote: >>>> >>>>> "Barry Kelly" <barry.j.kelly@gmail.com> wrote: >>>>> >>>>>> Willy Denoyette [MVP] wrote: >>>>>> >>>>>>> Application.Exit() is a Forms API, >>>>>> >>>>>> That is true. >>>> >>>>> Well here you are calling PostQuitMessage which doesn't really do >>>>> what it's >>>>> supposed to do >>>> >>>> PostQuitMessage posts WM_QUIT to the current thread's message >>>> queue. This is no different in a WPF application than in any other >>>> Windows application. WM_QUIT causes GetMessage to return 0. >>>> >>> >>> Well, It doesn't post a WM_QUIT message to the UI's thread queue >>> when run on Vista (both RTM and SP1), of course it does post >>> WM_QUIT when called in a Windows.Forms based application (or any >>> non managed windows app.). >> >> Barry has this one exactly right. PostQuitMessage is a Win32 >> function, it couldn't care less whether your app is WPF or WinForms >> or MFC or whatever. It posts WM_QUIT and returns. >> >> I don't know how you can get any clearer than this: >> >> http://msdn2.microsoft.com/en-us/library/ms644945(VS.85).aspx >> "The PostQuitMessage function posts a WM_QUIT message to the thread's >> message queue and returns immediately; the function simply indicates >> to the system that the thread is requesting to quit at some time in >> the future." >> > > > The docs are clear, but I'm afraid they are missing some additional > remarks when run on Vista (don't know what happens on XP SP2 and SP3). > Please don't point to the docs to prove I'm wrong, use some debugging > tools and correct me if you notice the *documented* behavior. > Running SpyXX [1] doesn't reveal any WM_QUIT message for a WPF enabled > application (say the sample posted by Barry), it does (as expected) > when called from any other type of application (managed Forms, and > native MFC and Win32). > If you can't get Spyxx (from VS2008) to work for you, or if you don't > fully trust what SPxx reveals(like I do), you can always run the app > in the debugger (say Windbg), set a breakpoint on GetMessageW and > inspect the MSG struct returned (there are quite a lot of them) when > you call the API, you won't see any WM_QUIT message (at least I > don't). You really should break on PostMessage and PostThreadMessage (A and W variants), because it's entirely possible that PostQuitMessage did exactly what the documentation described, but the .NET method (Application.Shutdown I guess) triggered ending the message loop so GetMessage was never called. For example: put this code in any of the application types where you do see WM_QUIT: PostQuitMessage(); ExitProcess(); Clearly the behavior of PostQuitMessage hasn't changed, yet you'll never see WM_QUIT returned by GetMessage. [quoted text, click to view] > > > Willy. > > On Vista32 SP1 and Vista64 SP1 and WS2008, all running the same v3.5 > Framework bits.
[quoted text, click to view] "Ben Voigt [C++ MVP]" <rbv@nospam.nospam> wrote in message news:uOlihGYmIHA.484@TK2MSFTNGP06.phx.gbl... > Willy Denoyette [MVP] wrote: >> "Barry Kelly" <barry.j.kelly@gmail.com> wrote in message >> news:4djkv39krr67nr7f3fjttfi86581in3gpm@4ax.com... >>> Willy Denoyette [MVP] wrote: >>> >>>> "Barry Kelly" <barry.j.kelly@gmail.com> wrote: >>>> >>>>> Willy Denoyette [MVP] wrote: >>>>> >>>>>> Application.Exit() is a Forms API, >>>>> >>>>> That is true. >>> >>>> Well here you are calling PostQuitMessage which doesn't really do >>>> what it's >>>> supposed to do >>> >>> PostQuitMessage posts WM_QUIT to the current thread's message queue. >>> This is no different in a WPF application than in any other Windows >>> application. WM_QUIT causes GetMessage to return 0. >>> >> >> Well, It doesn't post a WM_QUIT message to the UI's thread queue when >> run on Vista (both RTM and SP1), of course it does post WM_QUIT when >> called in a Windows.Forms based application (or any non managed >> windows app.). > > Barry has this one exactly right. PostQuitMessage is a Win32 function, it > couldn't care less whether your app is WPF or WinForms or MFC or whatever. > It posts WM_QUIT and returns. > > I don't know how you can get any clearer than this: > > http://msdn2.microsoft.com/en-us/library/ms644945(VS.85).aspx > "The PostQuitMessage function posts a WM_QUIT message to the thread's > message queue and returns immediately; the function simply indicates to > the system that the thread is requesting to quit at some time in the > future." > The docs are clear, but I'm afraid they are missing some additional remarks when run on Vista (don't know what happens on XP SP2 and SP3). Please don't point to the docs to prove I'm wrong, use some debugging tools and correct me if you notice the *documented* behavior. Running SpyXX [1] doesn't reveal any WM_QUIT message for a WPF enabled application (say the sample posted by Barry), it does (as expected) when called from any other type of application (managed Forms, and native MFC and Win32). If you can't get Spyxx (from VS2008) to work for you, or if you don't fully trust what SPxx reveals(like I do), you can always run the app in the debugger (say Windbg), set a breakpoint on GetMessageW and inspect the MSG struct returned (there are quite a lot of them) when you call the API, you won't see any WM_QUIT message (at least I don't). Willy. On Vista32 SP1 and Vista64 SP1 and WS2008, all running the same v3.5 Framework bits.
[quoted text, click to view] "Ben Voigt [C++ MVP]" <rbv@nospam.nospam> wrote in message news:eaRqYocmIHA.1164@TK2MSFTNGP02.phx.gbl... > Willy Denoyette [MVP] wrote: >> "Ben Voigt [C++ MVP]" <rbv@nospam.nospam> wrote in message >> news:uOlihGYmIHA.484@TK2MSFTNGP06.phx.gbl... >>> Willy Denoyette [MVP] wrote: >>>> "Barry Kelly" <barry.j.kelly@gmail.com> wrote in message >>>> news:4djkv39krr67nr7f3fjttfi86581in3gpm@4ax.com... >>>>> Willy Denoyette [MVP] wrote: >>>>> >>>>>> "Barry Kelly" <barry.j.kelly@gmail.com> wrote: >>>>>> >>>>>>> Willy Denoyette [MVP] wrote: >>>>>>> >>>>>>>> Application.Exit() is a Forms API, >>>>>>> >>>>>>> That is true. >>>>> >>>>>> Well here you are calling PostQuitMessage which doesn't really do >>>>>> what it's >>>>>> supposed to do >>>>> >>>>> PostQuitMessage posts WM_QUIT to the current thread's message >>>>> queue. This is no different in a WPF application than in any other >>>>> Windows application. WM_QUIT causes GetMessage to return 0. >>>>> >>>> >>>> Well, It doesn't post a WM_QUIT message to the UI's thread queue >>>> when run on Vista (both RTM and SP1), of course it does post >>>> WM_QUIT when called in a Windows.Forms based application (or any >>>> non managed windows app.). >>> >>> Barry has this one exactly right. PostQuitMessage is a Win32 >>> function, it couldn't care less whether your app is WPF or WinForms >>> or MFC or whatever. It posts WM_QUIT and returns. >>> >>> I don't know how you can get any clearer than this: >>> >>> http://msdn2.microsoft.com/en-us/library/ms644945(VS.85).aspx >>> "The PostQuitMessage function posts a WM_QUIT message to the thread's >>> message queue and returns immediately; the function simply indicates >>> to the system that the thread is requesting to quit at some time in >>> the future." >>> >> >> >> The docs are clear, but I'm afraid they are missing some additional >> remarks when run on Vista (don't know what happens on XP SP2 and SP3). >> Please don't point to the docs to prove I'm wrong, use some debugging >> tools and correct me if you notice the *documented* behavior. >> Running SpyXX [1] doesn't reveal any WM_QUIT message for a WPF enabled >> application (say the sample posted by Barry), it does (as expected) >> when called from any other type of application (managed Forms, and >> native MFC and Win32). >> If you can't get Spyxx (from VS2008) to work for you, or if you don't >> fully trust what SPxx reveals(like I do), you can always run the app >> in the debugger (say Windbg), set a breakpoint on GetMessageW and >> inspect the MSG struct returned (there are quite a lot of them) when >> you call the API, you won't see any WM_QUIT message (at least I >> don't). > > You really should break on PostMessage and PostThreadMessage (A and W > variants), because it's entirely possible that PostQuitMessage did exactly > what the documentation described, but the .NET method > (Application.Shutdown I guess) triggered ending the message loop so > GetMessage was never called. > > For example: put this code in any of the application types where you do > see WM_QUIT: > > PostQuitMessage(); > ExitProcess(); > > Clearly the behavior of PostQuitMessage hasn't changed, yet you'll never > > see > WM_QUIT returned by GetMessage. > Hmmm, how do you expect see a WM_QUIT when you terminate the process directly after PostQuitMessage ? Also, I did break on PostQuitMessage (there are no A or W variants) don't worry, your assumption that PQM has not changed may be valid for the "user" portion, which is a small thunk [1] that calls into the kernel (syscall), that's the place where messages are constructed, and that's where things got changed dramatically in Vista, that's the portion that knows about "Avalon" and the DWM. That's the portion that needs to coordinate with the DWM composition, that's the part that handles PQM when called from a WPF application running on Vista with DWM (glass) enabled. [1] 0:000> uf user32!postquitmessage USER32!PostQuitMessage: 00000000`76e90918 4863c9 movsxd rcx,ecx 00000000`76e9091b ba34000000 mov edx,34h 00000000`76e90920 e94bcc0000 jmp USER32!ZwUserCallOneParam (00000000`76e9d570) USER32!ZwUserCallOneParam: 00000000`76e9d570 4c8bd1 mov r10,rcx 00000000`76e9d573 b802100000 mov eax,1002h 00000000`76e9d578 0f05 syscall 00000000`76e9d57a c3 ret Once again, the message loop is not terminated as a result of a WM_QUIT message put in the message queue, none of the GetMessage calls return 0 once PQM has been called, that means none of them have "picked-up" a WM_QUIT. It's the DWM that stops the message loop, which doesn't mean that PQM is the right API to call from WPF (it isn't). You should start to convince yourself, I can't post more the debugger output here. Start a kernel debugger session and look what PQM does in the kernel, do the same thing when calling Application.Shutdow, look how thing got coordinated with the DWM (using ALPC's ) over you will understand what I mean here. Don't be surprised when you got blocked by DRM in kernel debugger, don't be surprised to see some COM interaction between the processes and don't be surprised to find a some undocumented Windows messages in the application queue. Willy.
Keep hitting wrong buttons, sorry... Gentlemen, thank you very much for an interesting discussion, from which I learned a lot, but I feel I had to be more specific. 1. Let’s say I’ve started a SimpleWinForm application. I presume that means starting a message loop. 2. From within that application I create an AppDomain in which I create a new thread on which I call Application.Run(new SomeOtherWinForm()). See, for example, Jon Skeet’s code above except that the code should be running on a dedicated thread in a separate AppDomain. Microsoft documentation says that Application.Exit() method ‘Informs ALL message pumps that they must terminate, and then closes all application windows after the messages have been processed’. From the above I would conclude that upon calling Application.Exit() both SomeOtherWinForm and SimpleWinForm should close and the whole thing should terminate. Experiments show that this is not the case – only SomeOtherWinForm closes. Again, Microsoft documentation for System.Windows.Application (not System.Windows.Forms.Application!) says that there is only one instance of Application object per AppDomain. It looks as if the same relationship is true for System.Windows.Forms.Application objects and AppDomains, because this would explain the above behaviour, but I wasn’t sure. SS [quoted text, click to view] "Sunny S" wrote: > Hi, > > Does Application.Exit() apply only to the AppDomain in which it is called? > Is it the same as in WPF – a single Application object per AppDomain? > Generally speaking, what is the relationship between an Application object > and AppDomain objects? > > Regards, >
Willy, Thanks very much for a quick reply. Can you see any immediate problems I am going to run into if I use Windows.Forms in multiple AppDomains? SS [quoted text, click to view] "Willy Denoyette [MVP]" wrote: > "Sunny S" <sunny.s@newsgroup.nospam> wrote in message > news:DB96CD9F-4274-4ED9-9028-D0ECBB323A36@microsoft.com... > > Keep hitting wrong buttons, sorry... > > > > Gentlemen, thank you very much for an interesting discussion, from which I > > learned a lot, but I feel I had to be more specific. > > > > 1. Let’s say I’ve started a SimpleWinForm application. I presume that > > means > > starting a message loop. > > > > 2. From within that application I create an AppDomain in which I create a > > new thread on which I call Application.Run(new SomeOtherWinForm()). See, > > for > > example, Jon Skeet’s code above except that the code should be running on > > a > > dedicated thread in a separate AppDomain. > > > > Microsoft documentation says that Application.Exit() method ‘Informs ALL > > message pumps that they must terminate, and then closes all application > > windows after the messages have been processed’. > > > > From the above I would conclude that upon calling Application.Exit() both > > SomeOtherWinForm and SimpleWinForm should close and the whole thing should > > terminate. Experiments show that this is not the case – only > > SomeOtherWinForm > > closes. > > > > Again, Microsoft documentation for System.Windows.Application (not > > System.Windows.Forms.Application!) says that there is only one instance of > > Application object per AppDomain. It looks as if the same relationship is > > true for System.Windows.Forms.Application objects and AppDomains, because > > this would explain the above behaviour, but I wasn’t sure. > > > > SS > > When the documentation says "all running message loops on all threads and > closes all windows of the application." it really should say in the callers > AppDomain (AD) and it's owning AD's. > That means, that if you call Application.Exit in a child AD , only the child > AD windows will be affected. If, however you cal A.E from the parent AD , > then also the child AD windows will be affected. > Note also that Windows.Forms was not designed to be run from within multiple > domains in a single process. > > > Willy. > > > >
Hi Jon, I modified your example code to create two threads and to start message loops on each of them as follows: static void Main() { { Thread t = new Thread(ShowUI1); t.SetApartmentState(ApartmentState.STA); t.Start(); Thread t2 = new Thread(ShowUI2); t2.SetApartmentState(ApartmentState.STA); t2.Start(); } } static void ShowUI1() { Form form = new Form { Size = new Size(200, 200), Text = "Form UI1" }; Button b = new Button { Text = "Die!", Location = new Point(5, 5) }; b.Click += (s, e) => { Application.Exit(); }; form.Controls.Add(b); Application.Run(form); } static void ShowUI2() { Form form = new Form { Size = new Size(200, 200), Text = "Form UI2" }; Button b = new Button { Text = "Die!", Location = new Point(5, 5) }; b.Click += (s, e) => { Application.Exit(); }; form.Controls.Add(b); Application.Run(form); } If you run this code, you’ll see that when you kill one of the Forms the other dies too and the application shuts down. Apparently, calling Application.Exit() on one thread kills the other thread's UI as well. This is in line with Microsoft documentation saying that Application.Exit() method ‘Informs all message pumps that they must terminate, and then closes all application windows after the messages have been processed’. Things seem to be different if you create these two threads in different AppDomains like so: public class Test: MarshalByRefObject { static void Main() { { AppDomain ad1 = AppDomain.CreateDomain("AD1"); Test t1 = (Test) ad1.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, "Test"); t1.StartUI1(); AppDomain ad2 = AppDomain.CreateDomain("AD2"); Test t2 = (Test)ad2.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, "Test"); t2.StartUI2(); } } public void StartUI1() { Thread t = new Thread(ShowUI1); t.SetApartmentState(ApartmentState.STA); t.Start(); } public void StartUI2() { Thread t = new Thread(ShowUI2); t.SetApartmentState(ApartmentState.STA); t.Start(); } public void ShowUI1() { Form form = new Form { Size = new Size(200, 200), Text = "Form UI1" }; Button b = new Button { Text = "Die!", Location = new Point(5, 5) }; b.Click += (s, e) => { Application.Exit(); }; form.Controls.Add(b); Application.Run(form); } public void ShowUI2() { Form form = new Form { Size = new Size(200, 200), Text = "Form UI2" }; Button b = new Button { Text = "Die!", Location = new Point(5, 5) }; b.Click += (s, e) => { Application.Exit(); }; form.Controls.Add(b); Application.Run(form); } } In this case killing one of the Forms doesn’t kill the other one and this is not in line with the documentation. That’s, essentially, what my question was about. Thanks for replying, it’s nice to hear from you again:) SS
Jon, I’ve just done some more tests. My understanding of Willy Denoyette’s explanation (see at the bottom of this thread) was that Application.Exit() kills the message pumps in the current Appdomain and its ‘child’ AppDomains. To verify this I further modified the code with AppDomains so that one of the threads creates yet another ‘child’ AppDomain and starts yet another message loop in it. This test showed that my understanding was incorrect. All three message loops in those AppDomains are independent in the sense that killing one of them doesn’t kill the others.
Hi Willy, Again, thanks for the reply. You might be interested in reading (and, perhaps, commenting on:)) my reply to Jon Skeet above. I've done some experiments to clarify dependecies between message pumps running in different
[quoted text, click to view] "Sunny S" <sunny.s@newsgroup.nospam> wrote in message news:DB96CD9F-4274-4ED9-9028-D0ECBB323A36@microsoft.com... > Keep hitting wrong buttons, sorry... > > Gentlemen, thank you very much for an interesting discussion, from which I > learned a lot, but I feel I had to be more specific. > > 1. Let’s say I’ve started a SimpleWinForm application. I presume that > means > starting a message loop. > > 2. From within that application I create an AppDomain in which I create a > new thread on which I call Application.Run(new SomeOtherWinForm()). See, > for > example, Jon Skeet’s code above except that the code should be running on > a > dedicated thread in a separate AppDomain. > > Microsoft documentation says that Application.Exit() method ‘Informs ALL > message pumps that they must terminate, and then closes all application > windows after the messages have been processed’. > > From the above I would conclude that upon calling Application.Exit() both > SomeOtherWinForm and SimpleWinForm should close and the whole thing should > terminate. Experiments show that this is not the case – only > SomeOtherWinForm > closes. > > Again, Microsoft documentation for System.Windows.Application (not > System.Windows.Forms.Application!) says that there is only one instance of > Application object per AppDomain. It looks as if the same relationship is > true for System.Windows.Forms.Application objects and AppDomains, because > this would explain the above behaviour, but I wasn’t sure. > > SS
When the documentation says "all running message loops on all threads and closes all windows of the application." it really should say in the callers AppDomain (AD) and it's owning AD's. That means, that if you call Application.Exit in a child AD , only the child AD windows will be affected. If, however you cal A.E from the parent AD , then also the child AD windows will be affected. Note also that Windows.Forms was not designed to be run from within multiple domains in a single process. Willy.
[quoted text, click to view] "Sunny S" <sunny.s@newsgroup.nospam> wrote in message news:67A7646B-4AA9-4B6E-89F6-A4C8CBE9B522@microsoft.com... > Jon, > > I’ve just done some more tests. My understanding of Willy Denoyette’s > explanation (see at the bottom of this thread) was that Application.Exit() > kills the message pumps in the current Appdomain and its ‘child’ > AppDomains. > > To verify this I further modified the code with AppDomains so that one of > the threads creates yet another ‘child’ AppDomain and starts yet another > message loop in it. This test showed that my understanding was incorrect. > All > three message loops in those AppDomains are independent in the sense that > killing one of them doesn’t kill the others. >
I know this is quite confusing, but I'm not sure why you consider this "not inline with the docs". Note that the docs talks about applications, and stopping all message pumps in the application, it doesn't talk about threads running other AD's. In your last sample you are creating separate AD/thread pairs *and* you create a new application (Application.Run(..) in each of the domains/threads, calling A.E in one of the AD/threads only stops the (single) message pumps in this application, which is inline with the docs, right? Now, say the from AD1/thread1 you create another thread, and you create a window and run a message pump in this thread. That means, you have AD1/thread1 and thread2, and two separate message pumps. Calling A.E from one of these threads will stop all (2) pumps, which is inline with the docs, right? And, say you have a AD/thread that runs an application (Application.Run(...)], and this thread creates another AD that shows a form. Here you have two AD's, one *Application* and only one thread that pumps the message queue of both the main form and the other AD's form. When you call A.E from the second form code, you will simply unload the second AD and it's form, but you won't stop the message pump. Calling A.E from the main form will stop the message pump and close all forms tear down the AD's for the whole application, which is again inline with the doc's. Willy.
Hi Willi, I agree that 'not in line with the docs' was, perhaps, an overstatement:). What I actually wanted to say is that as far as I am concerned the documentation was not clear about the scope of the Application object and the relationship between Application, A.E method and AppDomains. For example, you say ' ... you create a new application (Application.Run(..) in each of the domains/threads ...' Define 'application'. Surely it's not a new Application object or is it? BTW, the documentation just says that calling A.R 'Begins running a standard application message loop on the current thread'. I am not trying to be argumentative, I'm just trying to understand what's going on. Let's take one of your scenarios: "From AD1/thread1 you create another thread, and you create a window and run a message pump in this thread." Why can't I use the same logic as above and say that by 'creating a window and running a message pump' on a new thread (through Application.Run(Form), I presume) I create a new application? Let's futher modify this scenario so that the second thread is created, as above, from AD1/thread1, but in a separate AppDomain (AD2), so that AD2 is a 'child' of AD1. In this case, calling A.E on either of the threads doesn't stop the other (I did test it:). You see, this is the sort of questions I was trying to clarify for myself and I found your comments quite helpful, thank you. [quoted text, click to view] "Willy Denoyette [MVP]" wrote: > "Sunny S" <sunny.s@newsgroup.nospam> wrote in message > news:67A7646B-4AA9-4B6E-89F6-A4C8CBE9B522@microsoft.com... > > Jon, > > > > I’ve just done some more tests. My understanding of Willy Denoyette’s > > explanation (see at the bottom of this thread) was that Application.Exit() > > kills the message pumps in the current Appdomain and its ‘child’ > > AppDomains. > > > > To verify this I further modified the code with AppDomains so that one of > > the threads creates yet another ‘child’ AppDomain and starts yet another > > message loop in it. This test showed that my understanding was incorrect. > > All > > three message loops in those AppDomains are independent in the sense that > > killing one of them doesn’t kill the others. > > > > > > I know this is quite confusing, but I'm not sure why you consider this "not > inline with the docs". > Note that the docs talks about applications, and stopping all message pumps > in the application, it doesn't talk about threads running other AD's. > > In your last sample you are creating separate AD/thread pairs *and* you > create a new application (Application.Run(..) in each of the > domains/threads, calling A.E in one of the AD/threads only stops the > (single) message pumps in this application, which is inline with the docs, > right? > > Now, say the from AD1/thread1 you create another thread, and you create a > window and run a message pump in this thread. That means, you have > AD1/thread1 and thread2, and two separate message pumps. Calling A.E from > one of these threads will stop all (2) pumps, which is inline with the docs, > right? > > And, say you have a AD/thread that runs an application > (Application.Run(...)], and this thread creates another AD that shows a > form. Here you have two AD's, one *Application* and only one thread that > pumps the message queue of both the main form and the other AD's form. When > you call A.E from the second form code, you will simply unload the second AD > and it's form, but you won't stop the message pump. Calling A.E from the > main form will stop the message pump and close all forms tear down the AD's > for the whole application, which is again inline with the doc's. > > Willy. > >
Hi Willi, We are almost there:):):) To recap, we have: AD1/T1 -> calls A.R(Form1); creates T2 -> creates AD2 -> call A.R(Form2). Here calling A.E on T2 does close Form2, but doesn't close Form1. The reverse is also true: calling A.E on T1 closes Form1, but doesn't close Form2. I accept your explanation that A.R(Form2) creates a new 'application' that is independent of the application running Form1, so exiting one of them doesn't affect the other. Why then things are different for the following scenario: AD1/T1 -> calls A.R(Form1); creates T2 -> calls A.R(Form2), where we don't create a separate AppDomain for T2? As you pointed out erlier, closing either Form1 or Form2 closes the other Form and shuts down the application. Apparently, calling A.R on a different thread in a separate AppDomain is somehow different from calling it in the same AppDomain. Would it be correct to assume that the scope of Application.Exit() is limited to the current AppDomain only? [quoted text, click to view] "Willy Denoyette [MVP]" wrote: > See inline. > > > WIlly. > > "Sunny S" <sunny.s@newsgroup.nospam> wrote in message > news:5740021E-1C8F-422F-AF74-E45DE21AF7B6@microsoft.com... > > Hi Willi, > > > > I agree that 'not in line with the docs' was, perhaps, an overstatement:). > > What I actually wanted to say is that as far as I am concerned the > > documentation was not clear about the scope of the Application object and > > the > > relationship between Application, A.E method and AppDomains. > > > Well, as said before, Windows.Forms was designed to be used from the > "default domain" only and not from muttiple AD's running in the same > process. The reason is quite simple, the underlying Win32 Windows > architecture doesn't know about AD's, it only knows about processes and > threads and one thread which is important in the "Windows" context is the UI > thread. It's the thread that must run a message pump in order to retrieve > Window messages from the application and from the System. > > > > For example, you say ' ... you create a new application > > (Application.Run(..) > > in each of the domains/threads ...' Define 'application'. Surely it's not > > a > > new Application object or is it? BTW, the documentation just says that > > calling A.R 'Begins running a standard application message loop on the > > current thread'. I am not trying to be argumentative, I'm just trying to > > understand what's going on. > > > > A.R creates an ApplicationContext (and a static Application instance ), it's > the ApplicationContext who actually defines *the* application in terms of > the MSDN docs. > > > > Let's take one of your scenarios: "From AD1/thread1 you create another > > thread, and you create a window and run a message pump in this thread." > > Why > > can't I use the same logic as above and say that by 'creating a window and > > running a message pump' on a new thread (through Application.Run(Form), I > > presume) I create a new application? > > You create a new Application in terms of the docs, that's right. > > > > > Let's futher modify this scenario so that the second thread is created, as > > above, from AD1/thread1, but in a separate AppDomain (AD2), so that AD2 is > > a > > 'child' of AD1. In this case, calling A.E on either of the threads doesn't > > stop the other (I did test it:). > > > Ok so you have: > AD1/T1 -> creates T2 -> creates AD2 -> call A.R which creates a new > ApplicationContext (a new application as per msdn) which start a pump on T2. > Calling A.E in T2 will stop the pump on T2, destroy the ApplicationContext > and as such stop this application. > The fact that you do this is a new AD is irrelevant, an AD != an > "application". > > > > > You see, this is the sort of questions I was trying to clarify for myself > > and I found your comments quite helpful, thank you. > > > > "Willy Denoyette [MVP]" wrote: > > > >> "Sunny S" <sunny.s@newsgroup.nospam> wrote in message > >> news:67A7646B-4AA9-4B6E-89F6-A4C8CBE9B522@microsoft.com... > >> > Jon, > >> > > >> > I’ve just done some more tests. My understanding of Willy Denoyette’s > >> > explanation (see at the bottom of this thread) was that > >> > Application.Exit() > >> > kills the message pumps in the current Appdomain and its ‘child’ > >> > AppDomains. > >> > > >> > To verify this I further modified the code with AppDomains so that one > >> > of > >> > the threads creates yet another ‘child’ AppDomain and starts yet > >> > another > >> > message loop in it. This test showed that my understanding was > >> > incorrect. > >> > All > >> > three message loops in those AppDomains are independent in the sense > >> > that > >> > killing one of them doesn’t kill the others. > >> > > >> > >> > >> > >> I know this is quite confusing, but I'm not sure why you consider this > >> "not > >> inline with the docs". > >> Note that the docs talks about applications, and stopping all message > >> pumps > >> in the application, it doesn't talk about threads running other AD's. > >> > >> In your last sample you are creating separate AD/thread pairs *and* you > >> create a new application (Application.Run(..) in each of the > >> domains/threads, calling A.E in one of the AD/threads only stops the > >> (single) message pumps in this application, which is inline with the > >> docs, > >> right? > >> > >> Now, say the from AD1/thread1 you create another thread, and you create a > >> window and run a message pump in this thread. That means, you have > >> AD1/thread1 and thread2, and two separate message pumps. Calling A.E from > >> one of these threads will stop all (2) pumps, which is inline with the > >> docs, > >> right? > >> > >> And, say you have a AD/thread that runs an application > >> (Application.Run(...)], and this thread creates another AD that shows a > >> form. Here you have two AD's, one *Application* and only one thread that > >> pumps the message queue of both the main form and the other AD's form. > >> When > >> you call A.E from the second form code, you will simply unload the second > >> AD > >> and it's form, but you won't stop the message pump. Calling A.E from the > >> main form will stop the message pump and close all forms tear down the > >> AD's > >> for the whole application, which is again inline with the doc's. > >> > >> Willy. > >> > >> > >> > >
Hi Willy, Well, what can I say? A big thank you, again:) As for your question why am I so interested in A.E -- at this point it's already, perhaps, a bit of an obsession. My original interest was triggered by attempts to find a way to rudely shut down an application that is running in an AppDomain that was created by a host. The app is supposed to be written by a third party, should be considered as an untrusted one and peppered with bugs (that is, in addition to our own bugs:)). If that app enters a tight loop, then I couldn’t see a way to quit it gracefully other than calling A.E. Unloading an AppDomain, even if that was possible with a foreground thread still running in it, wouldn’t be a good option since we would loose state information. So A.E seemed to be a reasonable option. So I started thinking of what would happen if I inject a thread into that problematic AppDomain and call A.E on it, and then I came up with some other scenarios most of which included A.E in one way or another. Obviously, I needed to understand what are possible ramifications, etc. BTW, where and how can I learn what happens ‘under the hood’? I tried Reflector, but the most interesting (and messy?) parts of functionality are hidden in internal methods which Reflector wouldn’t ‘reflect’:)). I don't want to be too intrusive, but how did you learn what's going on behind 'the big picture'? Regards, SS
See inline. WIlly. [quoted text, click to view] "Sunny S" <sunny.s@newsgroup.nospam> wrote in message news:5740021E-1C8F-422F-AF74-E45DE21AF7B6@microsoft.com... > Hi Willi, > > I agree that 'not in line with the docs' was, perhaps, an overstatement:). > What I actually wanted to say is that as far as I am concerned the > documentation was not clear about the scope of the Application object and > the > relationship between Application, A.E method and AppDomains. >
Well, as said before, Windows.Forms was designed to be used from the "default domain" only and not from muttiple AD's running in the same process. The reason is quite simple, the underlying Win32 Windows architecture doesn't know about AD's, it only knows about processes and threads and one thread which is important in the "Windows" context is the UI thread. It's the thread that must run a message pump in order to retrieve Window messages from the application and from the System. [quoted text, click to view] > For example, you say ' ... you create a new application > (Application.Run(..) > in each of the domains/threads ...' Define 'application'. Surely it's not > a > new Application object or is it? BTW, the documentation just says that > calling A.R 'Begins running a standard application message loop on the > current thread'. I am not trying to be argumentative, I'm just trying to > understand what's going on. >
A.R creates an ApplicationContext (and a static Application instance ), it's the ApplicationContext who actually defines *the* application in terms of the MSDN docs. [quoted text, click to view] > Let's take one of your scenarios: "From AD1/thread1 you create another > thread, and you create a window and run a message pump in this thread." > Why > can't I use the same logic as above and say that by 'creating a window and > running a message pump' on a new thread (through Application.Run(Form), I > presume) I create a new application?
You create a new Application in terms of the docs, that's right. [quoted text, click to view] > > Let's futher modify this scenario so that the second thread is created, as > above, from AD1/thread1, but in a separate AppDomain (AD2), so that AD2 is > a > 'child' of AD1. In this case, calling A.E on either of the threads doesn't > stop the other (I did test it:). >
Ok so you have: AD1/T1 -> creates T2 -> creates AD2 -> call A.R which creates a new ApplicationContext (a new application as per msdn) which start a pump on T2. Calling A.E in T2 will stop the pump on T2, destroy the ApplicationContext and as such stop this application. The fact that you do this is a new AD is irrelevant, an AD != an "application". [quoted text, click to view] > You see, this is the sort of questions I was trying to clarify for myself > and I found your comments quite helpful, thank you. > > "Willy Denoyette [MVP]" wrote: > >> "Sunny S" <sunny.s@newsgroup.nospam> wrote in message >> news:67A7646B-4AA9-4B6E-89F6-A4C8CBE9B522@microsoft.com... >> > Jon, >> > >> > I’ve just done some more tests. My understanding of Willy Denoyette’s >> > explanation (see at the bottom of this thread) was that >> > Application.Exit() >> > kills the message pumps in the current Appdomain and its ‘child’ >> > AppDomains. >> > >> > To verify this I further modified the code with AppDomains so that one >> > of >> > the threads creates yet another ‘child’ AppDomain and starts yet >> > another >> > message loop in it. This test showed that my understanding was >> > incorrect. >> > All >> > three message loops in those AppDomains are independent in the sense >> > that >> > killing one of them doesn’t kill the others. >> > >> >> >> >> I know this is quite confusing, but I'm not sure why you consider this >> "not >> inline with the docs". >> Note that the docs talks about applications, and stopping all message >> pumps >> in the application, it doesn't talk about threads running other AD's. >> >> In your last sample you are creating separate AD/thread pairs *and* you >> create a new application (Application.Run(..) in each of the >> domains/threads, calling A.E in one of the AD/threads only stops the >> (single) message pumps in this application, which is inline with the >> docs, >> right? >> >> Now, say the from AD1/thread1 you create another thread, and you create a >> window and run a message pump in this thread. That means, you have >> AD1/thread1 and thread2, and two separate message pumps. Calling A.E from >> one of these threads will stop all (2) pumps, which is inline with the >> docs, >> right? >> >> And, say you have a AD/thread that runs an application >> (Application.Run(...)], and this thread creates another AD that shows a >> form. Here you have two AD's, one *Application* and only one thread that >> pumps the message queue of both the main form and the other AD's form. >> When >> you call A.E from the second form code, you will simply unload the second >> AD >> and it's form, but you won't stop the message pump. Calling A.E from the >> main form will stop the message pump and close all forms tear down the >> AD's >> for the whole application, which is again inline with the doc's. >> >> Willy. >> >> >>
[quoted text, click to view] "Sunny S" <sunny.s@newsgroup.nospam> wrote in message news:C30ACC37-E41C-4546-8739-7F04FAE1070E@microsoft.com... > Hi Willi, > > We are almost there:):):) > > To recap, we have: AD1/T1 -> calls A.R(Form1); creates T2 -> creates > AD2 -> > call A.R(Form2). Here calling A.E on T2 does close Form2, but doesn't > close > Form1. The reverse is also true: calling A.E on T1 closes Form1, but > doesn't > close Form2. >
Yep. [quoted text, click to view] > I accept your explanation that A.R(Form2) creates a new 'application' > that > is independent of the application running Form1, so exiting one of them > doesn't affect the other. > > Why then things are different for the following scenario: AD1/T1 -> calls > A.R(Form1); creates T2 -> calls A.R(Form2), where we don't create a > separate > AppDomain for T2? As you pointed out erlier, closing either Form1 or Form2 > closes the other Form and shuts down the application. >
Here you create one AD, 2 threads, 2 applications (ApplicationContexts, ApplicationThreadContexts, etc... ) , 2 message pumps (one per thread). When you call A.E in one of the threads, you get rid of all of the ApllicationContexts in the containing AD and it's AD children. Note that what's happening is quite more complex, but that's the big picture. Why are you so interested in A.E's behavior, which is not the most appropriate way to stop an application anyway, just currious. [quoted text, click to view] > Apparently, calling A.R on a different thread in a separate AppDomain is > somehow different from calling it in the same AppDomain. Would it be > correct > to assume that the scope of Application.Exit() is limited to the current > AppDomain only? > > > "Willy Denoyette [MVP]" wrote: > >> See inline. >> >> >> WIlly. >> >> "Sunny S" <sunny.s@newsgroup.nospam> wrote in message >> news:5740021E-1C8F-422F-AF74-E45DE21AF7B6@microsoft.com... >> > Hi Willi, >> > >> > I agree that 'not in line with the docs' was, perhaps, an >> > overstatement:). >> > What I actually wanted to say is that as far as I am concerned the >> > documentation was not clear about the scope of the Application object >> > and >> > the >> > relationship between Application, A.E method and AppDomains. >> > >> Well, as said before, Windows.Forms was designed to be used from the >> "default domain" only and not from muttiple AD's running in the same >> process. The reason is quite simple, the underlying Win32 Windows >> architecture doesn't know about AD's, it only knows about processes and >> threads and one thread which is important in the "Windows" context is the >> UI >> thread. It's the thread that must run a message pump in order to retrieve >> Window messages from the application and from the System. >> >> >> > For example, you say ' ... you create a new application >> > (Application.Run(..) >> > in each of the domains/threads ...' Define 'application'. Surely it's >> > not >> > a >> > new Application object or is it? BTW, the documentation just says that >> > calling A.R 'Begins running a standard application message loop on the >> > current thread'. I am not trying to be argumentative, I'm just trying >> > to >> > understand what's going on. >> > >> >> A.R creates an ApplicationContext (and a static Application instance ), >> it's >> the ApplicationContext who actually defines *the* application in terms >> of >> the MSDN docs. >> >> >> > Let's take one of your scenarios: "From AD1/thread1 you create another >> > thread, and you create a window and run a message pump in this thread." >> > Why >> > can't I use the same logic as above and say that by 'creating a window >> > and >> > running a message pump' on a new thread (through Application.Run(Form), >> > I >> > presume) I create a new application? >> >> You create a new Application in terms of the docs, that's right. >> >> > >> > Let's futher modify this scenario so that the second thread is created, >> > as >> > above, from AD1/thread1, but in a separate AppDomain (AD2), so that AD2 >> > is >> > a >> > 'child' of AD1. In this case, calling A.E on either of the threads >> > doesn't >> > stop the other (I did test it:). >> > >> Ok so you have: >> AD1/T1 -> creates T2 -> creates AD2 -> call A.R which creates a new >> ApplicationContext (a new application as per msdn) which start a pump on >> T2. >> Calling A.E in T2 will stop the pump on T2, destroy the >> ApplicationContext >> and as such stop this application. >> The fact that you do this is a new AD is irrelevant, an AD != an >> "application". >> >> >> >> > You see, this is the sort of questions I was trying to clarify for >> > myself >> > and I found your comments quite helpful, thank you. >> > >> > "Willy Denoyette [MVP]" wrote: >> > >> >> "Sunny S" <sunny.s@newsgroup.nospam> wrote in message >> >> news:67A7646B-4AA9-4B6E-89F6-A4C8CBE9B522@microsoft.com... >> >> > Jon, >> >> > >> >> > I’ve just done some more tests. My understanding of Willy Denoyette’s >> >> > explanation (see at the bottom of this thread) was that >> >> > Application.Exit() >> >> > kills the message pumps in the current Appdomain and its ‘child’ >> >> > AppDomains. >> >> > >> >> > To verify this I further modified the code with AppDomains so that >> >> > one >> >> > of >> >> > the threads creates yet another ‘child’ AppDomain and starts yet >> >> > another >> >> > message loop in it. This test showed that my understanding was >> >> > incorrect. >> >> > All >> >> > three message loops in those AppDomains are independent in the sense >> >> > that >> >> > killing one of them doesn’t kill the others. >> >> > >> >> >> >> >> >> >> >> I know this is quite confusing, but I'm not sure why you consider this >> >> "not >> >> inline with the docs". >> >> Note that the docs talks about applications, and stopping all message >> >> pumps >> >> in the application, it doesn't talk about threads running other AD's. >> >> >> >> In your last sample you are creating separate AD/thread pairs *and* >> >> you >> >> create a new application (Application.Run(..) in each of the >> >> domains/threads, calling A.E in one of the AD/threads only stops the >> >> (single) message pumps in this application, which is inline with the >> >> docs, >> >> right? >> >> >> >> Now, say the from AD1/thread1 you create another thread, and you >> >> create a >> >> window and run a message pump in this thread. That means, you have >> >> AD1/thread1 and thread2, and two separate message pumps. Calling A.E >> >> from >> >> one of these threads will stop all (2) pumps, which is inline with the >> >> docs, >> >> right? >> >> >> >> And, say you have a AD/thread that runs an application >> >> (Application.Run(...)], and this thread creates another AD that shows >> >> a >> >> form. Here you have two AD's, one *Application* and only one thread >> >> that
Hi Jeff, Thanks for replying and for your comments. To answer your questions, 1. Yes, the app we are writing is being coded in Winform, it's not a Web application, at least for the time being. 2. I can see two explanations for our design being strange to you:) - a) we are doing something genuinely stupid; b) we are doing something genuinely new (a combination of both is also an option:):):)). On a serious note, we are trying to create an app that would host some other applications, either GUI or non-GUI, which would be configurable through the host UI. The host is supposed to be non-intrusive; once the apps are configured they should run as there is no host, although they would be required to respond to host’s request about their status. 3. Why don’t I call AppDomain.Unload()? I actually do, but there are scenarios when I don’t want or cannot do this. (a) If the 3rd party app that sits in this AppDomain is running a foreground thread then AppDomain.Unload throws an exception. (b) If there is a problem with a 3rd party app, so that it cannot continue, we would like to stop it - not in a graceful way, perhaps - and grab some status data. Then we can unload the whole thing. (c) We should be able to stop the 3rd party app, reconfigure it and start again. 4. Just to illustrate what I was talking about when I said that there were limits to which Reflector could ‘reflect’, let’s take the Object class. Look, for example, at internal static extern bool InternalEquals(object objA, object objB) As far as I know, there is no matching Win32 API to p/invoke and this is as far as I can go in exploring the CLR internals. Anyway, thank you very much for your help. SS [quoted text, click to view] "Jeffrey Tan[MSFT]" wrote: > Hi Sunny, > > Sorry for the late response to you, I am out of office yesterday. Anyway, I > am glad Willy has provided a great and informative discussion with you. > > I assume your application is coded in Winform since you are using > System.Winforms.Forms.Application. So, your application created a seperate > AppDomain to host the 3rd party code for security/robustness reason ? Can > you tell us if the 3rd party code is also GUI code? This design and > achitecture looks strange to me, since I did not see any programs using this > design. We normally run the semi-trusted non-GUI addin in the separate > AppDomain. > > I ask these because Application.Exit can only be used in GUI Winform code > not normal non-GUI code. Also, it can only shut down the GUI threads in the > *Application*. If the 3rd party code created a few more worker(non-GUI) > threads, they will be cleaned by Application.Exit. As Willy originally > pointed out, Application.Exit() has nothing to do with AppDomain, so it will > not help to clearn AppDomain. Why don't you call AppDomain.Unload method to > get rid of the buggy 3rd party code? > > Regarding your last question, I think Reflector should be the best tool to > understand the .Net BCL internal work. What internal call functions do you > have problem to understand? As I know Winform purely encapsulates the Win32 > GUI code, so I assume most of the non-.Net code is p/invoking the Win32 > User32 APIs. The Win32 GUI programming books(such as <Programming Windows>) > should be good resource to help you understand GUI APIs. > > Hope this helps. > > Best regards, > Jeffrey Tan > Microsoft Online Community Support > ========================================= > Delighting our customers is our #1 priority. We welcome your comments and > suggestions about how we can improve the support we provide to you. Please > feel free to let my manager know what you think of the level of service > provided. You can send feedback directly to my manager at: > msdnmg@microsoft.com. > > This posting is provided "AS IS" with no warranties, and confers no rights. > >
Hi Sunny, Sorry for the late response to you, I am out of office yesterday. Anyway, I am glad Willy has provided a great and informative discussion with you. I assume your application is coded in Winform since you are using System.Winforms.Forms.Application. So, your application created a seperate AppDomain to host the 3rd party code for security/robustness reason ? Can you tell us if the 3rd party code is also GUI code? This design and achitecture looks strange to me, since I did not see any programs using this design. We normally run the semi-trusted non-GUI addin in the separate AppDomain. I ask these because Application.Exit can only be used in GUI Winform code not normal non-GUI code. Also, it can only shut down the GUI threads in the *Application*. If the 3rd party code created a few more worker(non-GUI) threads, they will be cleaned by Application.Exit. As Willy originally pointed out, Application.Exit() has nothing to do with AppDomain, so it will not help to clearn AppDomain. Why don't you call AppDomain.Unload method to get rid of the buggy 3rd party code? Regarding your last question, I think Reflector should be the best tool to understand the .Net BCL internal work. What internal call functions do you have problem to understand? As I know Winform purely encapsulates the Win32 GUI code, so I assume most of the non-.Net code is p/invoking the Win32 User32 APIs. The Win32 GUI programming books(such as <Programming Windows>) should be good resource to help you understand GUI APIs. Hope this helps. Best regards, Jeffrey Tan Microsoft Online Community Support ========================================= Delighting our customers is our #1 priority. We welcome your comments and suggestions about how we can improve the support we provide to you. Please feel free to let my manager know what you think of the level of service provided. You can send feedback directly to my manager at: msdnmg@microsoft.com. This posting is provided "AS IS" with no warranties, and confers no rights.
Hi Jeff, Thanks for replying and my special thanks for the link to FCall. This should be very useful (or at least very interesting:) ). Regarding (a) in my previous post: The exception that AppDomain throws is actually CannotUnloadAppDomainException and VS2008 gives a hint: 'Make sure you are not trying to unload an application domain that ... has a running thread ...'. Again, this is only a problem for foreground threads. Regarding (b): basically the idea is to stop all processing, create some types defined in the loaded assemblies, and call some methods on those types. It may not be always possible if one of the types is running a tight loop on a foreground thread. So the first thing to do is to try and kill all the threads. Regarding (c): The host we are writing should be able to swap an assembly that is suspected to cause problems with an alternative one. Of course, this is also possible by unloading the AppDomain and loading it with the same assemblies except the suspected one. However, in our case under certain scenarios this could be time consuming and as an alternative we are investigating the possibility of swapping only the suspected assembly without unloading the whole set. Books recommendations: I've already read Jeff Richter’s <CLR via C#> (both editions) and right now I am finishing <Customizing The Microsoft .Net Framework CLR> by Steve Pratschner. <Shared Source .. > seems to be interesting, thanks, I’ll have a look. Again, thank you very much for your help. Where do you guys find time to answer all our questions?:) You seem to be so willing to help; that’s quite impressive.. Regards, SS [quoted text, click to view] ""Jeffrey Tan[MSFT]"" wrote: > Hi Sunny, > > Thanks for your feedback. > > Regarding "(a) If the 3rd party app that sits in this AppDomain is running > a foreground thread then AppDomain.Unload throws an exception", do you mean > ThreadAbortException thrown in the thread in the 3rd party AppDomain? Yes, > AppDomain.Unload() method uses Thread.Abort() method on the target thread > to terminate the threads. ThreadAbortException will perform stack unwind on > the target stack to perform clean-up and then terminate the target thread. > Then, what is the problem of this behavior? > > Regarding (b) and (c), I also do not think I understand the key points. > What is the problem of AppDomain.Unload() against your (b) and (c) > requirement? > > Regarding the Reflector issue, it seems that you are interested in the > internal routines implemented by the CLR. Yes, a lot of .Net services are > implemented in the CLR via native code. They are using "FCall" into the CLR > which can not be examined using Reflector. The only way to examine its > implementation is reversing engineer(disassemble) it. Also, Microsoft > released an open-source CLR implementation called SSCLI, which contains an > example implementation of CLR and .Net Framework. You may examine its > source code to understand these FCall functions. The SSCLI source code is > not guaranteed to be the same as CLR, but most of the principles are the > same. The articles below also talks about FCall: > http://blogs.msdn.com/yunjin/archive/2004/02/08/69906.aspx > https://blogs.msdn.com/joelpob/archive/2003/12/18/53745.aspx > > Also, a lot of interesting books talk about CLR internal implementation, > such as Jeffrey Richter's <CLR via C#>, Don Box's <Essential .Net>, <Shared > Source CLI Essentials> etc.. They are helpful to understand CLR principles. > > Hope this helps. > > Best regards, > Jeffrey Tan > Microsoft Online Community Support > ========================================= > Delighting our customers is our #1 priority. We welcome your comments and > suggestions about how we can improve the support we provide to you. Please > feel free to let my manager know what you think of the level of service > provided. You can send feedback directly to my manager at: > msdnmg@microsoft.com. > > This posting is provided "AS IS" with no warranties, and confers no rights. > > >
Hi Sunny, Thanks for your feedback. Regarding "(a) If the 3rd party app that sits in this AppDomain is running a foreground thread then AppDomain.Unload throws an exception", do you mean ThreadAbortException thrown in the thread in the 3rd party AppDomain? Yes, AppDomain.Unload() method uses Thread.Abort() method on the target thread to terminate the threads. ThreadAbortException will perform stack unwind on the target stack to perform clean-up and then terminate the target thread. Then, what is the problem of this behavior? Regarding (b) and (c), I also do not think I understand the key points. What is the problem of AppDomain.Unload() against your (b) and (c) requirement? Regarding the Reflector issue, it seems that you are interested in the internal routines implemented by the CLR. Yes, a lot of .Net services are implemented in the CLR via native code. They are using "FCall" into the CLR which can not be examined using Reflector. The only way to examine its implementation is reversing engineer(disassemble) it. Also, Microsoft released an open-source CLR implementation called SSCLI, which contains an example implementation of CLR and .Net Framework. You may examine its source code to understand these FCall functions. The SSCLI source code is not guaranteed to be the same as CLR, but most of the principles are the same. The articles below also talks about FCall: http://blogs.msdn.com/yunjin/archive/2004/02/08/69906.aspx https://blogs.msdn.com/joelpob/archive/2003/12/18/53745.aspx Also, a lot of interesting books talk about CLR internal implementation, such as Jeffrey Richter's <CLR via C#>, Don Box's <Essential .Net>, <Shared Source CLI Essentials> etc.. They are helpful to understand CLR principles. Hope this helps. Best regards, Jeffrey Tan Microsoft Online Community Support ========================================= Delighting our customers is our #1 priority. We welcome your comments and suggestions about how we can improve the support we provide to you. Please feel free to let my manager know what you think of the level of service provided. You can send feedback directly to my manager at: msdnmg@microsoft.com. This posting is provided "AS IS" with no warranties, and confers no rights.
Hi Jeff, Thanks for replying. To answer your question whether I tried to find out why Thread.Abort() didn’t terminate the foreground thread, - no, I didn’t even try. First, I am lazy and I prefer to ask experts; this does save time in the short run:) Second, the documentation on Thread.Abort says ‘The thread is not guaranteed to abort immediately, or at all’ and that is enough for me (see the first reason:))). In my simplistic scenario the thread was doing something like this: while (true) {}; so given the information I found at http://www.ondotnet.com/pub/a/dotnet/2003/02/18/threadabort.html I assumed there was no chance for that sort of thread to be aborted. Then I asked myself a question why is it still aborted when it is created as a background thread? I figured that trying to find an answer to this question would take me an unjustified amount of time given the fact that stopping the thread by Application.Exit() gives an immediate practical solution. I do need to read the books you’ve recommended … Regards, SS [quoted text, click to view] ""Jeffrey Tan[MSFT]"" wrote: > Hi Sunny, > > Thank you for explaining it in details. > > Oh, I was not aware of that the foreground UI thread will block the > AppDomain.Unload() method with CannotUnloadAppDomainException. Have you > invested to find out why the Thread.Abort did not terminate the target > thread? I have had a hard time to understand why the thread did not > terminate. > > Anyway, if Application.Exit() can terminate all the foreground GUI threads > in the target AppDomain, I think we can call Application.Exit() to > terminate all the UI threads in the target AppDomain and followed with an > AppDomain.Unload() method calling to clean up the target AppDomain. > > <Shared Source CLI Essentials> explains the CLI(which is very similiar with > CLR) in source-code level, so it has a deeper insight than other CLR books. > <Customizing The Microsoft .Net Framework CLR> targets the CLR hosting > topics in depth. > > Actually, I am the .Net CLR and VS.net debugging newsgroups MSDN > subscription support engineer, so it's my job and pleasure to help you > :-).(Also, I learned a lot in the newsgroup discussion) > > Best regards, > Jeffrey Tan > Microsoft Online Community Support > ========================================= > Delighting our customers is our #1 priority. We welcome your comments and > suggestions about how we can improve the support we provide to you. Please > feel free to let my manager know what you think of the level of service > provided. You can send feedback directly to my manager at: > msdnmg@microsoft.com. > > This posting is provided "AS IS" with no warranties, and confers no rights. >
Hi Sunny, Thank you for explaining it in details. Oh, I was not aware of that the foreground UI thread will block the AppDomain.Unload() method with CannotUnloadAppDomainException. Have you invested to find out why the Thread.Abort did not terminate the target thread? I have had a hard time to understand why the thread did not terminate. Anyway, if Application.Exit() can terminate all the foreground GUI threads in the target AppDomain, I think we can call Application.Exit() to terminate all the UI threads in the target AppDomain and followed with an AppDomain.Unload() method calling to clean up the target AppDomain. <Shared Source CLI Essentials> explains the CLI(which is very similiar with CLR) in source-code level, so it has a deeper insight than other CLR books. <Customizing The Microsoft .Net Framework CLR> targets the CLR hosting topics in depth. Actually, I am the .Net CLR and VS.net debugging newsgroups MSDN subscription support engineer, so it's my job and pleasure to help you :-).(Also, I learned a lot in the newsgroup discussion) Best regards, Jeffrey Tan Microsoft Online Community Support ========================================= Delighting our customers is our #1 priority. We welcome your comments and suggestions about how we can improve the support we provide to you. Please feel free to let my manager know what you think of the level of service provided. You can send feedback directly to my manager at: msdnmg@microsoft.com. This posting is provided "AS IS" with no warranties, and confers no rights.
[quoted text, click to view] "Sunny S" <sunny.s@newsgroup.nospam> wrote in message news:D9E76F91-C321-46F3-8AEE-658733104D41@microsoft.com... > Hi Jeff, > > Thanks for replying and my special thanks for the link to FCall. This > should > be very useful (or at least very interesting:) ). > > Regarding (a) in my previous post: The exception that AppDomain throws is > actually CannotUnloadAppDomainException and VS2008 gives a hint: 'Make > sure > you are not trying to unload an application domain that ... has a running > thread ...'. Again, this is only a problem for foreground threads. > > Regarding (b): basically the idea is to stop all processing, create some > types defined in the loaded assemblies, and call some methods on those > |