От MSI к WiX, часть 1 - Обязательные свойства
Главная страница серии здесь.
English version of this page is here.
Введение
Это не дословный перевод англоязычной версии, а просто пересказ того, что было написано первоначально по английски. Там где у меня не получится найти подходящий русский термин, я буду использовать английскую терминологию. Скажу сразу - мне совсем не нравится как у меня получилось это по русски.
Сегодня я начинаю серию статей о том как создать инсталлятор используя WiX. Моя цель - показать что пропущено в документации WiX и показать не только что нужно сделать в WiX, но и почему. В этой серии я буду использовать WiX 2.0.
Поскольку я буду использовать программы из Windows Installer SDK, такие как Orca, нам необходимо установить Windows Installer SDK, который является частью Microsoft Platform SDK. Вы можете установить SDK отсюда.
Вы можете установить только Windows Installer SDK.
Создание исходного Wix файла
Каждый Wix файл должен иметь следующий корневой элемент:
<?xml version='1.0' encoding='windows-1252'?>
<Wix xmlns='https://schemas.microsoft.com/wix/2003/01/wi'>
. . .
</Wix>
Расширение для Wix файлов с исходным кодом обычно wxs.
Объявление требуемых свойств
Windows Installer использует пять свойств из Property table для того чтобы отличить одну установленную программу от другой.
Вот список всех требуемых свойств:
- ProductCode - Уникальный идентификатор для конкретного программного продукта (GUID).
- ProductVersion - Версия продукта. Формат этой строки: major.minor.build.
- ProductLanguage - Цифровой идентификатор языка (LANGID) который инсталлятор будет использовать для всех сообщений в пользовательском интерфейсе, которые не были определены в базе данных. Этот идентификатор обязательно должен быть одним из списка языков в свойстве Template Summary из Summary Information stream.
- ProductName - Название программы.
- Manufacturer - Имя производителя прогрвммы.
Рекомендуется также добавить свойство UpgradeCode для того, чтобы упростить установку будущих новых версий программы.
Запомните: Windows Installer требует, чтобы все буквы в GUID были заглавными буквами. Если Вы используете Visual Studio для редактирования Ваших WiX исходных кодов, здесь Вы найдете инструкуции по созданию Visual Studio макроса для автоматизации процесса создания нового GUID.
Так мы добавляем требуемые свойства в WiX:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="https://schemas.microsoft.com/wix/2003/01/wi">
<Product Id="{1EFFDCD2-4B4B-439E-8296-651795EE02D9}"
Name="Minimal Windows Installer Sample"
Language="1033"
Codepage="1252"
Version="1.0.0"
Manufacturer="Acme Corporation"
UpgradeCode="{15F9543C-1C8D-45D6-B587-86E65F914F20}">
</Product>
</Wix>
Соответствие между свойствами и атрибутами элемента <Product>:
- ProductCode - Id.
- ProductVersion - Version.
- ProductLanguage - Language.
- ProductName - Name.
- Manufacturer - Manufacturer.
- UpgradeCode - UpgradeCode.
Теперь нам необходимо добавить последнее требуемое свойство, которое хранится в свойстве Revision Number Summary в Summary Information stream. Этим свойством является package code . Summary Information stream имеет несколько дополнительных свойств и представлен а WiX исходном коде элементом <Package>.
Свойства из Summary Information stream и их аналоги в элементе <Package>
Свойство | Атрибут | Назначение |
---|---|---|
Revision Number | Id | Package Code - код пакета |
Subject | Description | Значение этого атрибута - имя программы и может иметь то же значение что и свойство ProductName:[ProductName] |
Comments | Comments | Общее описание назначения инсталляционного пакета. Обычно содержит следующее сообщение:This installer database contains the logic and data required to install [ProductName]. |
Author | Manufacturer | Призводитель программы. Обычно имеет следующее значение:[Manufacturer] |
Codepage | SummaryCodepage | Числовое значение кодовой ANSI страницы используемое для всех строк в summary information. |
Keywords | Keywords | Список ключевых слов. Должен включать слово "Installer", а так же другие относящиеся к программе ключевые слова. |
Template | PlatformsLanguages | Здесь указываются тип процессора и языки операционной системы, с которыми данная инсталляционная база данных совместима. Правильный синтаксис для Template property:platform;langId,langId,... Wix использует два отдельных property для типа процессора и для списка языков.Внимание: Wix help для элемента <Package> ошибочно утверждает, что значением атритбута Platforms является список поддерживаемых типов процессоров. Только один тип процессора может быть указан в Template Summary property. |
Page Count | InstallerVersion | Минимально допустимая версия инсталлятора. |
Word CountBit 0 | ShortNames | Копируемые файлы используют только/не только короткие имена файлов. |
Word CountBit 1 | Compressed | Уровень сжатия по умолчанию для всех файлов в инсталляционном пакете. |
Word CountBit 2 | AdminImage | Источником устанавливаемых файлов является первоначальный носитель или административный образ созданный в результате административной установки. |
Word CountBit 3 | InstallPrivileges | Повышенные привилегии могут потребоваться/не требуются при установке этого пакета. |
Security | ReadOnly | Должен ли данный пакет открываться другими программами только для чтения. |
Title | Тип инсталляционного пакета. Для инсталляционных пакетов обычным значением для этого поля является:Installation Database | |
Character Count | Используется только для Transforms. | |
Creating Application | Программа, создавшая данный инсталляционный пакет. | |
Last Saved By | В инсталляционном пакете, инсталлятор устанавливает значение этого property в значение LogonUser property во время административной инсталляции. Это property должно быть установлено в Null перед отправкой инсталляционного пакета заказчикам. | |
Last Save Time/Date | Время когда инсталляционный пакет был в последний раз изменен. | |
Create Time/Date | Время и день когда автор создал инсталляционный пакет. | |
Last Printed | В инсталляционном пакете, Last Printed Summary property может быть установлено во время административной инсталляции в день и время когда административный образ был создан. Для неадминистративной инсталляции имеет то же значение что и Create Time/Date Summary property. |
Так выглядит исходный файл после того как мы добавили в него элемент <Package>:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="https://schemas.microsoft.com/wix/2003/01/wi">
<Product Id="{1EFFDCD2-4B4B-439E-8296-651795EE02D9}"
Name="Minimal Windows Installer Sample"
Language="1033"
Codepage="1252"
Version="1.0.0"
Manufacturer="Acme Corporation"
UpgradeCode="{15F9543C-1C8D-45D6-B587-86E65F914F20}">
<Package Id="{909A6CE7-2739-4522-92C2-03AD7D7EE4CD}"
Description="Minimal Windows Installer Sample"
Comments="This installer database contains the logic and data required to install Minimal Windows Installer Sample."
InstallerVersion="200"
Languages="1033"
SummaryCodepage="1252"
Platforms="Intel"
ReadOnly="no"
Compressed="yes"
AdminImage="no"
Keywords="Installer"
ShortNames ="no"
Manufacturer="Acme Corporation" />
</Product>
</Wix>
Package Сode представлен атрибутом Id и должен быть уникальным для каждого пакета.
Важно: Атрибут Languages должен содержать в своем списке языков ID языка из атрибута Language элемента <Product>.
Ещё о property
Windows Installer property - это переменные, при помощи которых можно определить поведение и действия, выполняемые Windows Installer во время установки программы:
- Имена property чувствительны к регистрам. Например, XYZ и Xyz - разные property.
- Имя public property состоит из заглавных букв, в то время как private property должно содержать как минимум одну маленькую букву. Только public property могут быть включены в командную строку.
Как определить дерево директорий для программы
В базе данных MSI пакета, Directory table определяет дерево директорий для программы. Дерево директорий начинается с обязательной корневой директории, представленной TARGETDIR property. По умолчанию, значением TARGETDIR property является значение property SourceDir.
Дерево директорий представлено в WiX иерархией элементов <Directory>.
Это дерево директорий для нашего проекта:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="Minimal" LongName="MinimalInstallation">
</Directory>
</Directory>
</Directory>
Я использую стандартную Program Files директорию для установки программы. Внутри этой директории я создаю поддиректорию с "коротким" именем (которое соответствует стандартному имени в MS-DOS) "Minimal" и с "длинным" именем "MinimalInstallation". Windows Installer имеет набор предопределенных имен для системных директорий Windows которые Вы можете использовать в своих инсталляторах.
Теперь мы добавим feature в наш проект и component, являющийся частью feature.
Логическая структура дерева features задана в таблице Feature базы данных MSI. В WiX используется элемент <Feature>.
На заметку: Колонка Level таблицы Feature (атрибут Level элемента <Feature>) содержит начальный уровень инсталляции для feature. Уровень инсталляции ноль запрещяет feature и она становится невидимой в пользовательском интерфейсе. Пользователи могут использовать INSTALLLEVEL public property в командной строке чтобы указать какие features должны быть установлены. Более подробно мы рассмотрим features и components в четвертой части.
Все компоненты перечислены в таблице Component базы данных MSI и в WiX представлены элементами <Component>. В этом примере наш компонент не будет ничего устанавливать. Так выглядит наш исходный текст в WiX:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="https://schemas.microsoft.com/wix/2003/01/wi">
<Product Id="{1EFFDCD2-4B4B-439E-8296-651795EE02D9}"
Name="Minimal Windows Installer Sample"
Language="1033"
Codepage="1252"
Version="1.0.0"
Manufacturer="Acme Corporation"
UpgradeCode="{15F9543C-1C8D-45D6-B587-86E65F914F20}">
<Package Id="{909A6CE7-2739-4522-92C2-03AD7D7EE4CD}"
Description="Minimal Windows Installer Sample"
Comments="This installer database contains the logic and data required to install Minimal Windows Installer Sample."
InstallerVersion="200"
Languages="1033"
SummaryCodepage="1252"
Platforms="Intel"
ReadOnly="no"
Compressed="yes"
AdminImage="no"
Keywords="Installer"
ShortNames ="no"
Manufacturer="Acme Corporation" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="Minimal" LongName="MinimalInstallation">
<Component Id="Component1"
Guid="{78E22868-B750-47EB-9E4C-C19CCA939394}">
<CreateFolder />
</Component>
</Directory>
</Directory>
</Directory>
<Feature Id="Feature1"
Title="Feature1 title"
Description="Feature1 description"
Level="1"
ConfigurableDirectory="INSTALLDIR" >
<ComponentRef Id="Component1" />
</Feature>
</Product>
</Wix>
Обратите внимание, что элемент <Component> содержит подэлемент <CreateFolder>. Он нам нужен поскольку Windows Installer обычно не создает пустых директорий. Для того, чтобы создать пустую директорию, имя директории должно присутствовать в таблице In order to create an empty folder, the name of the folder must be presented in the CreateFolder базы данных MSI.
На заметку: Если во время инсталляции должна быть создана директория и она отсутствует после окончания инсталляции, Вы забыли добавить элемент <CreateFolder>.
Вы можете создать инсталлятор для программы Minimal используя следующие команды:
candle.exe Minimal.wxs
light.exe -out Minimal.msi Minimal.wixobj
или, если Вы предпочитаете MSBuild (Minimal.proj):
<
Project DefaultTargets="Build" xmlns="https://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!-- Required by WiX -->
<!-- Path and name of the output without extension -->
<OutputName>Minimal</OutputName>
<!-- What need to be built -->
<OutputType Condition="$(OutputType)==''">package</OutputType>
<!--
The path to the WiX installation -->
<ToolPath>d:\WIX\</ToolPath>
<!--
Input path to source files.
If not passed, assumes the same folder where project file is located. -->
<BaseInputPath Condition="$(BaseInputPath)==''">$(MSBuildProjectDirectory)\</BaseInputPath>
<!--
Create a compiled output in the folder where project is located -->
<OutputPath Condition="$(OutputPath)==''">$(MSBuildProjectDirectory)\</OutputPath>
<!--
Add missing trailing slash in paths -->
<ToolPath Condition="!HasTrailingSlash('$(ToolPath)') ">$(ToolPath)\</ToolPath>
<BaseInputPath Condition="!HasTrailingSlash('$(BaseInputPath)') ">$(BaseInputPath)\</BaseInputPath>
<OutputPath Condition="!HasTrailingSlash('$(OutputPath)') ">$(OutputPath)\</OutputPath>
</PropertyGroup>
<!--
Candle.exe command-line options -->
<ItemGroup>
</ItemGroup>
<!--
Light.exe command-line options -->
<ItemGroup>
</ItemGroup>
<
Import Project="$(ToolPath)wix.targets"/>
<!--
List of files to compile -->
<ItemGroup>
<Compile Include="$(BaseInputPath)Minimal.wxs"/>
</ItemGroup>
</Project>
это команда для компиляции MSBuild проекта:
msbuild Minimal.proj
Теперь, если Вы установили Installer SDK, щелкните правой кнопкой мышки над файлом Minimal.msi file и выберите меню "Edit with Orca". Запустится программа Orca и она загрузит базу данных Minimal.msi. Выберите меню "Tools", потом меню "Validate...". Отмените выборку (? uncheck ?) "Show "INFO" Messages" и кликнете по кнопке "Go". Запустится package validation (проверка базы на соответствие правилам). В нашем случае, проверка выдаст ICE71 warning: "The Media table has no entries." Это означает, что все инсталляционные пакеты должны иметь запись в таблице Media с значением 1 в поле DiskId. Для того, чтобы исправить это предупреждение, нам надо добавить элемент <Media> перед элементом <Directory>:
<Media Id="1" />
<Directory Id="TARGETDIR" Name="SourceDir">
На заметку: Всегда выполняйте ICE validation Вашего инсталляционного пакета.
Теперь мы можем установить программу используя Minimal.msi и убедиться, что директория MinimalInstallation создается в директории Program Files и удаляется после деинсталляции программы.
Причиной, по которой мы использовали public property INSTALLDIR в строке:
<Directory Id="INSTALLDIR" Name="Minimal" LongName="MinimalInstallation">
является то, что мы хотим дать возможность пользователю изменить директорию, где будет установлена программа, используя командную строку. Попробуйте установить Minimal.msi используя следующую командную строку:
msiexec /i Minimal.msi INSTALLDIR=c:\MinimalTest
Как Вы можете убедиться, наш msi создает директорию MinimalTest на диске C вместо директории Program Files.
Что дальше
В следующий раз мы добавим поддержку для Add/Remove Program.
Comments
Anonymous
September 12, 2008
Спасибо, толковая, понятная статья. По сравнению с другими статьями оказалась самой полезной.Anonymous
July 05, 2009
не понятно как сделать подкаталоги, т.е. Program FilesMyApp делается легко как сделать например Program FilesMyAppIcons ? из cli конечно жеAnonymous
July 16, 2009
Легко: <Directory ...> <Directory Id="INSTALLDIR" ... > <Component ... > ... </Component> <Directory Id="ICONS" Name="Icons"> <Component ... </Directory> </Directory> </Directory>