Загрузка нескольких копий группы DLL в одном процессе - PullRequest
2 голосов
/ 02 мая 2010

Фон
Я поддерживаю плагин для приложения. Я использую Visual C ++ 2003.

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

  • plugin.dll -> utilA.dll, utilB.dll
  • utilA.dll -> utilB.dll
  • utilB.dll -> utilA.dll, utilC.dll

Вы получите изображение.

Некоторые из зависимостей между библиотеками DLL - время загрузки и время выполнения.

Все файлы DLL хранятся в каталоге исполняемого файла (не требуется, просто как он работает сейчас).

Проблема
Существует новое требование - запускать несколько экземпляров плагина в приложении.
Приложение запускает каждый экземпляр плагина в своем собственном потоке, то есть каждый поток вызывает функции, экспортируемые plugin.dll. Код плагина, однако, совсем не поточнобезопасен - множество глобальных переменных и т. Д.

К сожалению, исправление всего этого в настоящее время не вариант, поэтому мне нужен способ загрузить несколько (не более 3) копий библиотек DLL плагина в одном процессе.

Вариант 1: подход с использованием разных имен
Создание 3 копий каждого файла DLL, чтобы каждый файл имел свое имя. например plugin1.dll, plugin2.dll, plugin3.dll, utilA1.dll, utilA2.dll, utilA3.dll, utilB1.dll и т. д. Приложение загрузит plugin1.dll, plugin2.dll и plugin3.dll. Файлы будут в каталоге исполняемого файла.

Чтобы каждая группа DLL знала друг друга по имени (чтобы работали взаимозависимости), имена должны быть известны во время компиляции - это означает, что библиотеки DLL должны быть скомпилированы несколько раз, только каждый раз с другим выходным файлом. имена.

Не очень сложно, но я бы не хотел иметь 3 копии файлов проекта VS и не хотел бы собирать одни и те же файлы снова и снова.

Вариант 2: сближение сборочных узлов
Создайте 3 копии файлов DLL, каждая группа в своем собственном каталоге, и определите каждую группу как сборку, поместив файл манифеста сборки в каталог со списком DLL плагина.
Каждая DLL будет иметь манифест приложения, указывающий на сборку, так что загрузчик найдет копии служебных DLL, которые находятся в том же каталоге. Манифест должен быть встроен, чтобы его можно было найти при загрузке DLL с использованием LoadLibrary. Я буду использовать mt.exe из более поздней версии VS для этой работы, поскольку VS2003 не имеет встроенной поддержки встраивания манифеста.

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

Редактировать: Работает с ISOLATION_AWARE_ENABLED, как и ожидалось - загрузка DLL во время выполнения использует исходный контекст активации загружаемой DLL.

Вопросы
Есть другие варианты? Подойдет любое быстрое и грязное решение. : -)

Будет ли ISOLATION_AWARE_ENABLED работать даже с VS2003? Редактировать: Да.

Комментарии будут высоко оценены.

Спасибо!

1 Ответ

0 голосов
/ 02 мая 2010

ISOLATION_AWARE_ENABLED реализован в заголовочных файлах Windows SDK и поэтому, вероятно, вообще не стоит VS2003. Тем не менее, можно загрузить последнюю версию Windows 7 SDK и использовать ее с VS2003.

Вам не нужно использовать MT для связи в манифестах. Манифесты могут быть встроены в качестве ресурсов в средах, которые не имеют явных знаний.

Добавьте следующее в файл .rc dll, чтобы встроить манифест. (С достаточно недавней платформой sdk RT_MANIFEST уже должен быть определен):

#define RT_MANIFEST 24 
#define APP_MANIFEST 1
#define DLL_MANIFEST 2

DLL_MANIFEST RT_MANIFEST dllName.dll.embed.manifest
...