Loading Mixed-Mode C++/CLI .dll (and dependencies) dynamically from unmanaged c++

江枫思渺然 提交于 2019-11-29 22:13:29

问题


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?


回答1:


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.




回答2:


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;
    try
    {
        finalPath = gcnew String(ourAssemblyPath) + args->Name->Substring(0, args->Name->IndexOf(",")) + ".dll";
        Assembly^ retval = Assembly::LoadFrom(finalPath);
        return retval;
    }
    catch (...)
    {
    }

    return nullptr;
}


来源:https://stackoverflow.com/questions/7016663/loading-mixed-mode-c-cli-dll-and-dependencies-dynamically-from-unmanaged-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!