Our .NET 3.5 C# application creates multiple appdomains. Each appdomain loads the same unmanaged 3rd party dll. This dll reads a configuration file upon initialization. If the configuration changes during runtime, the dll must be unloaded and loaded again. This dll is not in our scope to rewrite correctly.
Does each appdomain have access to a separtate copy of this unmanaged dll, or does Windows keep one copy of the dll and maintain a usage count? If the latter is is the case, how do we get each instance of the unmanaged dll to reflect its unique configuration?
I think unmanaged dlls are loaded only once per process by the OS, so every app-domain will have the same loaded instance. To unload a dll, use the FreeLibrary function. However, since multiple app-domains are likely to have loaded the dll, there is no guarantee that FreeLibrary from one app-domain will actually free/unload the dll.
As BillW says, this seems like a design nightmare to me too!
Related
I'm embedding multiple 3rd party managed and unmanaged dlls into one dll.
That single dll gets picked up and injected into another host application at runtime ussing Assembly.Load
The entire thing is supposed to work as a host with plugins thing. (just to clarify)
I have it working for all dlls (managed, unmanaged and mixed) except for one: VideoOS.Platform.SDK.Export, for which I get
dll not found exception on runtime, the dll is from Milestone NVR SDK
I've tried:
putting it as IncludeAssemblies, Unmanaged32Assemblies and Unmanaged64Assemblies
toggling: compression, temp files on disk
manually loading it from the resources with: AppDomain.CurrentDomain.AssemblyResolve
decompiling the library itself with (Reflector, DotPeek, ILSpy) they all turn up with issues, so I'm thinking it's probabbly some pinvokes or similar that they can't decompile.
Notes:
The whole process works when the dll is in the same folder as the host app exe but not when it's embededd
I had an issue with a referenced library that started working when put in Unmanaged32Assemblies was resolved OK
I wrote a simple plugin manager class with MEF and FileSystemWatcher for refreshing plugins automatically, but I hear some say that to be able to add and remove assemblies (plugins) on the fly we need to use an AppDomain also.
Can anyone guide me as to when we need to use AppDomain and MEF together (especially for my plugin manager scenario)?
What is the relationship between them ?
In short, an AppDomain is required when you want to overwrite .dlls that are in use by an application, and that AppDomain must specify the ShadowCopyFiles = "true".
Shadow copying files means that the AppDomain will copy the .dlls to a temporary directory and load them from that temporary directory so the original .dlls can be overwritten.
Unfortunately the assemblies which are loaded into any AppDomain cannot be unloaded unless the AppDomain that contains them is unloaded.
With that in mind, refreshing a plugin is difficult because you would have to A) unload the entire AppDomain which necessarily unloads all other .dlls in that AppDomain, or B) allow a new version of the same .dll to be loaded increasing the memory footprint of your application. The second option also requires your plugin .dlls to be strong named and a different version number in order for MEF to recognise a difference and load the new .dll.
I'm really not sure whether .net dll also have entry point like c++ dll generally have.
How can i see if .net dll have entry point or not.
I read somewhere that a WIN32 dlls can have entry-points, dot-net class-libraries dont.
Thanks,
It is an obscure subject, I'll go through it at breakneck speed. Every .NET assembly has an unmanaged entrypoint, 5 bytes of machine code (9 if built for x64) that serve as the entrypoint marked in the PE32 executable file header. Nothing but a JMP instruction, an EXE jumps to _CorExeMain() and a DLL jumps to _CorDllMain(). These functions are located in mscoree.dll and ensure that the CLR is loaded and initialized so it can execute managed code.
These entrypoints help to run managed program without having to start the VM host explicitly. Avoids the need for, say, mono.exe or java.exe. They are not actually used anymore on modern Windows versions, the OS has awareness of an executable file containing a .NET manifest and the loader passes the job to a loader shim, mscoree.dll again. This awareness is necessary to implement the considerable trick of erecting a 64-bit process out an EXE that contains a 32-bit PE32 header. Mscoree.dll patches internal loader data structures to accomplish this feat.
Each .NET assembly also contains a managed entrypoint, listed in the manifest header. Called by the CLR right after it loaded the assembly. An EXE always has one, it points to the Main() method and the compiler ensures that you can't forget to write one. A DLL might have one, a mixed-mode assembly always has one for example. Points to a module initializer located in the <Module> class, the C++/CLI compiler uses it to ensure that the CRT (C runtime library) is initialized before any managed code can execute.
No, .NET DLL assemblies do not have a DllMain the way an unmanaged DLL would. However, all of the behaviors that one would implement in DllMain can generally be implemented using various .NET constructs. For example:
A class static constructor gives you a chance to initialize static members before the type is used
Instance initialization (constructor, field initializers) allow you to initialize instance data before the instance is used
Implementing the IDisposable interface gives you deterministic cleanup. Implementing a finalizer gives you the possibility (but not the guarantee) of non-deterministic cleanup (i.e. before the object is garbage-collected)
The AppDomain has the DomainUnload and ProcessExit events which can give you the chance to run cleanup code as the app domain or process is being closed.
I have a COM+ Application composed of several serviced components.
One of them instantiates on demand a type from a dll through Activator.CreateInstance(pluginType, args);. The type is not a serviced component itself, it contains just the implementation of certain interface that the component knows about.
I don't have problems with the instantiation itself, the problem is that the dll is getting locked by the dllhost.exe, and I would like, if possible, to be able to replace it without shutting down the COM+ Application.
Is it possible somehow to unlock the dll without shutting down the COM+ App?
Or from another point of view, is there a way I could programmatically unload the dll to unlock it?
NOTE: The dll is located in the COM+ application root directory with rest of the dlls.
Loaded modules are referenced counted in windows. In windows we have loadLibrary and freelibrary. If freelibrary is called and the reference count is zero then the dll will be unloaded and free to replace, delete, etc.
In .NET though once an assembly is loaded into an appDomain it is there until the appdomain dies (unless reflection emit collectable assembly). If you were to spawn another appdomain and do the create instance here when the new appdomain dies the assembly will be unloaded.
Asp.net does something called shadow caching. Asp.net you can replace the dlls at anytime without having to kill the worker process. They do this by not loading the dlls in the bin folder but instead they copy them to a seperate location and load them from there in a seperate appdomain. They watch the bin folder, when a change happens they kill the appdomain, copy the dlls to the temp folder, and create a new appdomain.
Shadow Copying Assemblies
http://msdn.microsoft.com/en-us/library/ms404279.aspx
This is not a specific problem for COM+, it is universal on Windows and fundamental to the way it works. Loading code from an executable file (exe or dll) is done by Windows creating a memory-mapped file for the executable file. Code is only read from the file when a page fault requires actually reading the file and mapping the code into RAM. This will happen repeatedly when other processes compete for RAM and the code gets unmapped.
The MMF puts a lock on the file. Required so that the file cannot be modified while it has code mapped into RAM.
There's no workaround for this, the process that has the DLL loaded must terminate or must cooperate and unload the DLL before the lock is released. At best you can rename the file while it is in use, that doesn't otherwise affect the process.
How can I unload a DLL from memory that belongs to another process, or the process had ended but the DLL is still loaded into memory?
I know how to find an existing process and even list all the loaded DLL's for that, but what I can't seem to get is how to find loaded DLL's and unload them from memory.
Everything I've read talks about AppDomains, but I'm not sure if this case would apply or not to that method since I want to close DLL's that aren't called by my app.
Any help would be appreciated.
I don't think you can unload a single assembly. But you can unload an AppDomain that contains the assembly.
A shared DLL loaded in domain neutral manner cannot be unloaded unless the Process is exited. Domain specific DLLs are unloaded alongwith Domain. There is however no way to unload individual DLLs even if the DLL has been loaded for reflection only.