I developed a DLL in Managed C++ which loads some plugins (implemented in any .NET language) at runtime using System.Reflection.Assembly.LoadFile. The interface which is implemented by all plugins is implemented in C#. It's used by the Managed C++ code like this:
#using <IMyPluginInterface.dll> // Make the 'IMyPluginInterface' type available
ref class PluginManager {
List<IMyPluginInterface ^> ^m_plugins;
// Load all plugins in a well-known directory.
void load() {
for ( string dllFile in Directory.GetFiles( .., "*.dll" ) ) {
// Lookup the type of the plugin object using Reflection
Type pluginType = ...;
// Finally, instantiate the plugin and add it to our list.
m_plugins.Add( (IMyPluginInterface ^)Activator.CreateInstance( pluginType ) );
}
}
}
Loading the plugins works well; the problem I'm facing is that at runtime, the IMyPlugnInterface.dll
file might not be in the same directory as the Managed C++ DLL. This means that the 'IMyPluginInterface' type is not available at runtime, and an exception is thrown.
I previously asked whether it was maybe possible to influence the lookup path used when resolving DLLs referenced via the #using
statement. Unfortunately, this didn't yield any result.
Is there maybe a different approach to this? Can types which are referenced via #using
be compiled into the Managed C++ DLL? Maybe anybody else has an entirely different solution?
You can use several options - if you know in advance where the assembly will be located, you can add that path to your application's configuration file:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="MyPath"/>
</assemblyBinding>
</runtime>
</configuration>
If you want to search for the assembly at runtime, you can implement a handler for AppDomain::CurrentDomain->AssemblyResolve
event:
ref class AssemblyResolver
{
public:
/// The path where the assemblies are searched
property String^ Path
{
String^ get()
{ return path_; }
}
explicit AssemblyResolver(String^ path)
: path_(path)
{ /* Void */ }
Assembly^ ResolveHandler(Object^ sender, ResolveEventArgs^ args)
{
// The name passed here contains other information as well
String^ dll_name = args->Name->Substring(0, args->Name->IndexOf(','));
String^ path = System::IO::Path::Combine(path_, dll_name+".dll");
if ( File::Exists(path) )
return Assembly::LoadFile(path);
return nullptr;
}
private:
String^ path_;
};
and you can wire it using something like this:
AssemblyResolver^ resolver = gcnew AssemblyResolver(path);
AppDomain::CurrentDomain->AssemblyResolve += gcnew ResolveEventHandler(
resolver,
&AssemblyResolver::ResolveHandler
);
Just make sure this is done before calling any methods that may use types from the assembly that has to be resolved.
Is it not the standard .net assembly resolution strategy? See here for a detailed introduction.
来源:https://stackoverflow.com/questions/1503266/how-do-i-change-the-lookup-path-for-net-libraries-referenced-via-using-in-mana