Здравствуйте, Rakafon, Вы писали:
R>Так вот ... могу ли я в этот механизм внести свои изменения/дополнения ...? Может быть с помощью манифестов ...? Ведь в манифестах прописывают инфу о том где искать CRT-шные DLL-ки, какую версию Common Controls подгружать и так далее ... Но скока я не рыл по поводу манифестов, везде инфа только о том как подключать Shared DLL типа msvcr**.dll, msvcp**.dll, atl**.dll, cmnctrls.dll, настраивать security, и так далее, а вот толкового мануала о том, что за инфу вообще можно запихать в манифест, как можно ссылаться там на сторонние DLL модули и пр., никак и нигде найти не могу ...
R>Я просто хочу чтоб все DLL приложения не располагались в одном каталоге, а были распределены по логическим подпапкам, при этом понятно связывались с EXE статически, а не динамически, существовали в единственном экземпляре каждая, не была засрана переменная Path и т.д.
R>Коллеги, не знаете как это можно забабахать? Можно ли это сделать с помощью манифестов?
Можно. Манифесты это только верхушка айсберга под названием isolated applications & side-by-side assemblies (не путать со сборками дотнета). Это решение прдлагается MS для уменьшения конфликтов версий, избавления от DLL-hell'а, и прочих подобных аспектов (в частности это замена механизма DLL/COM redirection).
Терминология:
Isolated application — это обычное приложение, которое 'изолировано' от возможных изменений каких-либо внешних компонентов.
Side-by-side assembly (сборка) — один файл (обычная DLL, COM-сервер, библиотека типов) или группа файлов.
* Сборка может быть установлена как private — для использования только одним приложением. Такая сборка устанавливается в папку с приложением.
* Сборка может быть установлена как shared — такие сборки хранятся в папке %windir%\WinSxS и доступны для использования любыми приложениями. Shared сборка обязательно должда быть подписанной. Private сборка также может быть подписана (но это не обязательно).
Манифесты соответственно делятся на два типа — манифесты для приложений (или компонентов) и манифесты для сборок. Манифесты первого типа описывают (в том числе) зависимости от сборок. Манифесты второго типа описывают (в том числе) содержимое сборок.
Для решения поставленной задачи нужно: собрать private сборку — сначала производится сборка всех компонентов, в нашем случае это один dll-файл (пусть будет TestDLLStatic.dll) Компилируется как обычная dll-библиотека (возможно она будет обладать своим манифестом, но это не важно).
Каждая сборка должна иметь имя, по которой ее можно идентифицировать. Этим именем так же будет названа папка, в которой хранится содержимое сборки (в MSND есть описание алгоритма поиска сборок, там учитываются и другие случаи, вроде название локали). Также нужен манифест для описания содержимого. Пусть именем будет 'MyDll', тогда манифест может иметь следующую структуру:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<noInheritable/>
<assemblyIdentity type="win32" name="MyDll" version="1.0.0.0" processorArchitecture="x86" />
<file name="TestDLLStatic.dll" />
</assembly>
Т.е. список файлов (их может быть несколько), имя, версия и т.п. Подробный список разрешенных атрибутов есть в MSDN. Атрбут publicKeyToken отсутствует (это важно), т.к. сборку мы не будем подписывать.
Теперь структура папок:
TestDLLHost.exe (это приложение будет использовать нашу сборку)
MyDll - папка
|- MyDll.manifest - манифест, описанный выше
\- TestDLLStatic.dll
Название папки и файла-манифеста должны быть такими же как и атрибут 'name' используемый в манифесте.
Теперь о том как использовать эту сборку: для приложения TestDLLHost.exe должен существовать свой манифест, в котором нужно указать завивимость от нашей сборки: Такой манифест может быть внешним (отдельный файл) или внедренным. MS Visual Studio по умолчанию (правда не помню с какой версии) использует внедренный манифест — в таком случае можно воспользоваться директивой 'pragma' (в cpp файле):
#pragma comment(linker, "\"/manifestdependency:type='Win32' name='MyDll' version='1.0.0.0' processorArchitecture='X86'\"")
Это приведет к тому что в секцию dependency/dependentAssembly получившегося манифеста будет добавлена зависимость от собрки MyDll:
<dependency>
<dependentAssembly>
<assemblyIdentity type='win32' name='MyDll' version='1.0.0.0' processorArchitecture='x86' />
</dependentAssembly>
</dependency>
Важно — требуется полное совпадение атрибутов, используемых в 'pragma' и атрибутов в сборке, т.е. type/version/processorArchitecture. Если автоматическая генерация манифестов выключена и используется внешний манифест, то в него необходимо добавать секцию dependency вручную. Все.
Hint: Файлы из MSVC CRT инсталлируются в качестве shared сборки, но ее можно превратить в private и носить с собой (release версию) — таким образом не нужно при установке проверять наличие соответствующей версии (и устанавливать в случае необходимости). Как это делается: В папку с приложением копируется папка из (например) '<X>:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86' — 'Microsoft.VC90.CRT':
TestDLLHost.exe
Microsoft.VC90.CRT (папка)
|- msvcm90.dll
|- msvcp90.dll
|- msvcr90.dll
\- Microsoft.VC90.CRT.manifest
После этого в файле 'Microsoft.VC90.CRT.manifest' необходимо удалить атрибут publicKeyToken. После чего на нее нужно сослаться из манифеста приложения, добавив секцию dependency/dependentAssembly (но уже без атрибута publicKeyToken).
Но нужно понимать, что если приложение будет иcпользовать другую dll и эта dll будет использовать CRT из shared сборки, то фактически в процессе окажется две копии runtim'a со всеми вытекающими последствиями.