Изменение пути поиска DLL для статической связанной DLL

Я искал любые подсказки, как я могу это сделать, но все, что я нашел, - это перенаправить SxS DLL в локальную папку приложения. Вот что я хочу сделать: (С++) Application.exe связан с DLL, Plugin.DLL(зависимым проектом). Эта DLL не помещается внутри каталога приложения, а находится в подпапке под названием "плагины". Поскольку DLL статически связана, приложение попытается загрузить его из папки приложения.

Есть ли способ изменить путь поиска для этой DLL? Либо через манифесты, либо в компоновку компоновщика VS2008?

Ответ 1

Моя первая мысль: если вы статически связываете dll, это не плагин. Просто поместите dll в папку EXE и сделайте это. Это конфигурация развертывания, поддерживаемая Windows для статически загружаемых DLL.

Тем не менее, есть способы добиться того, чего вы хотите. Но они в основном глупы или сложны без уважительной причины: ваши варианты:

  • Не статически связывать. Используйте LoadLibrary ( "plugins/Plugin.dll" ) и GetProcAddress для доступа к содержимому плагина.
  • Добавьте "путь к вашей папке плагинов" в переменную среды системы PATH.
  • Используйте механизм загрузки задержки для задержки доступа к функциям плагинов, установите настраиваемую вспомогательную функцию, которая может загружать dll (ы), используя предоставленную путь.
  • Поверните папку плагинов в сборку (создав в ней файл .manifest, в котором содержится список plugin.dll). Добавьте "плагины" в качестве зависимой сборки к вашему приложению. Теперь он будет выглядеть в папке плагинов.
  • Разделите приложение на заглушку exe и динамически загруженную часть. В заглушке exe вызовите SetDllDirectory, чтобы указать на папку плагина, затем вызовите LoadLibrary, передав полный путь к "appstub.dll".

Чтобы превратить папку с одной или несколькими DLL в "сборку", просто добавьте файл в папку с папками name.manifest.

Итак, plugins.manifest: -

<assembly manifestVersion="1.0">
  <assemblyIdentity type="Win32" name="Plugins" version="1.0.0.0" processorArchitecture="x86" />
  <file name="Plugin.dll"/>
</assembly>

ОЧЕНЬ хорошая идея обеспечить, чтобы имя папки и DLL было иным, как если бы имя DLL было именем сборки, окна начинают искать свой встроенный файл манифеста для получения информации о сборке.

Предполагая, что вы используете Visual Studio 7 или более позднюю версию, следующая директива, добавленная в файл .c/.cpp или .h в проекте, затем сделает попытку вашего приложения загружать DLL из сборки, а не только в локальный каталог:

#pragma comment(linker, "/manifestdependency:\"name='Plugins' "\
                        "processorArchitecture='*' version='1.0.0.0' "\
                        "type='win32'\"")

Ответ 2

Расширение и подробное описание предложения Криса подкаталога "assembly":


Боковое примечание: у Криса также есть две отличные записи с более подробной информацией:


MS docs

На самом деле это называется "Private Assembly" , и MS docs объясняют это следующим образом:

Частные сборки устанавливаются в папке приложения структура каталогов. Как правило, это папка, содержащая исполняемый файл приложения. Частные сборки могут быть развернуты в той же папке, что и приложение, в папке с тем же именем, что и сборка или в поддиректории, специфичной для языка с тем же именем как сборка.

Например (...)

Appdir\Microsoft.Tools.Pop\Microsoft.Tools.Pop.MANIFEST: манифест развертывается как отдельный файл в подпапке с именем сборки.

(...)

Частные сборки могут быть установлены любым способом установки, который может скопировать файл сборки в эту папку, например команду xcopy.

Пример

У вас есть надежный старый исполняемый файл в папке с программой C:\Test\Program\app.exe, и вы хотите - при загрузке - загрузите свой DLL файл из подпапки Plugins, т.е. C:\Test\Program\plugins\tool1.dll, не войдя в PATH или любой другой материал.

Вам необходимо:

  • Скомпилируйте app.exe с помощью:

    #pragma comment(linker, "/manifestdependency:\"name='Plugins' version='1.0.0.0' type='win32'\"")
    // name, type and version seems to be the minimum info to get away with
    

    Примечание: Компиляция/связывание этого, вместо использования внешнего манифеста (app.exe.manifest) требуется в моей тестовой системе, я пока не узнал, почему. (* А)

    Однако также работает вложение/слияние файла манифеста, указанного ниже, в исполняемый файл с помощью инструмента mt, а не с помощью компоновщика. (Configuration > Manifest Tool > Additional Manifest Files)

  • Вставьте tool1.dll вставьте подпапку Plugins

  • добавить файл plugins.manifest в подпапку плагинов, т.е. C:\Test\Program\plugins\plugins.manifest, и это выглядит следующим образом:

plugins.manifest:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <assemblyIdentity
                            type="win32"
                            name="Plugins"
                            version="1.0.0.0"
            />
    <file name="tool1.dll"/>
</assembly>

Что это. Запуск app.exe автоматически найдет dll в подпапке в режиме загрузки.


(* a): Слияние этого файла манифеста работает, но вы не можете использовать его в качестве единственного внешнего файла манифеста, и я подозреваю, что он пропускает всю другую информацию о манифесте, которую система сборки уже вставляет в ваш исполняемый файл!

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <dependency>
        <dependentAssembly>
            <!-- Note: type: The value must be win32 and all in lower case. Required. --> 
            <!-- Note: version: The value must be win32 and all in lower case. Required. --> 
            <assemblyIdentity
                                    type="win32"
                                    name="plugins"
                                    version="1.0.0.0"
            />
        </dependentAssembly>
    </dependency>
</assembly>