Изменение пути поиска 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>