DLL-Связывание. Поиск DLL. Манифесты.
От: Юрий Жмеренецкий ICQ 380412032
Дата: 30.09.09 11:20
Оценка: 87 (19) +1
#Имя: FAQ.winapi.dll.manifest
Здравствуйте, 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 со всеми вытекающими последствиями.
dll manifest
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.