Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
I have a managed C++ assembly I'm loading dynamically in an unmanaged c++ application through a standard LoadLibrary() call. The managed C++ assembly has dependencies on several more managed (C#) assemblies. Everything worked fine until I moved all the managed assemblies to a subdirectory of the unmananged application. To illustrate:
Managed C++ .dll (MyCoolDll.dll)
Dependent on DotNetDll1.dll
Dependent on DotNetDll2.dll
Unmanaged C++ app (MyCoolApp.exe)
Loads MyCoolDll.dll via LoadLibrary("MyCoolDll.dll")
This worked fine, until I moved MyCoolDll.dll, DotNetDll1.dll & DotNetDll2.dll to /someSubDirectory (the code in MyCoolApp.exe was updated to LoadLibrary("someSubDirectory/MyCooldll.dll")
I'm guessing when MyCoolDll.dll is loaded, it's trying to find DotNetDll1.dll and DotNetDll2.dll in the working directory, instead of the directory it lives in.
How can I tell MyCoolDll.dll its dependencies live in a subdirectory? It's a library running inside of an unmanaged app, so I don't think I can specify this in an app.config or anything?
–
I think what you're looking for is a custom assembly resolver. I had to use one to do what I think you are trying to do -- I wanted to locate some of the DLLs in a folder that wasn't in the tree of the initial unmanaged DLL (which loaded managed code eventually).
Step 1 is to make a function you can call to set up the resolver:
void PrepareManagedCode()
// Set up our resolver for assembly loading
AppDomain^ currentDomain = AppDomain::CurrentDomain;
currentDomain->AssemblyResolve += gcnew ResolveEventHandler(currentDomain_AssemblyResolve);
} // PrepareManagedCode()
Then the resolver. This example has a global ourFinalPath which would in your case be the extra folder you were using:
/// <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;
finalPath = gcnew String(ourAssemblyPath) + args->Name->Substring(0, args->Name->IndexOf(",")) + ".dll";
Assembly^ retval = Assembly::LoadFrom(finalPath);
return retval;
catch (...)
return nullptr;
–
–
–
–
–
The CLR gets loaded in an unusual way in this scenario, through a thunk that the compiler injected when compiling the native export for __declspec(dllexport). Doing this is fine, it just isn't particularly fast.
The CLR will go out hunting for a .config file to initialize the primary AppDomain. And will look for MyCoolApp.exe.config, regardless that this is not a managed executable at all. You can use the <probing>
element to add subdirectories to search for assemblies.
I had this problem, but also a catch-22 in that my managed C++ DLL would immediately crash because it directly referenced the .NET DLLs that it could not find. I could not even call any .NET code at all, so Ed's solution did not initially work for me.
The trick was to create a second managed C++ DLL, with no references to any special .NET DLLs. Without these references it loads fine. In that second DLL, run Ed's code to set up the assembly resolver. Then load the problematic, managed C++ DLL, as before, and it works fine.
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.