История
Поддържам плъгин за приложение. Използвам 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? Редактиране: Така е.
Коментарите ще бъдат високо оценени.
Благодаря!