If I host CLR in my C++ executable, is there any way to set base directory of default AppDomain to something other than location of the executable?
Here's why I need it. I have a rather complex application that loads .NET plugins using a plugin loader executable, PluginBox.exe. The plugins are located outside of the main application folder. We run one instance of PluginBox.exe per plugin.
Currently PluginBox.exe is written in C++. I want to convert it to a managed app. PluginBox uses unmanaged CLR hosting (ICLRMetaHost, ICLRRuntimeInfo, etc.), and locates plugin assemblies by implementing IHostAssemblyStore interface. There is only one AppDomain, and its base directory is the application directory. When searching for assemblies, CLR invokes the assembly store before looking at the application base directory. So, if the plugin and the main app contain an assembly with the same name, the assembly store can load the plugin-specific version.
As a first step towards making PluginBox.exe managed, I would like to get rid of the assembly store and replace it with an assembly resolver. The trouble is, unlike assembly store, assembly resolver is called after the application base directory has been considered. So, if the plugin and the main app contain an assembly with the same name, main app's assembly wins. This disrupts plugin execution.
I would like to switch base directory of the hosted CLR to where the plugin is located. So far, I found only two ways to do that, both of them unacceptabe: move PluginBox.exe to the plugin directory, or create a second AppDomain, which is problematic for a variety of internal reasons. This is a huge application with a lot of history, and any drastic moves are bound to cause problems.
Any thoughts and ideas are appreciated.
PS. Current CLR version is 4.0.
Related
I never understand , What actually happens to the the external DLLs when code is compiled by the compiler and converted to Intermediate code to run on CLR.
Does DLL code added to the Intermediate code and the references are not longer needed on the new machine or just the path of added DLLs are stored and we need those DLLs on our drive to run the program.
Generally (ie. there are some exceptions) the referenced assembly needs to be on the deployment system. All that is included in your assembly is the assembly name (this includes version and possibly signature).
Assembly binding (involving the GAC, config overrides etc.) is applied at runtime to get the right assembly. The rules depend on how the app domain was set up (eg. extra folders can be added, which is why ASP.NET web apps apply different rules).
There are various cases where the reference can be embedded (including referencing ActiveX when the right options are set and use of the assembly binding tool).
I'm creating a .NET assembly with a COM interface. Ideally I'd like to have registry keys separated from the assembly so performing a release only needs to drop a .dll on a shared drive (rather then needing to push out an MSI each time)
I created different classes that inherited from the main class to get different GUIDs for each environment.
However when I test this the first version loaded (eg. development) ends up servicing calls for the other environments (eg. test) later on. This wouldn't normally be a problem but when used this component is called from an all day running GUI executable. Conceivably people could be running different environments throughout the day.
Each interface has an independent codebase set in the registry (no GAC) and the process monitor shows that both assemblies are loaded yet only the first is used. I presume that's because .NET is seeing the same class/assembly name and reusing the first one loaded.
How I can isolate the assemblies in this situation?
You can strong name the assemblies ("signing" tab in project properties in Visual Studio, not to be confused with Authenticode signing) and change either the version number, public key or both for the different versions/environments. This way the CLR assembly loader will consider them different and will not bind to the one that's already been loaded in the given context.
I'm writing a plug-in for a 3rd party application (.NET). This application lets me choose the plug-in (as a .dll library file) to load. However, if I have two versions of the same library---they have the same name but are in different directories---and try to load one after the other, it only loads the first plug-in and treats the second as if it was the first. In other words, if the first plug-in is supposed to show a message box saying "First plug-in" and the second plug-in is supposed to show a message box saying "Second plug-in," then loading the second plug-in after the first will actually show a message saying "First plug-in" (i.e., the second plug-in was actually never loaded).
After searching and reading online, I believe that the problem is that the 3rd party application loads its plug-ins into its primary AppDomain. Therefore, plug-in libraries are never unloaded (become locked?) and subsequent attempts to load a plug-in with the same name simply uses the library that's already been loaded. I thought perhaps signing my plug-in libraries would fix the problem, but unfortunately, I'm unable to sign them because I depend on a .dll provided by the 3rd party application and it is not signed. Also, I cannot change the 3rd party application's config file, so I cannot play around with probing.
Our current solution is to re-name the assembly for every version of the plug-in library we have (for example, "PlugIn-1.0.dll" and "PlugIn-2.0.dll"), including re-naming all their dependent assemblies. I don't mean just changing their file name, but changing the AssemblyName property and re-compiling. This works, but I'd like to see if there's a cleaner solution. It wouldn't be so bad if it was just the plug-in assembly name we had to change, but we are also forced to change all their dependent .dll's (because different plug-ins may use different versions of these .dll's as well). I tried creating a config file for the plug-in library to change the probing directory, but this doesn't work. It looks like it is the application itself that does the probing, not the library that depends on the .dll's (am I correct in inferring this?)
Finally, I tried having my plug-in create an AppDomain and load its dependent .dll's into it, but unfortunately my plug-in directory location (and dependent .dll's) must be on a remote location relative to the 3rd party app. There are security/permission issues with loading assemblies over network locations in .NET 4.0 (which I'm using) that I haven't been able to solve.
What are my options? Thanks in advance.
I think you're knocking on the right door with spinning up your own AppDomain. That is the only way I know of to have different versions of the same assembly loaded into the same process.
And yes - as soon as a .NET appdomain has loaded an assembly, it will not load another version of that assembly. Whoever is first wins. And of course, there is no way to unload an assembly once it has been loaded.
As for your permission issues.. Can you copy the assemblies from that network location to a user folder (where the user has write permissions) and load them from there? I've been able to do this successfully for an auto-updating application.
I have a wcf service referencing a dll. Only way it works is by placing the dll in %windir%/system32 folder.
Things I have tried
tried switching between iis express, development server and iis (but this is irrelevant)
placing the dll in the bin folder and/or other application folders
trying to use the "regsvr32" util but the dll is not a com dll so it does not work.(no ddl entry point)
It is not a .NET dll so I don't think GAC can be manipulated to work with this
played with the system path variable without any success
What I actually want
A simpler method to access the dlls so I do not have to place the dll in system32 but contain it in an application folder and access it from there.
What am I missing?
EDIT:
I did find this post interesting and similar but again, it also uses the system32 method which is not the way to go.
If this is a win32 native library, you can "preload" it from a known location using pinvoked LoadLibrary passing a full path of your library as a parameter, somewhere early in your processing pipeline.
When any method from the library decorated with DllImport is called, the runtime will try to load the library (and would fall because the dll cannot be found) but since you preloaded it eariler, loading will succeed (loader checks the library file name, doesn't pay any attention to the directory the library is loaded from).
I've created and registered a managed COM library in C# on my development machine. I've successfully registered it and created a .tlb file with regasm, and successfully imported the tlb into a c++ console app used for testing.
My COM assembly is called "efcAPI.dll" and it references another assembly that has not been set up for COM or registered in anyway called "efcServerDiscovery.dll". This second dll contains some code used by my COM dll and exists in the same folder as efcAPI.dll.
Everything concerning loading the COM assembly works fine. I can create instances of my classes defined in the COM and call methods from them. However when I call certain methods that use the code defined in efcServerDiscovery.dll I get a _com_error which reports that it could not load file or assembly 'efcServerDiscovery'.
I've verified that everywhere on my hard drive where efcAPI.dll exists there's a copy of efcServerDiscovery.dll (which is just the location I built and registered efcAPI.dll from). I've also attempted to place efcAPI.dll and efcServerDiscovery.dll in the same directory as the c++ app with no success.
Any suggestions as to where the c++ app is looking for the assembly or how to discover where it's looking would be great!
Yes, this is a problem with COM components having non-COM dependencies. Windows doesn't consider the location of the COM DLL when it searches for dependent DLLs. The normal search rules are in effect, the folder that contains the EXE first, Windows directories, current working directory, PATH environment. The location of the COM server does not play a role.
Assuming you don't want to deploy to the EXE folder, none of these are good places to store your DLL, although plenty of installers made the desperation move of storing it in c:\windows\system32 or modify the system PATH environment variable.
One thing you could do is P/Invoke SetDllDirectory() in your C# code before running any code in the DLL. Using Assembly.GetExecutingAssembly().Location will do it. That is however not a safe thing to do though, it might alter the search rules for the app that uses your component.
The only real fix is to install the DLL in the Windows side-by-side cache (WinSxS) and to include a manifest in your C# executable. Given the state of the documentation, I can only wish you the best of luck.
In these situations i always start with Dependency Walker verifying that what & where its trying to load is what i think it is.
fuslogvw will tell you where the CLR is looking for assemblies
Or use GAC.
(here are your characters, stackoverflow)