Изменение пути поиска DLL для статически связанных DLL - PullRequest
11 голосов
/ 30 сентября 2010

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

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

Ответы [ 2 ]

17 голосов
/ 30 сентября 2010

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

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

  • Не статически связывать. Используйте LoadLibrary ("plugins / Plugin.dll") и GetProcAddress для доступа к содержимому плагина.
  • Добавьте «путь к папке с плагинами» в системную переменную среды PATH.
  • Используйте механизм отложенной загрузки для отсрочки доступа к функциональности плагинов, установите пользовательскую вспомогательную функцию , которая может загружать dll (и), используя предоставленный путь.
  • Превратите папку плагинов в сборку (создав в ней файл .manifest со списком plugin.dll). Добавьте «плагины» в качестве зависимой сборки в ваше приложение. Теперь он будет выглядеть в папке плагинов.
  • Разделите ваше приложение на исполняемый файл и динамически загружаемую часть. В заглушке 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 было именем сборки. Windows начинает поиск во встроенном файле манифеста информации о сборке.

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

#pragma comment(linker, "/manifestdependency:\"name='Plugins' "\
                        "processorArchitecture='*' version='1.0.0.0' "\
                        "type='win32'\"")
7 голосов
/ 15 апреля 2016

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


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


MSdocs

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

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

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

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

(...)

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

Пример

Вы получили верный старый исполняемый файл в папке с программой C:\Test\Program\app.exe и хотите - при Load-Time - загрузить файл 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) на моемТест системы, я пока не выяснил почему.(* a)

    То, что также работает , однако, встраивает / объединяет указанный ниже файл манифеста в исполняемый файл с помощью инструмента 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>
...