Підказки та поради WiX


264

Ми вже деякий час використовуємо WiX, і, незважаючи на звичайні захоплення щодо простоти використання, це працює досить добре. Що я шукаю - корисна порада щодо:

  • Налаштування проекту WiX (макет, посилання, шаблони файлів)
  • Інтеграція WiX у рішення та побудова / випуск процесів
  • Налаштування інсталяторів для нових установок та оновлень
  • Будь-які хороші хакі WiX, якими ви хочете поділитися

подивіться на gui4wix.codeplex.com
TarunG

10
Закрито як не конструктивне? Я навчився купи, задаючи це питання! Трохи консистенція з StackOverflow б непогано ... наприклад stackoverflow.com/questions/550632 / ...
si618

15
Він отримав '203' Ups, цього достатньо, щоб довести свою корисність.
TarunG

ТАК питання повинні мати остаточну, правильну відповідь; Питання відкритого типу змушують запитувати людей про актуальні проблеми на першу сторінку. faq @Si. Ця політика завжди існувала у AFAIK, але зараз її краще застосовувати; це питання майже три роки.
Джим Дагг

Досить справедливий Джим, це питання відкритого типу, і, мабуть, вирішувати вирішуватиме спільнота SO, але я мушу сказати, що закривати це як не конструктивне виглядає дивним, враховуючи, що я і погляди на це, багато інших людей вважають це питання корисним (наприклад, goo.gl/Zqp2X ), і воно дуже добре відповідає practical, answerable questions based on actual problems that you faceчастині FAQ.
si618

Відповіді:


157
  1. Зберігайте змінні в окремому wxiфайлі включення. Дозволяє повторне використання, змінні швидше знаходять і (за потреби) дозволяють легше маніпулювати зовнішнім інструментом.

  2. Визначте змінні платформи для складання x86 та x64

    <!-- Product name as you want it to appear in Add/Remove Programs-->
    <?if $(var.Platform) = x64 ?>
      <?define ProductName = "Product Name (64 bit)" ?>
      <?define Win64 = "yes" ?>
      <?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?>
    <?else ?>
      <?define ProductName = "Product Name" ?>
      <?define Win64 = "no" ?>
      <?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?>
    <?endif ?>
  3. Збережіть місце установки в реєстрі, що дозволяє оновленням знайти правильне місцеположення. Наприклад, якщо користувач встановлює спеціальний каталог встановлення.

     <Property Id="INSTALLLOCATION">
        <RegistrySearch Id="RegistrySearch" Type="raw" Root="HKLM" Win64="$(var.Win64)"
                  Key="Software\Company\Product" Name="InstallLocation" />
     </Property>

    Примітка : Гуру WiX Rob Mensching опублікував відмінний запис у блозі, який детальніше розглядає та виправляє крайній випадок, коли властивості встановлюються з командного рядка.

    Приклади з використанням 1. 2. і 3.

    <?include $(sys.CURRENTDIR)\Config.wxi?>
    <Product ... >
      <Package InstallerVersion="200" InstallPrivileges="elevated"
               InstallScope="perMachine" Platform="$(var.Platform)"
               Compressed="yes" Description="$(var.ProductName)" />

    і

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="$(var.PlatformProgramFilesFolder)">
        <Directory Id="INSTALLLOCATION" Name="$(var.InstallName)">
  4. Найпростіший підхід - це завжди великі оновлення , оскільки він дозволяє як нові встановлення, так і оновлення в єдиному MSI. UpgradeCode закріплений за унікальним Посібником і ніколи не зміниться, якщо ми не хочемо оновити існуючий продукт.

    Примітка : У WiX 3.5 є нове елемент MajorUpgrade, який робить життя ще простішим !

  5. Створення піктограми в програмі "Додати / видалити"

    <Icon Id="Company.ico" SourceFile="..\Tools\Company\Images\Company.ico" />
    <Property Id="ARPPRODUCTICON" Value="Company.ico" />
    <Property Id="ARPHELPLINK" Value="http://www.example.com/" />
  6. Після версії версій ми встановлюємо версію наших інсталяторів, копіюючи файл msi в каталог розгортання. Приклад цього за допомогою цілі wixproj, викликаної з цілі AfterBuild:

    <Target Name="CopyToDeploy" Condition="'$(Configuration)' == 'Release'">
      <!-- Note we append AssemblyFileVersion, changing MSI file name only works with Major Upgrades -->
      <Copy SourceFiles="$(OutputPath)$(OutputName).msi" 
            DestinationFiles="..\Deploy\Setup\$(OutputName) $(AssemblyFileVersion)_$(Platform).msi" />
    </Target>
  7. Використовуйте тепло для збору файлів за допомогою шаблону (*). Корисно, якщо ви хочете повторно використовувати файли WXS у кількох проектах (див. Мою відповідь на кілька версій одного продукту). Наприклад, цей пакетний файл автоматично збирає вихід RoboHelp.

    @echo off  
    robocopy ..\WebHelp "%TEMP%\WebHelpTemp\WebHelp" /E /NP /PURGE /XD .svn  
    "%WIX%bin\heat" dir "%TEMP%\WebHelp" -nologo -sfrag -suid -ag -srd -dir WebHelp -out WebHelp.wxs -cg WebHelpComponent -dr INSTALLLOCATION -var var.WebDeploySourceDir 

    Дещо відбувається, robocopyвилучення метаданих Subversion робочої копії перед збиранням; то-dr кореневого каталогу встановлено на наше місце установки, а не за замовчуванням TARGETDIR; -varвикористовується для створення змінної для вказівки вихідного каталогу (вихід веб-розгортання).

  8. Простий спосіб включити версію продукту до заголовка діалогового вікна, використовуючи Strings.wxl для локалізації. (Кредит: saschabeaumont . Додано, оскільки ця чудова порада прихована в коментарі)

    <WixLocalization Culture="en-US" xmlns="http://schemas.microsoft.com/wix/2006/localization">
        <String Id="WelcomeDlgTitle">{\WixUI_Font_Bigger}Welcome to the [ProductName] [ProductVersion] Setup Wizard</String>
    </WixLocalization>
  9. Збережіть собі біль і дотримуйтесь порад Віма Коена щодо одного компонента на файл. Це також дозволяє вимкнути (або підкреслити *) компонент GUID .

  10. Роб Меншинг має акуратний спосіб швидкого пошуку проблем у файлах журналів MSI шляхом пошуку value 3. Зверніть увагу на коментарі щодо інтернаціоналізації.

  11. Додаючи умовні функції, інтуїтивніше встановити рівень функції за замовчуванням на 0 (вимкнено), а потім встановити рівень умови на бажане значення. Якщо ви встановите рівень функції за замовчуванням> = 1, рівень умови повинен бути 0, щоб його відключити, тобто логіка умови повинна бути протилежною тій, що ви очікували, що може заплутати :)

    <Feature Id="NewInstallFeature" Level="0" Description="New installation feature" Absent="allow">
      <Condition Level="1">NOT UPGRADEFOUND</Condition>
    </Feature>
    <Feature Id="UpgradeFeature" Level="0" Description="Upgrade feature" Absent="allow">
      <Condition Level="1">UPGRADEFOUND</Condition>
    </Feature>

Щодо додавання піктограми в програмі "Додати / видалити", то саме те, що я шукав. Де ти тримаєш ці три лінії? +1 для простої дивовижності.
Еверетт

Я схильний розміщувати їх відразу після (і, очевидно, нижче) елемента <Пакет>. Подивіться на схему дійсності wix.sourceforge.net/manual-wix3/schema_index.htm
si618

+1, хочу, щоб я міг зробити +100, це єдиний найкорисніший біт інформації Wix, про який я натрапив.
Тім Лонг

Дякую Тіме! Роб Меншинг, Боб Арсон, Вім Койен та інші заслуговують на кудо за обмін своїми знаннями.
si618

38

Перевірка, чи встановлений IIS:

<Property Id="IIS_MAJOR_VERSION">
    <RegistrySearch Id="CheckIISVersion" Root="HKLM" Key="SOFTWARE\Microsoft\InetStp" Name="MajorVersion" Type="raw" />
</Property>

<Condition Message="IIS must be installed">
    Installed OR IIS_MAJOR_VERSION
</Condition>

Перевірка наявності на Vista + сумісності метабаз IIS 6:

<Property Id="IIS_METABASE_COMPAT">
    <RegistrySearch Id="CheckIISMetabase" Root="HKLM" Key="SOFTWARE\Microsoft\InetStp\Components" Name="ADSICompatibility" Type="raw" />
</Property>

<Condition Message="IIS 6 Metabase Compatibility feature must be installed">
    Installed OR ((VersionNT &lt; 600) OR IIS_METABASE_COMPAT)
</Condition>

34

Зберігайте всі ідентифікатори в окремих просторах імен

  • Особливості починаються з F. прикладів: F.Documentation, F.Binaries, F.SampleCode.
  • Компоненти починаються з C. Ex: C.ChmFile, C.ReleaseNotes, C.LicenseFile, C.IniFile, C.Registry
  • CustomActions є CA. Ex: CA.LaunchHelp, CA.UpdateReadyDlg, CA.SetPropertyX
  • Файли є Fi.
  • Довідники є Di.
  • і так далі.

Я вважаю, що це дуже допомагає відстежувати всі різні ідентифікатори у всіх різних категоріях.


Я не використовую простори імен, але додаю ідентифікатори; наприклад: ExamplesFeature, ChmFileComponent. Напевно, я люблю набирати текст ;-)
dvdvorle

25

Фантастичне питання. Я хотів би побачити деякі найкращі практики.

У мене дуже багато файлів, які я поширюю, тому я створив свій проект на кілька вихідних файлів wxs.

У мене є вихідний файл верхнього рівня, який я називаю Product.wxs, який в основному містить структуру для установки, але не фактичні компоненти. Цей файл має кілька розділів:

<Product ...>
  <Package ...>
    <Media>... 
   <Condition>s ...
   <Upgrade ..>
   <Directory> 
        ...
   </Directory>
   <Feature>
      <ComponentGroupRef ... > A bunch of these that
   </Feature>
   <UI ...>
   <Property...>
   <Custom Actions...>
   <Install Sequences....
  </Package>
</Product>

Решта файлів .wix складаються з фрагментів, що містять ComponentGroups, на які посилається тег Feature в Product.wxs. Мій проект містить приємне логічне групування файлів, які я поширюю

<Fragment>
   <ComponentGroup>
     <ComponentRef>
     ....
    </ComponentGroup>
    <DirectoryRef>
      <Component... for each file
      .... 
    </DirectoryRef>
</Fragment>

Це не ідеально, мій павук OO відчуває трохи, тому що фрагменти мають посилатись на імена у файлі Product.wxs (наприклад, DirectoryRef), але мені легше підтримувати цей єдиний великий вихідний файл.

Я хотів би почути коментарі з цього приводу, або якщо хтось теж має хороші поради!


Наша установка також дуже схожа на такий підхід. Це добре, тому що ми можемо використовувати наш еквівалент Products.wxs в якості базової установки для різноманітних продуктів.
si618

@ Pee Tate: почуття павука правильне. Дивіться мою відповідь про псевдонім каталогів.
Вім Коен

Я приймаю той самий підхід: Product.wxs з макетом є статичним, а завдання збірки (heat.exe) генерує мій файл Content.wxs
timvw

20

Додайте прапорець до діалогового вікна виходу, щоб запустити додаток або файл довідки.

...

<!-- CA to launch the exe after install -->
<CustomAction Id          ="CA.StartAppOnExit"
              FileKey     ="YourAppExeId"
              ExeCommand  =""
              Execute     ="immediate"
              Impersonate ="yes"
              Return      ="asyncNoWait" />

<!-- CA to launch the help file -->
<CustomAction Id         ="CA.LaunchHelp"
              Directory  ="INSTALLDIR"
              ExeCommand ='[WindowsFolder]hh.exe IirfGuide.chm'
              Execute    ="immediate"
              Return     ="asyncNoWait" />

<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT"
          Value="Launch MyApp when setup exits." />

<UI>
  <Publish Dialog  ="ExitDialog"
           Control ="Finish"
           Order   ="1"
           Event   ="DoAction"
           Value   ="CA.StartAppOnExit">WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT</Publish>
</UI>

Якщо ви зробите це таким чином, "стандартний" зовнішній вигляд не зовсім правильний. Поле прапорця завжди є сірим фоном, тоді як діалогове вікно білого кольору:

alt текст http://www.dizzymonkeydesign.com/blog/misc/adding-and-customizing-dlgs-in-wix-3/images/exit_dlg_1.gif

Один із способів цього - вказати власний користувальницький ExitDialog з іншим розташуванням прапорця . Це спрацьовує, але, здається, багато роботи лише для зміни кольору одного елемента керування. Інший спосіб вирішити те саме - це післяобробляти згенерований MSI для зміни полів X, Y в таблиці керування для цього конкретного елемента управління CheckBox. Код javascript виглядає так:

var msiOpenDatabaseModeTransact = 1;
var filespec = WScript.Arguments(0);
var installer = new ActiveXObject("WindowsInstaller.Installer");
var database = installer.OpenDatabase(filespec, msiOpenDatabaseModeTransact);
var sql = "UPDATE `Control` SET `Control`.`Height` = '18', `Control`.`Width` = '170'," +
          " `Control`.`Y`='243', `Control`.`X`='10' " +
          "WHERE `Control`.`Dialog_`='ExitDialog' AND " + 
          "  `Control`.`Control`='OptionalCheckBox'";
var view = database.OpenView(sql);
view.Execute();
view.Close();
database.Commit();

Запуск цього коду як сценарій командного рядка (з використанням cscript.exe) після створення MSI (від light.exe) створить ExitDialog, який виглядає більш професійно:

alt текст http://www.dizzymonkeydesign.com/blog/misc/adding-and-customizing-dlgs-in-wix-3/images/exit_dlg_2.gif


Га! Не мій блог. Я також це читав. І у мене є посилання на запис у блозі в тексті вище. Але вони зробили це інакше, ніж я. Мені подобається мій шлях краще !!
Cheeso

1
Дякую за js, дуже корисно! Одна річ , яку я повинен був змінити в WXS це замінити WIXUI_EXITDIALOGOPTIONALCHECKBOXз WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installedвнутрішньої<Publish>
Олександр Кожевников

Чи є спосіб зробити так, щоб прапорець був встановлений за замовчуванням?
Алек Девіс

Щоб встановити прапорець за замовчуванням, я використав це: <Ідентифікатор властивості = "WIXUI_EXITDIALOGOPTIONALCHECKBOX" Значення = "1" />
Алек Девіс

Схоже, вишукане рішення, але тільки як я ним користуватися? Чи є спосіб встановити js всередині елемента <AfterBuild> у свій wixproj? Або оскільки ви посилаєтесь на запуск його з командного рядка, чи краще це як подія після складання, і в цьому випадку, який хороший інтерпретатор командного рядка js для Windows?
vanmelle

18

Створення реальної, тестової, навчальної, ... версій за допомогою одних і тих же вихідних файлів.

Коротше кажучи: Створіть унікальний UpgradeCode для кожного інсталятора та автоматично визначте перший символ кожного Посібника для кожного інсталятора, залишивши 31 унікальний.

Передумови

Припущення

  • Змінні WiX використовуються для визначення UpgradeCode, ProductName, InstallName.
  • У вас вже є робочий інсталятор. Я б не намагався цього зробити, поки ви цього не зробите.
  • Усі ваші компоненти зберігаються в одному файлі (Components.wxs). Цей процес спрацює, якщо у вас є декілька файлів, просто буде ще робота.

Структура каталогів

  • Налаштування.Бібліотека
    • Усі файли wxs (компоненти, функції, діалогові вікна інтерфейсу користувача, ...)
    • Common.Config.wxi (ProductCode = "*", ProductVersion, PlatformProgramFilesFolder, ...)
  • Setup.Live (wixproj)
    • Зв’яжіть усі файли Setup.Library за допомогою "Додати існуючий файл" -> "Додати як посилання" (кнопка зі стрілкою вниз прямо біля кнопки "Додати" у Visual Studio)
    • Config.wxi (має унікальні UpgradeCode, ProductName, InstallName, ...)
  • Налаштування.Тест , ...
    • наживо, але Config.wxi налаштований для тестового середовища.

Процес

  • Створіть каталог Setup.Library та перемістіть усі ваші файли wxs та wxi (крім Config.wxi) з існуючого проекту.
  • Створіть Setup.Live, Setup.Test тощо за нормальним wixproj.
  • Додати ціль BeforeBuild у wixproj у Setup.Live тощо, щоб виконати завдання MSBuild Community FileUpdate для зміни керівних принципів (я використовував A для Live, B для тесту та C для навчання)
  • Додати ціль AfterBuild, щоб повернути Components.wxs Посібники назад до 0.
  • Перевірте за допомогою Orca, що кожен компонент у кожному MSI має змінені орієнтири.
  • Перевірте, чи відновлені оригінальні напрямні.
  • Переконайтеся, що кожен MSI встановлює (і модернізує) правильний продукт та місце розташування.

Приклад Config.wxi

<?xml version="1.0" encoding="utf-8"?>
<Include>
<!-- Upgrade code should not change unless you want to install 
     a new product and have the old product remain installed, 
     that is, both products existing as separate instances. -->
<?define UpgradeCode = "YOUR-GUID-HERE" ?>

<!-- Platform specific variables -->
<?if $(var.Platform) = x64 ?>
  <!-- Product name as you want it to appear in Add/Remove Programs-->
  <?define ProductName = "Foo 64 Bit [Live]" ?>
<?else ?>
  <?define ProductName =  "Foo [Live]" ?>
<?endif ?>

<!-- Directory name used as default installation location -->
<?define InstallName = "Foo [Live]" ?>

<!-- Registry key name used to store installation location -->
<?define InstallNameKey = "FooLive" ?>

<?define VDirName = "FooLive" ?>
<?define AppPoolName = "FooLiveAppPool" ?>
<?define DbName = "BlahBlahLive" ?>
</Include>

Приклад Config.Common.wxi

<?xml version="1.0" encoding="utf-8"?>
<Include>
<!-- Auto-generate ProductCode for each build, release and upgrade -->
<?define ProductCode = "*" ?>

<!-- Note that 4th version (Revision) is ignored by Windows Installer -->
<?define ProductVersion = "1.0.0.0" ?>

<!-- Minimum version supported if product already installed and this is an upgrade -->
<!-- Note that 4th version (Revision) is ignored by Windows Installer -->
<?define MinimumUpgradeVersion = "0.0.0.0" ?>

<!-- Platform specific variables -->
<?if $(var.Platform) = x64 ?>
   <?define Win64 = "yes" ?>
   <?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?>
<?else ?>
   <?define Win64 = "no" ?>
   <?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?>
<?endif ?>

<?define ProductManufacturer = "Foo Technologies"?>

<!-- Decimal Language ID (LCID) for the Product. Used for localization. -->
<?define ProductLanguage = "1033" ?>

<?define WebSiteName = "DefaultWebSite" ?>
<?define WebSitePort = "80" ?>

<?define DbServer = "(local)" ?>
</Include>

Приклад Components.wxs

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <!-- The pre-processor variable which allows the magic to happen :) -->
  <?include $(sys.CURRENTDIR)\Config.wxi?>
  <?include ..\Setup.Library\Config.Common.wxi?>
  <Fragment Id="ComponentsFragment">
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="$(var.PlatformProgramFilesFolder)">
        <Directory Id="INSTALLLOCATION" Name="$(var.InstallName)">
          <Component Id="ProductComponent" Guid="0XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" KeyPath="yes">
          ...

Примітка. Зараз я б запропонував атрибут Guid не виходити з компонента (еквівалент *), використовуючи один файл на компонент і встановивши файл як шлях. Це знімає потребу в дзвінках ModifyComponentsGuidsіRevertComponentsGuids цілях, показаних нижче. Це, можливо, не можливо для всіх ваших компонентів.

Приклад Setup.Live.wixproj

<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
<Target Name="BeforeBuild">
  <CallTarget Targets="ModifyComponentsGuids" />
</Target>
<Target Name="AfterBuild">
  <CallTarget Targets="RevertComponentsGuids" />
</Target>
<!-- Modify the first character of every Guid to create unique value for Live, Test and Training builds -->
<Target Name="ModifyComponentsGuids">
  <FileUpdate Files="..\Setup.Library\Components.wxs" Regex="Guid=&quot;([a-f]|[A-F]|\d)" ReplacementText="Guid=&quot;A" />
</Target>
<!-- Revert the first character of every Guid back to initial value -->
<Target Name="RevertComponentsGuids">
  <FileUpdate Files="..\Setup.Library\Components.wxs" Regex="Guid=&quot;([a-f]|[A-F]|\d)" ReplacementText="Guid=&quot;0" />
</Target>

Заключні думки

  • Цей процес також повинен працювати для створення різних інсталяторів для різних модулів злиття (Live, Test, ... як функції) для одного і того ж інсталятора. Я працював з різними інсталяторами, оскільки це здавалося більш безпечним варіантом, є більший ризик, що хтось може оновити Live замість тренувань, якщо вони знаходяться в одній скриньці, а ви просто використовуєте функції для різних модулів злиття.
  • Якщо ви використовуєте MSI для виконання оновлень, а також нових установок, тобто основного підходу лише до оновлення, і ви зберігаєте місце установки в реєстрі, не забудьте створити змінну для імені ключа для кожної установки.
  • Ми також створюємо змінні у кожному Config.wxi, щоб увімкнути унікальні імена віртуальних каталогів, пули програм, імена баз даних та ін. Для кожного інсталятора.

ОНОВЛЕННЯ 1: Автогенеруючий компонент Інструкції усуває необхідність виклику завдання FileUpdate, якщо ви створюєте компонент з Guid = "*" для кожного файлу, встановлюючи файл як шлях.

ОНОВЛЕННЯ 2: Однією з проблем, з якими ми зіткнулися, є те, що якщо ви не генеруєте автоматичну програму Guid's, а збір не вдається, тоді тимчасові файли потрібно видалити вручну.

ОНОВЛЕННЯ 3: Знайдено спосіб зняти залежність від svn: зовнішні та тимчасові створення файлів. Це робить процес збирання більш еластичним (і найкращим варіантом, якщо ви не можете підкреслити свої Посібники), і менш крихким, якщо є збій у світлі або свічці.

ОНОВЛЕННЯ 4: Підтримка декількох примірників, що використовують перетворення екземплярів, є у WiX 3.0+ та, безумовно, також варто переглянути.


+1 для посилання MSBuild Tasks Community Tasks,
полюби

17

Використання журналу діагностики Msi для отримання детальної інформації про помилки

msiexec /i Package.msi /l*v c:\Package.log

Де

Пакет.msi
- назва вашого пакета і
c: \ Package.log
там, де потрібно вивести журнал

Коди помилок Msi

Вступне відео Wix
Oh та Random вступне відео Wix із показом "Містера WiX" Роб Меншешинг "корисна концептуальна велика картина".


2
+1 Було б набагато краще, якби ми могли ввімкнути вхід із системи Wix замість командного рядка.
si618

3
WiX робить. Встановіть властивість MsiLogging. Підтримується лише Windows Installer 4.0+.
Роб Меншінг

Велике спасибі "Містер Вікс". Треба перевірити це.
Терранс

17

Використовуйте налаштування Javascript, тому що вони так легко

Люди сказали, що Javascript - це неправильна річ, яка використовується для MSI CustomActions . Причини: важко налагодити, важко зробити його надійним. Я не згоден. Не важко налагоджувати, звичайно, не важче, ніж C ++. Це просто різне. Я вважав, що писати CustomActions у Javascript дуже просто, набагато простіше, ніж використання C ++. Набагато швидше. І так само надійно.

Є лише один недолік: налаштування Javascript можна витягти за допомогою Orca, тоді як для C / C ++ CA потрібна буде зворотна інженерія. Якщо ви вважаєте, що ваша магія інсталятора є захищеною інтелектуальною власністю, ви хочете уникати сценарію.

Якщо ви використовуєте скрипт, вам потрібно просто почати з якоїсь структури. Ось кілька для початку.


Код Javascript "котла" для CustomAction:

//
// CustomActions.js 
// 
// Template for WIX Custom Actions written in Javascript.
// 
// 
// Mon, 23 Nov 2009  10:54
// 
// ===================================================================


// http://msdn.microsoft.com/en-us/library/sfw6660x(VS.85).aspx
var Buttons = {
        OkOnly           : 0,
        OkCancel         : 1,
        AbortRetryIgnore : 2,
        YesNoCancel      : 3
};

var Icons = {
        Critical         : 16,
        Question         : 32,
        Exclamation      : 48,
        Information      : 64
};

var MsgKind = {
        Error            : 0x01000000,
        Warning          : 0x02000000,
        User             : 0x03000000,
        Log              : 0x04000000
};

// http://msdn.microsoft.com/en-us/library/aa371254(VS.85).aspx
var MsiActionStatus = {
        None             : 0,
        Ok               : 1, // success
        Cancel           : 2,
        Abort            : 3,
        Retry            : 4, // aka suspend?
        Ignore           : 5  // skip remaining actions; this is not an error.
};


function MyCustomActionInJavascript_CA() {
    try {
        LogMessage("Hello from MyCustomActionInJavascript");
        // ...do work here...
        LogMessage("Goodbye from MyCustomActionInJavascript");
    }
    catch (exc1) {
        Session.Property("CA_EXCEPTION") = exc1.message ;
        LogException(exc1);
        return MsiActionStatus.Abort;
    }
    return MsiActionStatus.Ok;
}

// Pop a message box.  also spool a message into the MSI log, if it is enabled. 
function LogException(exc) {
    var record = Session.Installer.CreateRecord(0);
    record.StringData(0) = "CustomAction: Exception: 0x" + decimalToHexString(exc.number) + " : " + exc.message;
    Session.Message(MsgKind.Error + Icons.Critical + Buttons.btnOkOnly, record);
}


// spool an informational message into the MSI log, if it is enabled. 
function LogMessage(msg) {
    var record = Session.Installer.CreateRecord(0);
    record.StringData(0) = "CustomAction:: " + msg;
    Session.Message(MsgKind.Log, record);
}


// http://msdn.microsoft.com/en-us/library/d5fk67ky(VS.85).aspx
var WindowStyle = {
    Hidden : 0,
    Minimized : 1,
    Maximized : 2
};

// http://msdn.microsoft.com/en-us/library/314cz14s(v=VS.85).aspx
var OpenMode = {
    ForReading : 1,
    ForWriting : 2,
    ForAppending : 8
};

// http://msdn.microsoft.com/en-us/library/a72y2t1c(v=VS.85).aspx
var SpecialFolders = {
    WindowsFolder : 0, 
    SystemFolder :  1, 
    TemporaryFolder : 2
};

// Run a command via cmd.exe from within the MSI
function RunCmd(command)
{
    var wshell = new ActiveXObject("WScript.Shell");
    var fso = new ActiveXObject("Scripting.FileSystemObject");
    var tmpdir = fso.GetSpecialFolder(SpecialFolders.TemporaryFolder);
    var tmpFileName = fso.BuildPath(tmpdir, fso.GetTempName());

    LogMessage("shell.Run("+command+")");

    // use cmd.exe to redirect the output
    var rc = wshell.Run("%comspec% /c " + command + "> " + tmpFileName, WindowStyle.Hidden, true);
    LogMessage("shell.Run rc = "  + rc);

    // here, optionally parse the output of the command 
    if (parseOutput) {
        var textStream = fso.OpenTextFile(tmpFileName, OpenMode.ForReading);
        while (!textStream.AtEndOfStream) {
            var oneLine = textStream.ReadLine();
            var line = ParseOneLine(oneLine);
                ...
        }
        textStream.Close();
    }

    if (deleteOutput) {
        fso.DeleteFile(tmpFileName);
    }

    return {
        rc : rc,
        outputfile : (deleteOutput) ? null : tmpFileName
    };
}

Потім зареєструйте власну дію приблизно так:

<Fragment>
  <Binary Id="IisScript_CA" SourceFile="CustomActions.js" />

  <CustomAction Id="CA.MyCustomAction"
              BinaryKey="IisScript_CA"
              JScriptCall="MyCustomActionInJavascript_CA"
              Execute="immediate"
              Return="check" />
</Fragmemt>

Звичайно, ви можете вставити стільки функцій Javascript, скільки вам подобається, для безлічі спеціальних дій. Один із прикладів: Я використовував Javascript, щоб зробити WMI-запит на IIS, щоб отримати список існуючих веб-сайтів, на які можна було б встановити фільтр ISAPI. Цей список потім використовувався для заповнення списку, показаного пізніше в послідовності інтерфейсу користувача. Все дуже просто.

На IIS7 немає постачальника WMI для IIS, тому я використовував shell.Run()підхід, щоб викликати appcmd.exe для виконання роботи. Легко.

Питання, пов’язані з цим: Про налаштування Javascript


2
+1 Я вважаю, що підхід DTF простий у налаштуванні, але і JavaScript може бути корисним.
si618

12

Пітер Тейт вже показав, як можна визначити багаторазові визначення ComponentGroup в окремих фрагментах wix. Деякі додаткові хитрощі, пов’язані з цим:

Збудова каталогу

Фрагментам групи компонентів не потрібно знати про каталоги, визначені основними wxs продукту. У фрагменті групи компонентів ви можете поговорити про таку папку:

<DirectoryRef Id="component1InstallFolder">
...
</DirectoryRef>

Тоді основний продукт може мати псевдонім один із його каталогів (наприклад, "productInstallFolder") таким чином:

<Directory Id="productInstallFolder" Name="ProductName">
   <!-- not subfolders (because no Name attribute) but aliases for parent! -->
   <Directory Id="component1InstallFolder"/> 
   <Directory Id="component2InstallFolder"/> 
</Directory>

Графік залежності

Елементи ComponentGroup можуть містити дочірні елементи ComponentGroupRef. Це чудово, якщо у вас великий пул багаторазових компонентів зі складним графіком залежності між ними. Ви просто встановите ComponentGroup у своєму власному фрагменті для кожного компонента і оголосите такі залежності:

<ComponentGroup Id="B">
   <ComponentRef Id="_B" />
   <ComponentGroupRef Id="A">
</ComponentGroup>

Якщо тепер ви посилаєтесь на групу компонентів "B" у вашому налаштуванні, оскільки це пряма залежність від вашої програми, вона автоматично втягне в групу компонентів "A", навіть якщо автор програми ніколи не зрозумів, що це залежність від "B". Це "просто працює", поки у вас немає кругової залежності.

Віксліб для багаторазового використання

Вищенаведена ідея графіка залежності найкраще працює, якщо ви компілюєте компоненти big-pool-o-багаторазового використання в wixlib для багаторазового використання з lit.exe. Створюючи налаштування програми, ви можете посилатися на цей wixlib так само, як на файл wixobj. Linker.exe-посилання автоматично усуне будь-які фрагменти, які не "затягнуті" за допомогою основних файлів wxs продукту.


12

Я здивований, що ніхто не згадував про використання T4 для створення файлу WXS під час збирання. Я дізнався про це за допомогою Генрі Лі @ New Age Solutions .

По суті, ви створюєте власну задачу MSBuild для виконання шаблону T4, і цей шаблон виводить WXS безпосередньо перед тим, як скомпілювати проект Wix. Це дозволяє вам (залежно від того, як ви її реалізуєте) автоматично включати всі збірки, що виводяться з компіляції іншого рішення (це означає, що вам більше не доведеться редагувати wxs, коли ви додаєте нову збірку).


2
+1 це дійсно приємно, я не так переживаю за збірки, але наші веб-проекти можуть мати проблеми зі сторінками aspx та іншими артефактами (зображеннями, css), які додаються до проекту, але не WiX.
si618

4
Для майбутніх відвідувачів Wix 3.5 має утиліту heat.exe, яка робить цей
урожай

@Mrchief - Я не вірю, що "Тепло" збирає згадані збірки, скопійовані локально - це, мабуть, планується на 4.0. Довідка: sourceforge.net/tracker/…
Пітер Т. LaComb молодший

Тепло не приймає посилання, що посилаються.
tofutim

Які хороші приклади використання T4 для створення файлу WXS?
tofutim

12

Використовуючи Heat.exe, щоб зруйнувати обличчя та нанести "Epic Pwnage" на болісно великі встановлення

Розкриваємо відповіді Сі та Роберта-П про тепло.

Переклад: (Використання тепла, щоб уникнути введення окремих файлів у проект вручну та для автоматизації побудов для загального простішого процесу.)

Детальний синтаксис тепла WiX 2.0

Для нових версій (не все, що відрізняється від старих версій, але можливі набридливі зміни синтаксису ....), перейдіть до каталогу Heat is from cmd.exe і просто введіть тепла, але я маю приклад один тут для довідки з новішими версіями, якщо потрібно.

Додавання наступного до своєї події Build у візуальній студії 2010.
(Клацніть правою кнопкою миші Проект-> Властивості -> Створення подій-> Події попереднього збирання)

$(WIX)bin\heat.exe" dir "$(EnviromentVariable)" -cg GroupVariable -gg -scom -sreg -sfrag - srd -dr INSTALLLOCATION -var env.LogicPath -out "$(FragmentDir)\FileName.wxs

-гг 

Створює керівництво під час запуску тепла (як при виконанні команди вище)

-ком 

Не завантажуйте "COM файли"

-рег 

Не брати "Файли реєстру"

-фрагмент 

Не захоплюйте "Фрагменти"

-ср 

Не захоплюйте "кореневу діру"

реж

dir вказує, що ви хочете, щоб Heat шукав у папці

"$ (EnviromentVariable)"

Ім’я змінної, яку ви додали б до змінних Preprocessor у проекті (Правий клацання миші, Перейдіть до властивостей) властивостей проекту-> Збірка, де написано Визначення змінних препроцесора (передбачається visual studio 2010)

Приклад:
EnviromentVariable = C: \ Project \ bin \ Налагодження;
Немає подвійних лапок, але закінчується крапкою з комою

-cg GroupVariable 

Група компонентів, на яку буде посилатися фрагмент, створений до основного файлу wxs

FragmentDir

Каталог фрагментів, де буде зберігатися вихідний wxs фрагмент

FileName.wxs

Назва файлу

Повний підручник тут, Тож вигадка корисна

Частина 1 Частина 2


Існує ще один корисний інструмент для трохи інших цілей: Парафін ( wintellect.com/CS/blogs/jrobbins/archive/2010/03/10/4107.aspx )
ralf.w.

9

У тому числі COM-об’єкти:

heatгенерує всі більшість (якщо не всі) записи реєстру та іншу необхідну для них конфігурацію. Радуйся!

Включаючи керовані COM-об’єкти (ака, .NET або C # COM-об'єкти)

Використання heatкерованого об'єкта COM надасть вам майже повний документ wix.

Якщо вам не потрібна бібліотека, доступна в GAC (тобто у всьому світі: НАЙБІЛЬШ час вам це не потрібно з вашими .NET-збірками - ви, мабуть, зробили щось не так у цей момент, якщо це не призначено. спільна бібліотека) ви хочете переконатися, що вам потрібно оновити CodeBaseключ реєстру, для якого встановлено [#ComponentName]. Якщо ви плануєте встановити його в GAC (наприклад, ви створили нову дивовижну загальну бібліотеку, яку всі захочуть використовувати), ви повинні видалити цей запис і додати два нові атрибути до Fileелемента: Assemblyі KeyPath. Збірка повинна бути встановлена ​​на ".net" і KeyPathповинна бути встановлена ​​на "так".

Однак для деяких середовищ (особливо будь-якого з керованою пам'яттю, наприклад, мовою сценаріїв) знадобиться і доступ до Typelib. Переконайтеся, що heatви працюєте на своїй typelib і включайте її. heatгенерує всі необхідні ключі реєстру. Наскільки це круто?


8

Установка на C:\ProductName

Деякі програми потрібно встановити на C:\ProductNameщось подібне, але 99,9% (якщо не 100%) прикладів у чистій установці C:\Program Files\CompanyName\ProductName.

Наступний код можна використовувати для встановлення TARGETDIRвластивості до кореня C:диска (взятого зі списку користувачів WiX ):

<CustomAction Id="AssignTargetDir" Property="TARGETDIR" Value="C:\" Execute="firstSequence" />
<InstallUISequence>
    <Custom Action="AssignTargetDir" Before="CostInitialize">TARGETDIR=""</Custom>
</InstallUISequence>
<InstallExecuteSequence>
    <Custom Action="AssignTargetDir" Before="CostInitialize">TARGETDIR=""</Custom>
</InstallExecuteSequence>

ПРИМІТКА: За замовчуванням TARGETDIR не вказує на C:\! Це швидше вказує на те, ROOTDRIVEщо в свою чергу вказує на корінь накопичувача з найбільш вільним місцем ( див. Тут ) - і це не обов'язково C:диск. Може бути ще один жорсткий диск, розділ або USB-диск!

Потім десь під <Product ...>тегом потрібні такі теги каталогів, як зазвичай:

<Directory Id="TARGETDIR" Name="SourceDir">
    <Directory Id="APPLICATIONFOLDER" Name="$(var.ProductName)">
        <!-- your content goes here... -->
    </Directory>
</Directory>

Не було б простіше просто встановити WindowsVolume?
Вім Коен

1
Так, але вам доведеться використовувати вирішення, оскільки WindowsVolumeвластивість може не використовуватися як Directory(компілятор видає помилку / попередження), як зазначено тут і тут . Особисто я вважаю цей спосіб заплутаним.
gehho

7

Екологічні змінні

Складаючи ваші документи Wxs до коду wixobj, ви можете використовувати змінні середовища для визначення різної інформації. Наприклад, скажімо, що ви хочете змінити, які файли будуть включені в проект. Скажімо, у вас є змінна середовище під назвою RELEASE_MODE, яку ви встановили безпосередньо перед тим, як створити MSI (або зі скриптом, або вручну, це не має значення) У своєму джерелі wix ви можете зробити щось на кшталт:

<define FILESOURCE = c:\source\output\bin\$(env.RELEASE_MODE) >

а потім пізніше у своєму коді використовуйте його на місці, щоб на ходу змінити wxs документ, наприклад:

<Icon Id="myicon.ico" SourceFile="$(var.FILESOURCE)" />

1
Також доступні змінні компіляції, такі як $ (конфігурація) і $ (платформа). Також ще багато на msdn.microsoft.com/en-us/library/aa302186.aspx
si618

1
@Si - раніше, ніж сьогодні, це посилання більше не активне. Я не зміг знайти останню.
Пітер М



7

Редагування діалогів

Однією з хороших можливостей редагування діалогів є використання SharpDevelop у версії 4.0.1.7090 (або вище). За допомогою цього інструменту можна відкрити, переглянути і редагувати в режимі дизайну окремий діалог (файли wxs з джерел WiX, наприклад, InstallDirDlg.wxs).


Дивовижно, не знав, що SharpDevelop підтримує це.
anton.burger

6

Налаштування прапора IIS enable32BitAppOnWin64 http://trycatchfail.com/blog/post/WiX-Snippet-change-enable32BitAppOnWin64.aspx

<InstallExecuteSequence>
   <RemoveExistingProducts After="InstallFinalize" />
   <Custom Action="ConfigureAppPool" After="InstallFinalize" >
     <![CDATA[NOT Installed AND VersionNT64 >= 600]]>         
   </Custom>
</InstallExecuteSequence>

<CustomAction Id="ConfigureAppPool" Return="check" Directory="TARGETDIR" ExeCommand="[SystemFolder]inetsrv\appcmd set apppool /apppool.name:[APPPOOLNAME] /enable32BitAppOnWin64:false" />

5

Змініть "Готовий до встановлення?" діалогове вікно (він же VerifyReadyDlg), щоб забезпечити підсумок зроблених виборів.

Це виглядає приблизно так:
alt текст http://i46.tinypic.com/s4th7t.jpg

Зробіть це за допомогою налаштування Javascript:


Код Javascript:

// http://msdn.microsoft.com/en-us/library/aa372516(VS.85).aspx
var MsiViewModify = 
    {
        Refresh          : 0,
        Insert           : 1,
        Update           : 2,
        Assign           : 3,
        Replace          : 4,
        Merge            : 5,
        Delete           : 6,
        InsertTemporary  : 7,   // cannot permanently modify the MSI during install
        Validate         : 8,
        ValidateNew      : 9,
        ValidateField    : 10,
        ValidateDelete   : 11
    };


// http://msdn.microsoft.com/en-us/library/sfw6660x(VS.85).aspx
var Buttons = 
    {
        OkOnly           : 0,
        OkCancel         : 1,
        AbortRetryIgnore : 2,
        YesNoCancel      : 3
    };

var Icons= 
    {
        Critical         : 16,
        Question         : 32,
        Exclamation      : 48,
        Information      : 64
    }

var MsgKind =
    {
        Error            : 0x01000000,
        Warning          : 0x02000000,
        User             : 0x03000000,
        Log              : 0x04000000
    };

// http://msdn.microsoft.com/en-us/library/aa371254(VS.85).aspx
var MsiActionStatus = 
    {
        None             : 0,
        Ok               : 1, // success
        Cancel           : 2,
        Abort            : 3,
        Retry            : 4, // aka suspend?
        Ignore           : 5  // skip remaining actions; this is not an error.
    };

function UpdateReadyDialog_CA(sitename)
{
    try 
    {
        // can retrieve properties from the install session like this:
        var selectedWebSiteId = Session.Property("MSI_PROPERTY_HERE");

        // can retrieve requested feature install state like this:
        var fInstallRequested   = Session.FeatureRequestState("F.FeatureName");

        var text1 = "This is line 1 of text in the VerifyReadyDlg";

        var text2 = "This is the second line of custom text";

        var controlView     = Session.Database.OpenView("SELECT * FROM Control");
        controlView.Execute();

        var rec             = Session.Installer.CreateRecord(12);
        rec.StringData(1)   = "VerifyReadyDlg";    // Dialog_
        rec.StringData(2)   = "CustomVerifyText1"; // Control - can be any name
        rec.StringData(3)   = "Text";              // Type
        rec.IntegerData(4)  = 25;                  // X
        rec.IntegerData(5)  = 60;                  // Y
        rec.IntegerData(6)  = 320;                 // Width
        rec.IntegerData(7)  = 85;                  // Height
        rec.IntegerData(8)  = 2;                   // Attributes
        rec.StringData(9)   = "";                  // Property
        rec.StringData(10)  = vText1;              // Text
        rec.StringData(11)  = "";                  // Control_Next
        rec.StringData(12)  = "";                  // Help
        controlView.Modify(MsiViewModify.InsertTemporary, rec);

        rec                 = Session.Installer.CreateRecord(12);
        rec.StringData(1)   = "VerifyReadyDlg";    // Dialog_
        rec.StringData(2)   = "CustomVerifyText2"; // Control - any unique name
        rec.StringData(3)   = "Text";              // Type
        rec.IntegerData(4)  = 25;                  // X
        rec.IntegerData(5)  = 160;                 // Y
        rec.IntegerData(6)  = 320;                 // Width
        rec.IntegerData(7)  = 65;                  // Height
        rec.IntegerData(8)  = 2;                   // Attributes
        rec.StringData(9)   = "";                  // Property
        rec.StringData(10)  = text2;               // Text
        rec.StringData(11)  = "";                  // Control_Next
        rec.StringData(12)  = "";                  // Help
        controlView.Modify(MsiViewModify.InsertTemporary, rec);

        controlView.Close();
    }
    catch (exc1)
    {
        Session.Property("CA_EXCEPTION") = exc1.message ;
        LogException("UpdatePropsWithSelectedWebSite", exc1);
        return MsiActionStatus.Abort;
    }
    return MsiActionStatus.Ok;
}


function LogException(loc, exc)
{
    var record = Session.Installer.CreateRecord(0);
    record.StringData(0) = "Exception {" + loc + "}: " + exc.number + " : " + exc.message;
    Session.Message(MsgKind.Error + Icons.Critical + Buttons.btnOkOnly, record);
}

Декларуйте Javascript CA:

<Fragment>
  <Binary Id="IisScript_CA" SourceFile="CustomActions.js" />

  <CustomAction Id="CA.UpdateReadyDialog"
              BinaryKey="IisScript_CA"
              JScriptCall="UpdateReadyDialog_CA"
              Execute="immediate"
              Return="check" />
</Fragment>

Прикріпіть CA до кнопки. У цьому прикладі КА запускається при натисканні кнопки Далі від CustomizeDlg:

<UI ...>
  <Publish Dialog="CustomizeDlg" Control="Next" Event="DoAction" 
           Value="CA.UpdateReadyDialog" Order="1"/>
</UI>

Пов'язане запитання SO: Як я можу встановити під час виконання текст, який відображатиметься у VerifyReadyDlg?


Безумовно, це не повинен бути JScript, сценарій мови Windows, а не JavaScript, сценарій мови DHTML. Можливо, трохи педантично, але дехто може трохи заплутати.
caveman_dick

5

Покладіть компоненти, які можуть бути виправлені окремо всередині власних фрагментів

Це стосується як встановлення продуктів, так і патчів, що якщо ви додаєте будь-який компонент до фрагменту, ви повинні включити всі компоненти в цей фрагмент. У разі створення інсталятора, якщо ви пропустите будь-які посилання на компоненти, ви отримаєте помилку посилання від light.exe. Однак, коли ви робите виправлення, якщо ви додаєте до фрагменту посилання на один компонент, то всі змінені компоненти цього фрагмента з’являться у вашому патчі.

подобається це:

<Fragment>
    <DirectoryRef Id="SampleProductFolder">
        <Component Id="SampleComponent1" Guid="{C28843DA-EF08-41CC-BA75-D2B99D8A1983}" DiskId="1">
            <File Id="SampleFile1" Source=".\$(var.Version)f\Sample1.txt" />
        </Component>
    </DirectoryRef>
</Fragment>

<Fragment>
    <DirectoryRef Id="SampleProductFolder">
        <Component Id="SampleComponent2" Guid="{6CEA5599-E7B0-4D65-93AA-0F2F64402B22}" DiskId="1">
           <File Id="SampleFile2" Source=".\$(var.Version)f\Sample2.txt" />
        </Component>
    </DirectoryRef>
</Fragment>

<Fragment>
    <DirectoryRef Id="SampleProductFolder">
        <Component Id="SampleComponent3" Guid="{4030BAC9-FAB3-426B-8D1E-DC1E2F72C2FC}" DiskId="1">
           <File Id="SampleFile3" Source=".\$(var.Version)f\Sample3.txt" />
        </Component>
    </DirectoryRef>
</Fragment>

замість цього:

<Fragment>
    <DirectoryRef Id="SampleProductFolder">
        <Component Id="SampleComponent1" Guid="{C28843DA-EF08-41CC-BA75-D2B99D8A1983}" DiskId="1">
            <File Id="SampleFile1" Source=".\$(var.Version)\Sample1.txt" />
        </Component>

        <Component Id="SampleComponent2" Guid="{6CEA5599-E7B0-4D65-93AA-0F2F64402B22}" DiskId="1">
           <File Id="SampleFile2" Source=".\$(var.Version)\Sample2.txt" />
        </Component>

        <Component Id="SampleComponent3" Guid="{4030BAC9-FAB3-426B-8D1E-DC1E2F72C2FC}" DiskId="1">
           <File Id="SampleFile3" Source=".\$(var.Version)\Sample3.txt" />
        </Component>
    </DirectoryRef>
</Fragment>

Також під час виправлення, використовуючи тему "Використання чистої WiX" з довідкового файлу WiX.chm, використовуючи цю процедуру для створення патчу:

torch.exe -p -xi 1.0\product.wixpdb 1.1\product.wixpdb -out patch\diff.wixmst
candle.exe patch.wxs
light.exe patch.wixobj -out patch\patch.wixmsp
pyro.exe patch\patch.wixmsp -out patch\patch.msp -t RTM patch\diff.wixmst

недостатньо лише створити 1.1 версію product.wixpdb, побудовану за допомогою компонентів в окремих фрагментах. Тому обов'язково правильно фрагментуйте свій продукт перед доставкою.


5

Друк EULA з Wix3.0 та новіших версій

1) Коли ви компілюєте свій вихідний код wix, light.exe повинен посилатися на WixUIExtension.dll у командному рядку. Для цього використовуйте перемикач командного рядка -ext.

2) Якщо ви додаєте посилання на WixUIExtension.dll, ваш проект не вдасться скомпілювати, це, швидше за все, через зіткнення діалогових ідентифікаторів, тобто ваш проект використовував ті самі ідентифікатори діалогів, що і деякі стандартні діалоги в WixUIExtension.dll, надайте різні ідентифікатори у ваших діалогах. Це досить поширена проблема.

3) У діалоговому вікні ліцензії повинен бути контроль ScrollableText з ідентифікатором "LicenseText". При друкуванні Wix шукає саме таку назву управління.

<Control Id="LicenseText" Type="ScrollableText" X="20" Y="60" Width="330" Height="160" Sunken="yes" TabSkip="no">
    <Text SourceFile="License.rtf" />
</Control>

і PushButton, який посилається на власну дію

<Control Type="PushButton" Id="PrintButton" Width="57" Height="17" X="19" Y="244" Text="Print">
    <Publish Event="DoAction" Value="PrintEula">1</Publish>
</Control>

4) Визначте CustomAction за допомогою id = "PrintEula" так:

<CustomAction Id="PrintEula" BinaryKey="WixUIWixca" DllEntry="PrintEula" Return="ignore" Execute="immediate" />

Примітка: BinaryKey відрізняється від Wix3.0 порівняно з Wix2.0 і має бути точно "WixUIWixca" (з урахуванням регістру).

Коли користувач натисне кнопку, йому буде представлено стандартне діалогове вікно Select Printer і він зможе друкувати звідти.


5
  • Ми відображаємо версію продукту десь (крихітної) на першому екрані графічного інтерфейсу. Тому що люди, як правило, помиляються у підборі правильної версії кожного разу. (І нехай нас розробники шукають віками ..)

  • Ми створили TFSBuild також генерувати перетворення (.mst файли) з конфігурацією для наших різних середовищ. (Ми знаємо про всі середовища, які нам потрібно розгорнути).

Оскільки оригінальна публікація у веб-журналі Гранта Холлідей вниз, я копіюю тут її вміст:


Завдання MSBuild по створенню файлів MSI Transform від XMLMarch 11 2008

У своєму попередньому дописі я описав, як можна використовувати файли MSI Transform (* .mst), щоб відокремити налаштування конфігурації для оточуючого середовища від загального пакету MSI.

Хоча це забезпечує рівень гнучкості у вашій конфігурації, є дві нижчі сторони файлів Transform:

  1. Вони є бінарним форматом
  2. Ви не можете "редагувати" чи "переглянути" файл перетворення. Ви повинні застосувати його або заново створити, щоб побачити, які зміни він включає.

На щастя, ми можемо використовувати об’єктну бібліотеку Microsoft Windows Installer (c: windowssystem32msi.dll) для відкриття MSI "баз даних" та створення файлів перетворення.

Кредити знову повертаються до Алекса Шевчука - від MSI до WiX - Частина 7 - Налаштування установки за допомогою Transforms для показу нам, як цього досягти за допомогою VbScript. По суті, все, що я робив, - це приклад Алекса і за допомогою Interop.WindowsInstaller.dll я реалізував завдання MSBuild. Завдання MSBuild

Завантажте вихідний код та приклад transforms.xml тут (~ 7Kb Zipped VS2008 Solution)



2
Ми переосмислюємо WelcomeDlgTitle у моєму файлі локалізації - чудово працює! <String Id = "WelcomeDlgTitle"> {\ WixUI_Font_Bigger} Ласкаво просимо до майстра настройки [ProductName] [ProductVersion] </String>
saschabeaumont

5

Перед розгортанням інсталяційного пакету я завжди контролюю його вміст.

Це просто простий дзвінок у командному рядку (відповідно до повідомлення Терренса), відкрийте командний рядок і введіть

msiexec /a Package.msi /qb TARGETDIR="%CD%\Extract" /l*vx "%CD\install.log%"

Це дозволить витягнути вміст пакета до підкаталогу "Витягнути" з поточним контуром.


4

Замість ORCA використовуйте InstEd, який є хорошим інструментом для перегляду таблиць MSI. Крім того, він має можливість відрізняти два пакети за допомогою Transform -> Порівняти з ...

Додатково доступна версія Plus з додатковою функціональністю. Але також безкоштовна версія пропонує хорошу альтернативу для Orca.


4

Реєстрація .NET збірок для COM Interop із сумісністю x86 / x64

Примітка Цей фрагмент по суті такий же, як і REGASM Assembly.dll / codebase

У цьому зразку триває кілька речей, тож ось код, і я поясню його згодом ...

  <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <?include $(sys.CURRENTDIR)\Config.wxi?>
  <?if $(var.Win64) ?>
  <?define CLSIDRoots = "CLSID;Wow6432Node\CLSID"?>
  <?else ?>
  <?define CLSIDRoots = "CLSID"?>
  <?endif?>
  <!-- ASCOM Driver Assembly with related COM registrations -->
  <Fragment>
    <DirectoryRef Id="INSTALLLOCATION" />
  </Fragment>
  <Fragment>
    <ComponentGroup Id="cgAscomDriver">
      <Component Id="cmpAscomDriver" Directory="INSTALLLOCATION" Guid="{0267031F-991D-4D88-A748-00EC6604171E}">
        <File Id="filDriverAssembly" Source="$(var.TiGra.Astronomy.AWRDriveSystem.TargetPath)" KeyPath="yes" Vital="yes" Assembly=".net" AssemblyApplication="filDriverAssembly"  />
        <RegistryKey Root="HKCR" Key="$(var.DriverId)"  Action="createAndRemoveOnUninstall">
          <RegistryValue Type="string" Value="$(var.DriverTypeName)"/>
          <RegistryKey Key="CLSID">
            <RegistryValue Type="string" Value="$(var.DriverGuid)" />
          </RegistryKey>
        </RegistryKey>
        <?foreach CLSID in $(var.CLSIDRoots) ?>
        <RegistryKey Root="HKCR" Key="$(var.CLSID)" Action="none">
          <RegistryKey Key="$(var.DriverGuid)" Action="createAndRemoveOnUninstall">
            <RegistryValue Type="string" Value="$(var.DriverTypeName)"/>
            <RegistryKey Key="InprocServer32">
              <RegistryValue Type="string" Value="mscoree.dll" />
              <RegistryValue Type="string" Name="ThreadingModel" Value="Both"/>
              <RegistryValue Type="string" Name="Class" Value="$(var.DriverTypeName)"/>
              <RegistryValue Type="string" Name="Assembly" Value="!(bind.assemblyFullname.filDriverAssembly)" />
              <RegistryValue Type="string" Name="RuntimeVersion" Value="v2.0.50727"/>
              <RegistryValue Type="string" Name="CodeBase" Value="file:///[#filDriverAssembly]" />
              <RegistryKey Key="!(bind.fileVersion.filDriverAssembly)" >
                <RegistryValue Type="string" Name="Class" Value="$(var.DriverTypeName)"/>
                <RegistryValue Type="string" Name="Assembly" Value="!(bind.assemblyFullname.filDriverAssembly)" />
                <RegistryValue Type="string" Name="RuntimeVersion" Value="v2.0.50727"/>
                <RegistryValue Type="string" Name="CodeBase" Value="file:///[#filDriverAssembly]" />
              </RegistryKey>
            </RegistryKey>
            <RegistryKey Key="ProgId" Action="createAndRemoveOnUninstall">
              <RegistryValue Type="string" Value="$(var.DriverId)" />
            </RegistryKey>
            <RegistryKey Key="Implemented Categories" Action="createAndRemoveOnUninstall" >
              <RegistryKey Key="{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" Action="createAndRemoveOnUninstall" />
            </RegistryKey>
          </RegistryKey>
        </RegistryKey>
        <?endforeach?>
      </Component>
    </ComponentGroup>
  </Fragment>
</Wix>

Якщо вам було цікаво, це насправді для драйвера телескопа ASCOM .

По-перше, я взяв поради зверху і створив кілька змінних платформи у окремому файлі, ви можете побачити ті, що розкидані по XML.

Частина "if-then-else" у верхній частині стосується сумісності x86 vs x64. Моя збірка орієнтована на «Будь-який процесор», тож у системі x64 мені потрібно зареєструвати її двічі, один раз у 64-бітному реєстрі та один раз у 32-бітовій Wow6432Nodeобласті. If-then-else встановлює мене для цього, значення використовуються в foreachциклі згодом. Таким чином, мені доведеться лише один раз авторувати ключі реєстру (принцип DRY).

Елемент файлу визначає фактичну встановлену і зареєстровану dll збірки:

<File Id="filDriverAssembly" Source="$(var.TiGra.Astronomy.AWRDriveSystem.TargetPath)" KeyPath="yes" Vital="yes" Assembly=".net" AssemblyApplication="filDriverAssembly"  />

Нічого не революційного, але зауважте Assembly=".net"- саме цей атрибут може призвести до того, що збірка буде передана в GAC, що НЕ є тим, чого я хотів. Використання AssemblyApplicationатрибута для повернення до себе - це просто спосіб зупинити виведення Wix з файлу в GAC. Тепер, коли Wix знає, що це .net збірка, однак, це дозволяє мені використовувати певні змінні сполучення в моєму XML, наприклад, !(bind.assemblyFullname.filDriverAssembly)щоб отримати повну назву збірки.


3

Встановіть DISABLEADVTSHORTCUTSвластивість, щоб змусити всі рекламовані ярлики у вашому інсталяторі стати звичайними ярликами, і вам не потрібно буде включати фіктивний ключ рег, щоб використовуватись як шлях.

<Property Id="DISABLEADVTSHORTCUTS" Value="1"/>

Я думаю, що Windows Installer 4.0 або новішої версії є обов'язковою умовою .


2

Це гарна структура, але, базуючись на моєму досвіді, мені цікаво, як ви вирішуєте ці умови:

A. Здається, всі ваші встановлення приземляються в одному місці призначення. Якщо користувачеві потрібно встановити всі 3 версії відразу, ваш процес дозволить це. Чи можуть вони однозначно сказати, яку версію кожного виконуваного файлу вони запускають?

B. Як ви обробляєте нові файли, які існують у TEST та / або TRENING, але ще не в LIVE?


Привіт Блейн, А. Ні. Вони цього не роблять. InstallName знаходиться в Config.wxi, це єдиний файл, на який не посилається svn: externals. Отже, це унікально для кожної установки, тобто кожного продукту. Ось чому ми змінюємо Посібники для кожної версії. B. GOTO A. :) Вони є окремими MSI із власним UpgradeCode.
si618

1
До речі, я розумію, чому ви відповіли на моє запитання запитанням, але як тільки ви отримаєте достатньо балів повторень, будь ласка, перенесіть своє запитання на коментарі до відповідей, інакше нитка буде важко прослідкувати.
si618

2

Ось спосіб допомогти великим веб-проектам перевірити, чи кількість розгорнутих файлів відповідає кількості файлів, вбудованих в MSI (або модуль об'єднання). Я тільки що запустив власну задачу MSBuild проти нашого основного додатку (ще в розробці), і він зібрав досить багато відсутніх файлів, в основному зображень, але кілька файлів javascript проскочили до!

Цей підхід (зазирнути до таблиці файлів MSI шляхом підключення до AfterBuild-цілі проекту WiX) може працювати для інших типів додатків, у яких ви маєте доступ до повного списку очікуваних файлів.


2

Виконання примусової перевстановлення, коли установка не дозволяє видалити або перевстановити і не відкатується.

Сценарій VBscript, який використовується для заміни установки, яка не видаляється з будь-якої причини.

Dim objShell
set objShell = wscript.createObject("wscript.shell")

iReturn = objShell.Run("CMD /K MsiExec.exe /I ""C:\Users\TheUser\Documents\Visual Studio 2010\Projects\InstallationTarget\HelloInstaller\bin\Debug\HelloInstaller.msi"" REINSTALLMODE=vomus REINSTALL=ALL",,True)

2

Створіть інтерфейс користувача, який має власну дію, яка встановить змінну, і інтерфейс буде відключити / включити наступну кнопку (або подібну) на основі змінної, встановленої в користувацькій дії.

Не такий прямолінійний, як ви могли б подумати, не надто складний, просто ніде не задокументований!

Взаємодія Wix із умовами, властивостями та спеціальними діями

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.