Вы не просите чего-то очень элементарного. Windows просто не поддерживает то, что вы хотите.
У вас есть несколько вариантов решения этой проблемы:
- Создать две библиотеки DLL. Ваша реализация плагина dll, которая статически связывается с любыми другими dll, которые вам нужны. И простая "фасадная" dll, которая загружается приложением хостинга. Фасадная библиотека DLL вызывает метод SetDllDirectory, затем LoadLibrary для загрузки вашей библиотеки реализации с требуемым путем поиска, а затем для каждой экспортируемой функции плагина реализует функцию-заглушку, которая использует GetProcAddress, чтобы просто передать вызов прямо в вашу библиотеку реализации.
Если интерфейс плагина сложный, а используемый вами интерфейс dll - нет, то:
Откажитесь и просто используйте LoadLibrary (с явным путем) и GetProcAddress, чтобы получить доступ к функциональности ваших спутниковых DLL. Боль.
Последний вариант наименее документирован и наиболее плохо понимается программистами Windows. В основном мы используем версию технологии Windows, созданную для поддержки сборок .NET: Side by Side. Не пугайся «Сборка бок о бок» - это просто обычная старая dll, но с сопровождающим файлом .manifest, который предоставляет некоторую дополнительную информацию о ней.
Причина, по которой мы хотим это сделать, заключается в том, что порядок поиска DLL-файлов, связанных с помощью технологии SxS, отличается от обычного порядка поиска DLL: - А именно - после поиска c: \ windows \ WinSxS окна будут искать то же самое папка как dll, которая ссылается на dll, а не на папку exe.
Начните с инвентаризации всех dll-сателлитов, к которым должен подключиться dll-плагин, и создайте из них «сборку». Что означает: создать файл .manifest с кучей файлов = узлов. Вам необходимо дать имя сборке. Давайте назовем это «MyAssembly».
Создайте файл «MyAssembly.manifest» в папке вашего dll, содержимое которого будет примерно таким: (перечисляя каждый из dll, который вам нужно включить)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity name="MyAssembly" processorArchitecture="*" type="win32" version="1.0.0.1"/>
<file name="firstrequireddll.dll"/>
<file name="2ndrequireddll.dll"/>
</assembly>
Теперь это ваш манифест сборки . Мы наполовину закончили.
Следующая половина состоит в том, чтобы на самом деле заставить вашу dll использовать сборку, и для этого вам нужно добавить ресурс манифеста в ваш файл Dll. В конечном итоге этот манифест должен содержать следующее содержание: -
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="MyAssembly" version="1.0.0.1" processorArchitecture="*"/>
</dependentAssembly>
</dependency>
</assembly>
Очевидно, что манифесты приложения (которые вводят в заблуждение при вводе в dll), также могут использовать узел <file>
, поэтому можно пропустить создание сборки и просто перейти с
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<file name="firstrequireddll.dll"/>
<file name="2ndrequireddll.dll"/>
</assembly>
как манифест длл. Я еще не играл с этой итерацией, поэтому я не уверен, как это изменит нормальный путь поиска DLL (если вообще).
Не зная вашей среды разработки, сложно понять, как посоветовать вам, как добавить манифест в dll. Если вы редактируете файл .rc и вводите манифест вручную, знайте, что в Dlls идентификатор ресурса для использования равен 2, а не 1, что обычно используется в примерах exe.
Если вы используете DevStudio 2005 или выше, есть удобная директива #pragma, которая заставит все магически иметь правильные идентификаторы и быть в правильных местах.
Если в настройках проекта установлены значения по умолчанию, VS2005 и выше автоматически сгенерируют и при необходимости вставят манифест. эта #pragma добавит дополнительные зависимости сборки
в сгенерированный манифест: -
#if _MSC_VER >= 1400 // VS2005 added this directive
#pragma comment(linker, \
"\"/manifestdependency:type='Win32' "\
"name='Company.Product.Subsystem' "\
"version='6.0.0.0' "\
"processorArchitecture='*' "\
"language='*'\"")
#endif