Привет! В прошлой статье мы рассмотрели создание простого инсталлятора. Он умеет копировать файлы в заданную директорию, создает ярлыки в меню Пуск и даже позволяет удалять установленную программу. Все это мы сделали без особых усилий. Этого функционала уже немало, но, как всегда, хочется чего-то большего.
В этой статье мы научим наш инсталлятор редактировать конфигурационные файлы нашего приложения. В качестве примера используется простая служба WCF, у которой нужно настроить порт, на котором она будет работать. Мы добавим диалог, в котором можно будем ввести номер порта.
Для создания нового диалога создадим новый файл WixUI_ApplicationProperties.wxs. Между секциями Fragment добавим следующий код.
Давайте по порядку разберемся, что тут написано. Секция Dialog описывает наш диалог. Его идентификатор ApplicationConfigurationsDlg будет использоваться дальше при описании сценариев мастера. Значение в атрибуте Title указывает на то, что заголовок окна нужно брать из файлов локализации. Это позволяет изменять текст при изменении локали инсталлятора. Я не буду заморачиваться с локализацией, поэтому в своиx элементах управления я буду использовать русский текст.
Далее идет описание элементов управления, которые будут отображены в диалоге. Тут описаны заголовки, иконка вверху формы и кнопки «Назад», «Далее» и «Отмена». Все наименования указываются как локализованные строки. На самом деле весь код до комментария я стащил из исходников WiX для упрощения жизни. Хочу только обратить внимание на две вещи.
Первое, у заголовка окна в тексте указан непонятный текст {\WixUI_Font_Title}. Это директива препроцессора WiX, которая делает отображаемый текст жирным. Спецы пишут, что так делать не стоит, и лучше использовать локализованные строки. Но как я уже сказал выше, я не стал заморачиваться с локализацией.
И второе, можно заметить, что кнопке Отмена назначен обработчик нажатия, который при нажатии переводит нас в окно отмены инсталляции. Мелочь, а приятно.
Далее мы добавляем поле ввода нашего порта и наименование поля в виде текста. Вообще все элементы управления в WiX описываются тегом Control. Конкретный тип элемента определяется атрибутом Type. Тут можно указать разные виды, например Text (просто текст), PushButton (кнопка), CheckBox, Combobox и так далее.
Далее задаются размеры и расположение элемента управления. В WiX нет никаких продвинутых режимов компоновки. Положение задается в виде координат относительно левого верхнего угла диалога. Вообще, чтобы не описывать диалог в виде текста, рисуя разметку на листочке, я порекомендую программку WixEdit. Она позволяет редактировать формы в визуальном дизайнере. Скажу прямо, программа оставляет желать лучшего с точки зрения юзабилити, но ничего более удобного мне найти не удалось. Поэтому пришлось довольствоваться ей.
Для сохранения порта нужно указать свойство. В данном случае мы указываем свойство SERVER_PORT. У свойств есть одна особенность. По сути, это те же самые переменные. Для использования свойств в UI они должны быть открытыми, то есть видны из разных мест инсталлятора. Чтобы сделать свойство открытым – необходимо, чтобы в его название входили только большие буквы. Вот такая вот магия.
Объявим наше свойство. Для этого в файле Product.wxs добавим следующую запись. Атрибут Value содержит в себе порт по умолчанию.
Теперь нам нужно добавить наш диалог в описание форм мастера. Это описание можно сделать с нуля, но мы поступим хитрей. Давайте скачаем исходники WiX. Там уже есть описание готовых мастеров. Мы возьмем за основу шаблон WixUI_InstallDir. Он расположен в файле src\ext\UIExtension\wixlib\WixUI_InstallDir.wxs. Создадим в проекте файл WixUI_ServerMaster.wxs, скопируем в него содержимое файла WixUI_InstallDir.wxs и немного отредактируем. Во-первых, изменим наименование мастера в UI Id="WixUI_ServerMaster". Во-вторых, уберем из мастера форму лицензионного соглашения. Для этого удалим все теги с упоминанием формы LicenseAgreementDlg. Таких будет две строки.
В этой статье мы научим наш инсталлятор редактировать конфигурационные файлы нашего приложения. В качестве примера используется простая служба WCF, у которой нужно настроить порт, на котором она будет работать. Мы добавим диалог, в котором можно будем ввести номер порта.
<UI> <Dialog Id="ApplicationConfigurationsDlg" Width="370" Height="270" Title="!(loc.WelcomeDlg_Title)"> <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes" Text="{\WixUI_Font_Title}Настройки сервера приложений" /> <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="!(loc.InstallDirDlgBannerBitmap)" /> <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0" /> <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" /> <Control Id="Next" Type="PushButton" X="248" Y="243" Width="56" Height="17" Default="yes" Text="!(loc.WixUINext)" /> <Control Id="Back" Type="PushButton" X="192" Y="243" Width="56" Height="17" Text="!(loc.WixUIBack)" /> <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="!(loc.WixUICancel)"> <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> </Control> <!-- ОПИСАНИЕ ПОЛЯ ПОРТА --> <Control Type="Text" Id="PortText" Width="61" Height="17" X="15" Y="64" Text="Порт сервера:" /> <Control Type="Edit" Id="PortEdit" Width="50" Height="16" X="82" Y="61" Property="SERVER_PORT"></Control> </Dialog> </UI>
Давайте по порядку разберемся, что тут написано. Секция Dialog описывает наш диалог. Его идентификатор ApplicationConfigurationsDlg будет использоваться дальше при описании сценариев мастера. Значение в атрибуте Title указывает на то, что заголовок окна нужно брать из файлов локализации. Это позволяет изменять текст при изменении локали инсталлятора. Я не буду заморачиваться с локализацией, поэтому в своиx элементах управления я буду использовать русский текст.
Далее идет описание элементов управления, которые будут отображены в диалоге. Тут описаны заголовки, иконка вверху формы и кнопки «Назад», «Далее» и «Отмена». Все наименования указываются как локализованные строки. На самом деле весь код до комментария я стащил из исходников WiX для упрощения жизни. Хочу только обратить внимание на две вещи.
Первое, у заголовка окна в тексте указан непонятный текст {\WixUI_Font_Title}. Это директива препроцессора WiX, которая делает отображаемый текст жирным. Спецы пишут, что так делать не стоит, и лучше использовать локализованные строки. Но как я уже сказал выше, я не стал заморачиваться с локализацией.
И второе, можно заметить, что кнопке Отмена назначен обработчик нажатия, который при нажатии переводит нас в окно отмены инсталляции. Мелочь, а приятно.
Далее мы добавляем поле ввода нашего порта и наименование поля в виде текста. Вообще все элементы управления в WiX описываются тегом Control. Конкретный тип элемента определяется атрибутом Type. Тут можно указать разные виды, например Text (просто текст), PushButton (кнопка), CheckBox, Combobox и так далее.
Далее задаются размеры и расположение элемента управления. В WiX нет никаких продвинутых режимов компоновки. Положение задается в виде координат относительно левого верхнего угла диалога. Вообще, чтобы не описывать диалог в виде текста, рисуя разметку на листочке, я порекомендую программку WixEdit. Она позволяет редактировать формы в визуальном дизайнере. Скажу прямо, программа оставляет желать лучшего с точки зрения юзабилити, но ничего более удобного мне найти не удалось. Поэтому пришлось довольствоваться ей.
Для сохранения порта нужно указать свойство. В данном случае мы указываем свойство SERVER_PORT. У свойств есть одна особенность. По сути, это те же самые переменные. Для использования свойств в UI они должны быть открытыми, то есть видны из разных мест инсталлятора. Чтобы сделать свойство открытым – необходимо, чтобы в его название входили только большие буквы. Вот такая вот магия.
Объявим наше свойство. Для этого в файле Product.wxs добавим следующую запись. Атрибут Value содержит в себе порт по умолчанию.
<Property Id="SERVER_PORT" Value="8888"/>
Теперь нам нужно добавить наш диалог в описание форм мастера. Это описание можно сделать с нуля, но мы поступим хитрей. Давайте скачаем исходники WiX. Там уже есть описание готовых мастеров. Мы возьмем за основу шаблон WixUI_InstallDir. Он расположен в файле src\ext\UIExtension\wixlib\WixUI_InstallDir.wxs. Создадим в проекте файл WixUI_ServerMaster.wxs, скопируем в него содержимое файла WixUI_InstallDir.wxs и немного отредактируем. Во-первых, изменим наименование мастера в UI Id="WixUI_ServerMaster". Во-вторых, уберем из мастера форму лицензионного соглашения. Для этого удалим все теги с упоминанием формы LicenseAgreementDlg. Таких будет две строки.
В-третьих, добавим описание нашей формы.
Тут мы указываем, что по нажатию кнопки «Далее» в окне выбора папки установки (InstallDirDlg) будет открыто окно ввода порта. То же действие прописано для нажатия кнопки «Назад» в окне подтверждения установки (VerifyReadyDlg). Оставшиеся строки описывают поведение кнопок «Назад» и «Далее» в окне ввода порта. Они обеспечивают переходы на предыдущее и следующее окно соответственно. Единичка между тегами Publish является условием выполнения действия. В данном случае переходы должны выполняться всегда.
Теперь в файле Product.wxs изменим значение тега UIRef с WixUI_InstallDir на WixUI_ServerMaster. На этом все готово, форма будет появляться при работе инсталлятора.
Осталась малость, научить инсталлятор прописывать введенный порт в файл конфигураций сервера. WiX позволяет редактировать xml файлы из коробки. Для этого нужно подключить к проекту сборку WixUtilExtension. Откроем файл Files.wxs и отредактируем его в соответствии с кодом ниже.
Тут мы добавили описание пространства имен xmlns:util для работы с расширениями. И добавили описание тега XmlFile, который позволяет редактировать xml-файл. У него задается следующий набор атрибутов:
<Publish Dialog="InstallDirDlg" Control="ChangeFolder" Event="SpawnDialog" Value="BrowseDlg" Order="2">1</Publish> <Publish Dialog="ApplicationConfigurationsDlg" Control="Back" Event="NewDialog" Value="InstallDirDlg">1</Publish> <Publish Dialog="ApplicationConfigurationsDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">1</Publish> <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="ApplicationConfigurationsDlg" Order="1">1</Publish>
Тут мы указываем, что по нажатию кнопки «Далее» в окне выбора папки установки (InstallDirDlg) будет открыто окно ввода порта. То же действие прописано для нажатия кнопки «Назад» в окне подтверждения установки (VerifyReadyDlg). Оставшиеся строки описывают поведение кнопок «Назад» и «Далее» в окне ввода порта. Они обеспечивают переходы на предыдущее и следующее окно соответственно. Единичка между тегами Publish является условием выполнения действия. В данном случае переходы должны выполняться всегда.
Теперь в файле Product.wxs изменим значение тега UIRef с WixUI_InstallDir на WixUI_ServerMaster. На этом все готово, форма будет появляться при работе инсталлятора.
Осталась малость, научить инсталлятор прописывать введенный порт в файл конфигураций сервера. WiX позволяет редактировать xml файлы из коробки. Для этого нужно подключить к проекту сборку WixUtilExtension. Откроем файл Files.wxs и отредактируем его в соответствии с кодом ниже.
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"> <Fragment> <DirectoryRef Id="INSTALLLOCATION" FileSource="..\..\InstallingApplication\ApplicationWindowsService\bin\Debug\"> <Component Id ="ProductComponents" DiskId="1" Guid="{B65CDCEE-7130-4759-A8E8-16D84717CCF2}"> <File Id="ApplicationService.Common.dll" Name="ApplicationService.Common.dll"/> <File Id="ApplicationWindowsService.exe" Name="ApplicationWindowsService.exe"/> <File Id="log4net.dll" Name="log4net.dll"/> <File Id="ApplicationWindowsService.exe.config" Name="ApplicationWindowsService.exe.config"/> <!-- НАСТРОЙКА ПОРТА СЕРВЕРА--> <util:XmlFile Id="AppConfigServerPort" Action="setValue" Permanent="yes" File="[#ApplicationWindowsService.exe.config]" ElementPath="/configuration/system.serviceModel/services/service[\[]@name='ApplicationService.Common.ApplicationService'[\]]/host/baseAddresses/add/@baseAddress" Value="net.tcp://localhost:[SERVER_PORT]/ApplicationService/"/> </Component> </DirectoryRef> </Fragment> </Wix>
Тут мы добавили описание пространства имен xmlns:util для работы с расширениями. И добавили описание тега XmlFile, который позволяет редактировать xml-файл. У него задается следующий набор атрибутов:
- Id – уникальный идентификатор действия редактирования.
- Action – выполняемое действие. В данном случае мы задаем значение атрибута.
- Permanent – указывает на то, должно ли свойство быть удалено при деинсталляции. В нашем случае это не важно, так как файл будет удален при деинсталляции.
- File – идентификатор файла конфигурации. Сам файл описан выше.
- ElementPath – путь до редактируемого элемента, заданный в формате XPath. Мы указываем атрибут baseAddress. Занимательная запись \[] и [\] используется для экранирования квадратных скобок, без них компилятор может ругнуться на некорректную запись.
- Value – записываемое значение. В данном случаем это обычная запись адреса WCF службы, в которую подставляется значение свойства SERVER_PORT. Запись в квадратных скобках указывает на то, что нужно подставить значение свойства.
Все готово, но осталось сделать совсем чуть-чуть. Если сейчас попробовать собрать инсталлятор, то компилятор выдаст ошибку.
The localization variable !(loc.msierrXmlFileFailedRead) is unknown. Please ensure the variable is defined. The localization variable !(loc.msierrXmlFileFailedOpen) is unknown. Please ensure the variable is defined. The localization variable !(loc.msierrXmlFileFailedSelect) is unknown. Please ensure the variable is defined. The localization variable !(loc.msierrXmlFileFailedSave) is unknown. Please ensure the variable is defined.
Ошибка говорит о том, что у компилятора нет файла локализации UtilExtensions для русской локали. Порывшись в интернете, я нашел подходящий файл. Он приложен к проекту инсталлятора. Добавим его к проекту, и теперь инсталлятор собирается без ошибок.
На этом все. Инсталлятор готов. Теперь мы можем указывать порт.
Исходники примера можно взять здесь (папка WixExample2)
Комментариев нет:
Отправить комментарий