A DLL process is running in an isolated App. Domain which was runned from a 3rd application.
I would like to unload AppDomain
If I use Enviroment.Exit(), it also kills the father application (app which lauches the DLL process)
edit
Doing as it follows neither:
AppDomain domainObj = AppDomain.CurrentDomain;
AppDomain.Unload(domainObj);
If a function from the DLL is running as a thread in a separate AppDomain in your process, then you can try calling AppDomain.Unload. According to the documentation,
When a thread calls Unload, the target domain is marked for unloading. The dedicated thread attempts to unload the domain, and all threads in the domain are aborted. If a thread does not abort, for example because it is executing unmanaged code, or because it is executing a finally block, then after a period of time a CannotUnloadAppDomainException is thrown in the thread that originally called Unload. If the thread that could not be aborted eventually ends, the target domain is not unloaded. Thus, in the .NET Framework version 2.0 domain is not guaranteed to unload, because it might not be possible to terminate executing threads.
So if you are unable to successfully unload this other appdomain - you may have to find other alternatives.
Related
I need to inject a dll into the main thread of a process (otherwise my process will crash)
How would I go about doing this? My dll is in C++ obviously, my injection method though uses C# and CreateRemoteThread.
I've tried using std::thread(func) but that didn't work (of course it probably wouldn't since it most likely creates a new thread)
I don't know if this is a problem for my DLL or my injector, so all help and attempts to help is appreciated.
Your DllMain will run in the context of every thread... figure out which is the main thread.
Since you can't do much while the loader lock is held, create a callback with thread affinity (for example using SetTimer) and do all the work from that callback.
You can create the target process suspended and use CreateRemoteThread() for injection, but mind the following limitations:
You should copy the thread main routine for the remote thread to the address space of the target process.
This code cannot contain any external references (e.g. CRTL or direct WinApi calls). I would usually limit this code to loading of the DLL and either executing function from it, or relying on the DllMain to do the job you need. In order to call LoadLibrary and GetProcAddress methods, I obtain their addresses and copy structure containing this information to the target process and pass the address of the remote structure as an argument for the thread main routine in CreateRemoteThread(). You can use VirtualAllocEx() to allocate memory in the remote process,
Remote thread in this situation will be executed before main thread, including process and some Win32/64 initialization. Therefore, not every Win32 API is safe to call in this condition.
You can read more here: http://blogs.microsoft.co.il/pavely/2017/03/14/injecting-a-dll-without-a-remote-thread/
I have pretty simple code like:
var childDomain = AppDomain.CreateDomain("child");
childDomain.ExecuteAssembly("WpfApplication1.exe");
AppDomain.Unload(childDomain);
But it closes app at all. I don't have any references to WpfApplication1.exe in parent app. I read this - AppDomain Unload killing Parent AppDomain but it hadn't helped.
So what I'm doing wrong?
The problem was in this line:
childDomain.ExecuteAssembly("WpfApplication1.exe");
ExecuteAssembly method runs application on the same thread as caller. So unloading is killing the main thread. The solution is run child app in new STA thread.
What Causes Finalize Methods to Be Called ?
2 answers( of 4 ) to this question are :
The CLR is unloading an AppDomain When an AppDomain unloads, the CLR considers
nothing in the AppDomain to be a root, and a garbage collection consisting of
all generations is performed.
The CLR is shutting down The CLR shuts down when a process terminates normally
(as opposed to an external shutdown via Task Manager, for example).
I assume that The CLR is unloading an AppDomain is when the program (console [exe] for example) is being closed ( by pressing close / normal end of program)
What about The CLR is shutting down ? continuing the [Exe] program analogy above :
what does it mean ? How can I ShutDown CLR ...?
[in the IIS world] does it mean IIS reset ?
please, can I have small explanation ?
The AppDomain is a more granular unit than the Process. A Process can can have multiple AppDomain instances, each of which can be unloaded separately.
The CLR shutdown is the process terminating.
The AppDomain unloading is each AppDomain separately.
(although I would not personally guarantee, without checking the documentation, that all finalizers etc are executed in either case)
As an example, I use multiple AppDomain instances in a long-running self-updating windows service; when new versions are detected it pulls down the new binaries, spawns a new AppDomain, gets it running, switches future operations to the new AppDomain, and unloads the old AppDomain (when running operations have completed).
I have a Application which copies a DLL (UserControlLibrary) to its own Debug/Release folder and loads it using this Code:
AppDomain appDomain = AppDomain.CreateDomain("MyDomain");
OpenFileDialog dialog = new OpenFileDialog();
dialog.Filter = "DLLs (*.dll)|*.dll";
if (dialog.ShowDialog().Value)
{
string newLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\" + dialog.SafeFileName;
File.Copy(dialog.FileName, newLocation, true);
Assembly assembly = appDomain.Load(AssemblyName.GetAssemblyName(newLocation));
UserControl userControl = (UserControl) assembly.CreateInstance("WpfControlLibrary1.UserControl1");
}
I now add that UserControl to a Grid using:
grid.Children.Add(userControl);
Works fine. Now I try to unload the DLL using:
AppDomain.Unload(appDomain);
grid.Children.Clear();
If I now try to load the DLL (because it changed meanwhile) again using the above code I get an error telling me the file is in use (File.Copy).
I've read a lot of things and my guess is that I'm not allowed to use the UserControl like I did (because that loads into the Main AppDomain). How do I have to change the Code to make it work?
I've also read a lot of things about using MarshalByRefObject but unfortunately I was unable to implement it in this project. A example or modification of the code above would be nice.
EDIT:
From the comments I've read so far (especially from svick) it looks like I have to use "AppDomain.CreateInstanceAndUnwrap" instead of "AppDomain.Load".
I've seen that approach already while searching for a solution earlier but as svick mentioned that doesn't work because a UserControl can't inherit from MarshalByRefObject.
Does anyone know another way?
Read the documentation for AppDomain.Load(). It specifically says that this method loads the assembly both into the assembly you are calling the method on and into the current assembly. So, even when you unload the app domain, the assembly still stays loaded in the current assembly.
I'm not sure there is a way around this as you can't make UserControl inherit from MarhshalByRefObject.
When you call unload, the AppDomain is not immediately unloaded (see MSDN for the full article):
When a thread calls Unload, the target domain is marked for unloading.
The dedicated thread attempts to unload the domain, and all threads in
the domain are aborted. If a thread does not abort, for example
because it is executing unmanaged code, or because it is executing a
finally block, then after a period of time a
CannotUnloadAppDomainException is thrown...
Perhaps this quote from the MSDN article for AppDomain.Unload could explain things:
In the .NET Framework version 2.0 there is a thread dedicated to unloading application domains. This improves reliability, especially when the .NET Framework is hosted. When a thread calls Unload, the target domain is marked for unloading. The dedicated thread attempts to unload the domain, and all threads in the domain are aborted. If a thread does not abort, for example because it is executing unmanaged code, or because it is executing a finally block, then after a period of time a CannotUnloadAppDomainException is thrown in the thread that originally called Unload. If the thread that could not be aborted eventually ends, the target domain is not unloaded. Thus, in the .NET Framework version 2.0 domain is not guaranteed to unload, because it might not be possible to terminate executing threads.
Maybe there are some rogue threads that are keeping the app domain alive and therefore also keeping your file locked.
As a workaround, you could copy the DLLs to random file names instead.
I have an application that loads external assemblies which I have no control over (similar to a plugin model where other people create and develop assemblies that are used by the main application). It loads them by creating new AppDomains for these assemblies and then when the assemblies are done being used, the main AppDomain unloads them.
Currently, it simplistically unloads these assemblies by
try
{
AppDomain.Unload(otherAssemblyDomain);
}
catch(Exception exception)
{
// log exception
}
However, on occasion, exceptions are thrown during the unloading process specifically CannotUnloadAppDomainException. From what I understand, this can be expected since a thread in the children AppDomains cannot be forcibly aborted due to situations where unmanaged code is still being executed or the thread is in a finally block:
When a thread calls Unload, the target
domain is marked for unloading. The
dedicated thread attempts to unload
the domain, and all threads in the
domain are aborted. If a thread does
not abort, for example because it is
executing unmanaged code, or because
it is executing a finally block, then
after a period of time a
CannotUnloadAppDomainException is
thrown in the thread that originally
called Unload. If the thread that
could not be aborted eventually ends,
the target domain is not unloaded.
Thus, in the .NET Framework version
2.0 domain is not guaranteed to unload, because it might not be
possible to terminate executing
threads.
My concern is that if the assembly is not loaded, then it could cause a memory leak. A potential solution would be to kill the main application process itself if the above exception occurs but I rather avoid this drastic action.
I was also considering repeating the unloading call for a few additional attempts. Perhaps a constrained loop like this:
try
{
AppDomain.Unload(otherAssemblyDomain);
}
catch (CannotUnloadAppDomainException exception)
{
// log exception
var i = 0;
while (i < 3) // quit after three tries
{
Thread.Sleep(3000); // wait a few secs before trying again...
try
{
AppDomain.Unload(otherAssemblyDomain);
}
catch (Exception)
{
// log exception
i++;
continue;
}
break;
}
}
Does this make sense? Should I even bother with trying to unload again? Should I just try it once and move on? Is there something else I should do? Also, is there anything that can be done from the main AppDomain to control the external assembly if threads are still running (keep in mind others are writing and running this external code)?
I'm trying understand what are best practices when managing multiple AppDomains.
I've dealt with a similar problem in my app. Basically, you can't do anything more to force the AppDomain to go down than Unload does.
It basically calls abort of all threads that are executing code in the AppDomain, and if that code is stuck in a finalizer or unmanaged code, there isn't much that can be done.
If, based on the program in question, it's likely that the finalizer/unmanaged code will finish some later time, you can absolutely call Unload again. If not, you can either leak the domain on purpose or cycle the process.
Try to make GC.Collect() if you do not unload the domain.
try
{
AppDomain.Unload(otherAssemblyDomain);
}
catch (CannotUnloadAppDomainException)
{
GC.Collect();
AppDomain.Unload(otherAssemblyDomain);
}
I had similar issues with random behavior for months now, (with some app.Unload even BLOCKING forever ! on some machines)
finally decided to take a big breath and made process isolation.
you can spawn child console process and redirect output
if you need to cancel this is finger in the nose to kill child process and all dependencies / handles.
To an extreme i had to run dedicated cleanup code, and came to solution to create additional process with dedicated cmd line waiting input extracted from console output of initial runner process.
yes this app domain is a real joke and i think this is not a coincidence that it is not anymore in net core.