Динамическая загрузка C ++ / CLI .dll (и зависимостей) в смешанном режиме из неуправляемого c ++ - PullRequest
5 голосов
/ 10 августа 2011

У меня есть управляемая сборка C ++, которую я загружаю динамически в неуправляемом приложении c ++ через стандартный вызов LoadLibrary (). Управляемая сборка C ++ зависит от нескольких других управляемых (C #) сборок. Все работало нормально, пока я не переместил все управляемые сборки в подкаталог не исправленного приложения. Для иллюстрации:

  • Управляемый C ++ .dll (MyCoolDll.dll)

    • Зависит от DotNetDll1.dll
    • Зависит от DotNetDll2.dll
  • Неуправляемое приложение C ++ (MyCoolApp.exe)

    • Загружает MyCoolDll.dll через LoadLibrary ("MyCoolDll.dll")

Это работало нормально, пока я не переместил MyCoolDll.dll, DotNetDll1.dll и DotNetDll2.dll в / someSubDirectory (код в MyCoolApp.exe обновлен до LoadLibrary ("someSubDirectory / MyCooldll.dll")

Я предполагаю, что при загрузке MyCoolDll.dll он пытается найти DotNetDll1.dll и DotNetDll2.dll в рабочем каталоге, а не в каталоге, в котором он находится.

Как я могу сказать MyCoolDll.dll, что его зависимости живут в подкаталоге? Это библиотека, работающая внутри неуправляемого приложения, так что я не думаю, что смогу указать это в app.config или что-нибудь еще?

Ответы [ 2 ]

8 голосов
/ 11 августа 2011

Я думаю, что вы ищете, это пользовательский распознаватель сборки. Мне пришлось использовать один, чтобы сделать то, что, как я думаю, вы пытаетесь сделать - я хотел найти некоторые библиотеки DLL в папке, которой не было в дереве исходной неуправляемой библиотеки DLL (которая в конечном итоге загружала управляемый код). *

Шаг 1 состоит в создании функции, которую вы можете вызвать для настройки распознавателя:

void PrepareManagedCode()
{
    // Set up our resolver for assembly loading
    AppDomain^ currentDomain = AppDomain::CurrentDomain;
    currentDomain->AssemblyResolve += gcnew ResolveEventHandler(currentDomain_AssemblyResolve);
}  // PrepareManagedCode()

Тогда резольвер. В этом примере есть глобальный ourFinalPath, который в вашем случае будет дополнительной папкой, которую вы использовали:

/// <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;
}
5 голосов
/ 11 августа 2011

В этом сценарии CLR загружается необычным образом, через thunk, который компилятор вставил при компиляции собственного экспорта для __declspec (dllexport). Делать это хорошо, просто не особо быстро.

CLR отправится на поиски файла .config для инициализации основного домена приложения. И будет искать MyCoolApp.exe.config, независимо от того, что это вообще не управляемый исполняемый файл. Вы можете использовать элемент <probing> для добавления подкаталогов для поиска сборок.

...