Как использовать `/ DELAYLOAD` на DLL из другой DLL - PullRequest
0 голосов
/ 03 апреля 2019

У меня есть решение с двумя DLL.Первая - это «основная» DLL.Это драйвер ODBC, но я думаю, что это не важно для этого вопроса.Вторая DLL содержит всю логику пользовательского интерфейса для первого.Поскольку пользовательский интерфейс не всегда нужен, я хочу использовать функцию /DELAYLOAD, которая явно говорит:

Задержка загрузки DLL может быть указана во время сборки либо.EXE или .DLL проект.

Основной проект DLL правильно ссылается на пользовательский интерфейс.Если я не использую /DELAYLOAD, все работает просто отлично.Две DLL будут установлены в одном каталоге, поэтому я подумал, что загрузка одной DLL из другой должна быть легкой.Но, по-видимому, это не так.

Как только вызывается первая функция из UI DLL, приложение (любой клиент ODBC в моем случае) вылетает.GetLastError() дает 126, что, очевидно, означает, что целевая DLL не может быть найдена ни в одном из путей поиска.

И действительно, согласно этот ответ LoadLibrary() действительно рассматриваеткаталог вызывающего исполняемого файла, но не в каталог исполняемой в данный момент DLL.Я предполагаю, что /DELAYLOAD также просто использует LoadLibrary() под капотом, это правильно?

Если я копирую исполняемый файл в каталог установки моего драйвера, он работает просто отлично, что подтверждает мое предположениечто он просто не смотрит в текущую директорию DLL.

Судя по этому, я также смог запустить его, вызвав

LoadLibrary(L"C:\\absolute\\path\\to\\UI.dll");

непосредственно перед первой функцией пользовательского интерфейсаDLL загружена.Я также смог определить этот путь программно, используя

wchar_t buffer[512];
GetModuleFileName(hThisDLL, buffer, sizeof(buffer));

Но тогда мне пришлось бы покрывать каждый вызов интерфейса с помощью этой логики.Так что я бы не увидел больше преимуществ, чем у /DELAYLOAD, по сравнению с «старой школой», с использованием LoadLibrary() и GetProcAddress().

Вопрос

Есть ли простой способ заставить /DELAYLOAD найти целевую DLL из другой DLL в том же каталоге?

1 Ответ

1 голос
/ 03 апреля 2019

Есть.Мое предложение было бы создать функцию ловушки с задержкой при загрузке.

https://docs.microsoft.com/en-us/cpp/build/reference/failure-hooks?view=vs-2019

По сути, вы пишете функцию внутри своей основной DLL, которая получает уведомление в случае задержки загрузкиотказ.В этой функции, когда указанный код указывает на сбой, вы пытаетесь вручную вызвать LoadLibrary с путем, состоящим из папки, в которой находится ваша основная DLL, плюс имя DLL, которая не смогла загрузить

Как вы получаетеВаша основная DLL из вашей основной DLL зависит от вас.Есть много способов.

Примерно так:

FARPROC WINAPI delayHook(unsigned dliNotify, PDelayLoadInfo pdli)
{

    FARPROC fpRet = NULL;

    switch (dliNotify)
    {
      case dliStartProcessing:           
        break;

      case dliNotePreLoadLibrary:
        break;

      case dliNotePreGetProcAddress:
        break;

      case dliFailLoadLib: 
        {
            std::string newPath = GetMyModulePath();
            newPath += "\\";
            newPath  += pdli->szDll;
            fpRet = reinterpret_cast<FARPROC>(::LoadLibrary(csDir));
        }

        break;

      case dliFailGetProc:

        break;

      case dliNoteEndProcessing: 
        break;

      default:  
          break;
    }

    return fpRet;
}

//
// Set access to our delay load hook.
//

PfnDliHook __pfnDliFailureHook2 = delayHook;
...