How to unload the .dll using c#? - c#

I am using .dll reference to my application.
i want to unload the .dll in a button click event.
How to do it ???

You can't unload an individual assembly - you have to unload a whole AppDomain. In other words, you'll need to load your other assembly (and associated code) in a new AppDomain, then when you want to unload it you unload the AppDomain.
Of course, this makes life a lot harder as you have to worry about marshalling calls between AppDomains - but it's all that .NET allows.

As Jon Skeet wrote, you cannot unload a DLL, but you can load the DLL in another AppDomain - and then unload the AppDomain. That is the only way to do it.
There are some things however that you need to be vary of, because you will naturally have to call functions across the AppDomain. This can happen in two different ways.
If you from one AppDomain (let's call it A), get a reference to an object that is instantiated in AppDomain B, then the default behaviour is that the object is serialized across the AppDomain boundary. That means that the object instance that A accesses is not the same instance that B accesses, and modifications made in A will not be reflected in B, unless you provide functionality to send to object back. This requires that the object is marked with Serializable.
You can however avoid the serialization by letting the class inherit from MarshalByRefObject. If the object is constructed in AppDomain B, and called from AppDomain A, the call will cross the AppDomain boundary. It will still be the same physical thread, so you don't have the overhead of a thread switch as you would in cross-process calls, or COM cross-apartment calls.
But if you construct an object in B that is referenced by an object in A, but the object in B is not accessed for 5 minutes, the object will be disposed. This behaviour can be overridden in MarshalByRefObject.InitializeLifetimeService().

See also the answer to Implementing .NET plug-ins without AppDomains. Note the discussion in the comments, where they point out that it very slowly leaks memory.

Related

Aliased registration for a COM component to allow concurrent calls

There's a COM library I need to use that CANT be changed.
The Apartment State is STA and can't be switched to MTA without refactoring.
It's got two methods
Method One is a short operation
Method Two is a long running operation
I'd like to be able to make calls to Method One even if Method Two is in progress.
One approach I've considered is copying and altering the COM component's actual binary and registering it as a totally different COM component, then using an instance of this alias'd library to do the calls to Method Two so that the main instance is only responsible for calls to Method One.
I've tried just opening up the DLL in a hex editor and replacing the ProgID and ClsId, but that doesn't seem to be working. The registry entries I'm aware of look right, but when I add a reference in visual studio in order to generate my interop assembly, the generated library still has the old ClsId and calls to Method One still block until Method Two completes.
Any ideas on how I can make this work?
Is this approach totally misguided or am I on the right track?
Creating two STA threads to handle invocations to the component definitely allowed me to make concurrent calls.
The solution here actually was way simpler than the craziness I was talking about initially. I had considered this solution before, but thought I'd tried it and it hadn't worked. Something must have been wrong with my previous implementation.
Specifically, I've got two STA threads in which I'm instantiating my COM component, and then I'm passing invocation requests to these threads via a blocking collection. The calls specified in the request objects are made and the request objects are provided with responses which signals the calling thread that the call is complete.
#IgorTandetnik pointed me in this direction.

Is there any programmable data that is automatically inherited by children Thread objects?

I had an idea for solving the problem of enumerating managed threads in .Net and for tracking thread ancestry (which thread created which other thread).
If it were possible to tag a Thread object with an object of the programmer's making that is automatically copied to children threads when they are created, it might be possible to use that tag to track when new threads are created, who created them, etc. The inspiration came from unix, where, when a process is forked, it inherits open file handles, etc. If there were some piece of data that is 1) thread-local or tied to a Thread object and 2) is automatically copied to new threads and 3) is modifiable, that would be a good start.
I'm guessing that we'll have to use reflection to access members of some of the Thread object that starts the chain because most of what i see in the thread that might be useful is otherwise locked up, but it's an start. I'm not sure how wise this approach is though.
Edit:
I think I'll explain my use case better because I don't think anybody understands.
I know about tracking threads explicitly, which I've done widely in code i own before. That's not the problem.
Basically, I'm trying to implement a 'thread-group-context', much in the same way that .Net has an appdomain-context, a remoting context [1] and an assembly-thread combination-local context [2].
For a given group of threads that were spawned from a common thread, I want to associate information with that grouping. While I understand that .Net doesn't have this concept (else I would have no problem!), it doesn't change the fact that every managed thread in .Net was created by one and only one other managed thread, and thus, can be drawn in a tree structure.
The problem I am trying to solve is thus: I have an API, that has an context object. This API calls into a large external library of code that does real work, and does so starting from a thread of its creation. That external does not explicitly get a copy of the API context object, however it would need one in order to make calls on the API. Since it does not have a reference to the API context object, it cannot make these calls. As things stand today, the external library does need to make calls, and to do so it looks up the current context object in a single static field, meaning that there can only be one instance of my API per AppDomain. I wish to fix this.
This external library is partly out of my control, and the interface between my API and the external library does not explicitly pass the context object. Up until now, when the external library needed to make calls into the API, it would look at a static field in my API to get a reference to the context object.
The problem is then that a final executable can only have one instance of my API session per AppDomain, because we're using static fields to pass the context object to the external library (workhorse) code.
One option is to make a GetContextObject() method in my API. When the API spawns the thread to run the external library code, it would remember that thread in a shared static dictionary. When the external library code calls GetContextObject(), it would look up what thread it is running on and return the proper context object for that thread.
If the external library code never created its own threads, then I'd have no problem, I'd always have a 100% correct mapping of thread to context. However, the external library does make its own threads, and does so without my API being aware. When the API receives a call from those threads, it won't know what context object to give up, and has to guess - if there's only one context object registered, it uses that, otherwise, it throws an exception saying it can't tell you.
If I could have data tagged to thread objects that is inherited by threads created by that parent thread, then I could implement this tracking system.
Also, the external library does not use the thread pool.
Basically, my options are thus:
1) Redesign the interface between my API and the external library to pass in the context object, and redesign the external library to correctly pass around this context object. Involves trundling through ~1 million LOC.
1a) Forbid the external library from directly using the Thread object, and instead require them to use my own MyApiThread object that, when created, adds itself to my custom tracking mechanism. Requires changing less code in the external library than option #1, but still involves a lot of rework.
2) Force the consumer of my API to start each API session in a new AppDomain so that I can store my context object in a static field (this is the 'solution' today). AppDomains involve a lot of overhead and I do not wish to force this upon my users.
3) Find a way to track thread ancestry to be able to return the correct context object to the code calling from the external library based on the calling thread. This is the subject of this post.
To those saying that Windows does not have a concept of child-parent threading, you are off base - that is irrelevant. DotNet is not a Windows-only system, and its very design was to isolate it from the machine and OS it is running on, which is why .Net exists for Linux, Solaris, FreeBSD in the form of Mono. Furthermore, Java does have the very concept of thread ancestry that I need, and Java is implemented on Windows, thus this is a very possible and reasonable concept. While I realize that the .Net api has a certain Microsoft-specific bend to it, realize that, largely, .Net and Windows are independent.
In fact, I'll make my comment an answer and point you at Jeffrey Richter.
The CallContext class gives you the ability to store data for a "logical execution path", which can cross threads and AppDomains.
Just adding more info for shambulator answer.
CallContext.GetLogicalData and CallContext.SetLogicalData do the trick

Load DLL create Instance and Unload

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.

Using AppDomains to Parallelize Non-thread-safe DLL

I have an unmanaged C++ DLL that my .NET application uses via p/invoke. The method that I need from this DLL is fairly time consuming and I would like to parallelize the method calls. The problem is that it uses a bunch of statics and globals, so it is not thread-safe (and can't be changed). My plan was to overcome this non-thread-safe issue by calling the unmanaged DLL from multiple AppDomains in parallel.
I can call the unmanaged code from the multiple AppDomains without any problems as long as I don't do it in parallel, but as soon as I make the calls in parallel, I get an AccessViolationException. I am using Parallel.For() to make the parallel calls.
Is it possible to make a non-thread-safe unmanaged DLL "thread-safe" by simply making the calls from multiple AppDomains?
Calling the native method from multiple AppDomain instances won't help you at all here. AppDomain boundaries don't apply to native DLL's and they won't provide any benefit
First and foremost: Load multiple copies of dll in same process
You'd have to make sure that all invocations within an AppDomain are on a single thread.
ParallelFor cannot make that happen, so you'd need to
manually parallelize (chunk up your loop for each thread/appdomain)
better (IMHO): write a wrapper function that will use a specific instance of your native dll (e.g. by using a reference to the AppDomain from threadlocal storage?).
Note that depending on the complexity of your situation (callbacks, use of global data in managed library) you might want to limit execution of each AppDomain to a specific CPU core (core affinity: see Begin/EndThreadAffinity). I might be a tad paranoid here :)
Wrap the C++ DLL in an EXE and parallelize process invocations (instead of running this code in threads or AppDomains). I had this problem with GeckoFX, which doesn't like threads, and this solution worked just fine. Of course, it's up to you to manage communication with these processes. I blogged about this some time ago.

Loading an Isolated dll into existing Appdomain and autoexecuting events

I have a solutions where three projects are running. One of my project is class library that is isolated from other two class. Now what I want to do is to load it into existing appdomain and auto execute its methods on some event occured from other assemblies in same domain.
I have an event inside that, and i want to execute that event
Is it possible? I not getting the way to autoexecute an. While googling I fouund AppDomain.CreateInstance () but not able to fully utilise it.
OR
Way to trap events occuring in APPDOMAIN. Since i have my dll loaded in domain so how can I trap events occuring inside a domain.
It's reasonably straight forward, this should get you going:
http://msdn.microsoft.com/en-us/library/ms173139(VS.80).aspx
Basically you need to create an object that inherits from MarshalByRefObject, then pass an instance of it to the parent Appdomain. You now have an object running in your appdomain that you can manipulate, be it attaching or raising events, calling methods, whatever.

Categories