我有一个托管C ++程序集,我通过标准的LoadLibrary()调用在非托管c ++应用程序中动态加载。托管C ++程序集依赖于几个托管(C#)程序集。一切正常,直到我将所有托管程序集移动到unmananged应用程序的子目录。举例说明:
托管C ++ .dll(MyCoolDll.dll)
非托管C ++应用程序(MyCoolApp.exe)
这很好,直到我移动MyCoolDll.dll,DotNetDll1.dll& DotNetDll2.dll到/ someSubDirectory(MyCoolApp.exe中的代码已更新为LoadLibrary(“someSubDirectory / MyCooldll.dll”)
我猜测何时加载了MyCoolDll.dll,它试图在工作目录中找到DotNetDll1.dll和DotNetDll2.dll,而不是它所在的目录。
如何告诉MyCoolDll.dll其依赖项存在于子目录中?它是一个在非托管应用程序内部运行的库,所以我认为我不能在app.config或其他任何东西中指定它?
答案 0 :(得分:8)
我认为您正在寻找的是自定义装配解析器。我不得不使用一个来做我认为你想做的事情 - 我想在一个文件夹中找到一些DLL,这个文件夹不在最初的非托管DLL(最终加载托管代码)的树中。
步骤1是创建一个可以调用以设置解析器的功能:
void PrepareManagedCode()
{
// Set up our resolver for assembly loading
AppDomain^ currentDomain = AppDomain::CurrentDomain;
currentDomain->AssemblyResolve += gcnew ResolveEventHandler(currentDomain_AssemblyResolve);
} // PrepareManagedCode()
然后是解析器。这个例子有一个全局的myFinalPath,在你的情况下是你正在使用的额外文件夹:
/// <summary>
/// This handler is called only when the CLR tries to bind to the assembly and fails
/// </summary>
/// <param name="sender">Event originator</param>
/// <param name="args">Event data</param>
/// <returns>The loaded assembly</returns>
Assembly^ currentDomain_AssemblyResolve(Object^ sender, ResolveEventArgs^ args)
{
sender;
// If this is an mscorlib, do a bare load
if (args->Name->Length >= 8 && args->Name->Substring(0, 8) == L"mscorlib")
{
return Assembly::Load(args->Name->Substring(0, args->Name->IndexOf(L",")) + L".dll");
}
// Load the assembly from the specified path
String^ finalPath = nullptr;
try
{
finalPath = gcnew String(ourAssemblyPath) + args->Name->Substring(0, args->Name->IndexOf(",")) + ".dll";
Assembly^ retval = Assembly::LoadFrom(finalPath);
return retval;
}
catch (...)
{
}
return nullptr;
}
答案 1 :(得分:5)
在这种情况下,CLR以不寻常的方式加载,通过编译器在编译__declspec(dllexport)的本机导出时注入的thunk。这样做很好,它不是特别快。
CLR将寻找.config文件以初始化主AppDomain。并且将查找MyCoolApp.exe.config,无论这根本不是托管可执行文件。您可以使用<probing>
element添加子目录来搜索程序集。