Уловки и советы по WiX

Мы уже некоторое время используем WiX, и, несмотря на обычные претензии к простоте использования, все идет достаточно хорошо. Я ищу полезный совет относительно:

  • Настройка проекта WiX (макет, ссылки, шаблоны файлов)
  • Интеграция WiX в решения и процессы сборки / выпуска
  • Настройка установщиков для новых установок и обновлений
  • Любые хорошие хаки WiX, которыми вы хотели бы поделиться

person Community    schedule 23.01.2009    source источник
comment
взгляните на gui4wix.codeplex.com   -  person TarunG    schedule 12.07.2011
comment
Закрыто как неконструктивно? Я многому научился, задавая этот вопрос! Немного согласованности из StackOverflow также было бы неплохо ... например. stackoverflow.com/questions/550632/   -  person si618    schedule 22.02.2012
comment
У него 203 ИБП, этого достаточно, чтобы доказать свою полезность.   -  person TarunG    schedule 23.02.2012
comment
ТАК вопросы должны иметь окончательный, правильный ответ; В открытых вопросах вопросы, которые люди задают о реальных проблемах, исчезают с первой страницы. faq @Si .: Эта политика всегда была там AFAIK, но теперь ее лучше применять; этому вопросу почти три года.   -  person Jim Dagg    schedule 22.06.2012
comment
Честно говоря, Джим, это открытый вопрос, и я думаю, что это должно решать сообщество SO, но я должен сказать, что закрытие его как неконструктивного кажется странным, учитывая, что я и, судя по всему, многие другие люди сочли этот вопрос полезным (например, goo.gl/Zqp2X) и что он очень хорошо сочетается с частью practical, answerable questions based on actual problems that you face FAQ.   -  person si618    schedule 13.08.2012
comment
Это полезно (почему я здесь), но это не вопросы и ответы, а обсуждение. Сам вопрос кажется законным, и наиболее популярный в настоящее время ответ кажется законным, но остальные ответы просто добавляют свои 2 цента, что создает ощущение обсуждения.   -  person Fls'Zen    schedule 07.09.2012


Ответы (31)


  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 Роб Меншинг опубликовал отличная запись в блоге, в которой содержится более подробная информация и устраняется край. случай, когда свойства задаются из командной строки.

    Примеры использования 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 привязан к уникальному Guid и никогда не изменится, если мы не хотим обновлять существующий продукт.

    Примечание. В 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. Используйте тепло для сбора файлов с подстановочным знаком (*) Guid. Полезно, если вы хотите повторно использовать файлы 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>
    
person Community    schedule 23.02.2009
comment
Что касается добавления значка в «Установка и удаление программ», это ТОЧНО то, что я искал. Куда вы втыкаете эти три строчки? +1 за чистую крутизну. - person Everett; 02.04.2009
comment
Я обычно помещаю их сразу после (и, очевидно, ниже) элемента ‹Package›. Посмотрите схему на валидность wix.sourceforge.net/manual-wix3/schema_index. htm - person si618; 02.04.2009
comment
+1, если бы я мог сделать +100, это единственная самая полезная часть информации Wix, на которую я наткнулся. - person Tim Long; 20.07.2011
comment
Спасибо, Тим! Роб Меншинг, Боб Арсон, Вим Коэн и другие заслуживают похвалы за то, что поделились своими знаниями. - person si618; 20.07.2011

Проверка, установлен ли 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>

Проверка, установлена ​​ли совместимость метабазы ​​IIS 6 в Vista +:

<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>
person Simon Steele    schedule 05.03.2009

Храните все идентификаторы в отдельных пространствах имен

  • Функции начинаются с F. Примеры: F.Documentation, F.Binaries, F.SampleCode.
  • Компоненты начинаются с C. Пример: C.ChmFile, C.ReleaseNotes, C.LicenseFile, C.IniFile, C.Registry
  • CustomActions: CA. Пример: CA.LaunchHelp, CA.UpdateReadyDlg, CA.SetPropertyX
  • Файлы Fi.
  • Каталоги Di.
  • и так далее.

Я считаю, что это очень помогает в отслеживании всех различных идентификаторов во всех различных категориях.

person Cheeso    schedule 26.11.2009
comment
Я не использую пространства имен, но добавляю идентификаторы; например: ExampleFeature, ChmFileComponent. Думаю, я люблю печатать ;-) - person dvdvorle; 09.05.2012

Фантастический вопрос. Мне бы очень хотелось увидеть некоторые передовые практики.

У меня много файлов, которые я распространяю, поэтому я разместил свой проект в нескольких исходных файлах 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>

Это не идеально, мое чувство ОО-паука немного покалывает, потому что фрагменты должны ссылаться на имена в файле Product.wxs (например, DirectoryRef), но мне легче поддерживать этот единственный большой исходный файл.

Я хотел бы услышать комментарии по этому поводу, или если у кого-то есть хорошие советы!

person Peter Tate    schedule 07.02.2009
comment
Наша установка также очень похожа на этот подход. Это хорошо, потому что мы можем использовать наш эквивалент Products.wxs в качестве базовой настройки для множества продуктов. - person si618; 08.02.2009
comment
@ Питер Тейт: ваше паучье чутье верное. См. Мой ответ о псевдонимах каталогов. - person Wim Coenen; 26.02.2009
comment
Я использую тот же подход: Product.wxs с макетом статичен, а задача сборки (heat.exe) генерирует мой файл Content.wxs - person timvw; 12.06.2010

Установите флажок в диалоговом окне выхода, чтобы запустить приложение или файл справки.

...

<!-- 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>

If you do it this way, the "standard" appearance isn't quite right. The checkbox is always a gray background, while the dialog is white:

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

Один из способов обойти это - указать свой собственный ExitDialog с другим расположением флажка. Это работает, но кажется, что нужно много работать, чтобы просто изменить цвет одного элемента управления. Другой способ решить ту же проблему - постобработка сгенерированного MSI для изменения полей X, Y в таблице Control для этого конкретного элемента управления 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, который выглядит более профессионально:

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

person Cheeso    schedule 26.11.2009
comment
Ха! Не мой блог. Я тоже это читал. И у меня есть ссылка на запись в блоге в тексте выше. Но они сделали это иначе, чем я. Мне мой путь больше нравится !! - person Cheeso; 26.11.2009
comment
Спасибо за js, очень полезно! Одна вещь, которую мне пришлось изменить в wxs, - это заменить WIXUI_EXITDIALOGOPTIONALCHECKBOX на WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed внутри <Publish> - person Alexander Kojevnikov; 10.07.2010
comment
Есть ли способ установить флажок по умолчанию? - person Alek Davis; 25.09.2010
comment
Чтобы установить флажок по умолчанию, я использовал следующее: ‹Property Id = WIXUI_EXITDIALOGOPTIONALCHECKBOX Value = 1 /› - person Alek Davis; 30.09.2010
comment
Похоже на отличное решение, но как мне его использовать? Есть ли способ поместить js в элемент ‹AfterBuild› в моем wixproj? Или, поскольку вы говорите о запуске его из командной строки, лучше ли это использовать в качестве события после сборки, и в этом случае, какой хороший интерпретатор командной строки js для Windows? - person vanmelle; 05.10.2010
comment
Чтобы ответить на свой вопрос, я наконец узнал о встроенном в Windows интерпретаторе js (cscript / wscript). Поэтому я поместил сценарий Cheeso в файл TweakExitDialog.js и добавил следующую строку в команду события после сборки моего проекта установки: cscript $ (ProjectDir) TweakExitDialog.js $ (TargetPath) - работает как шарм! - person vanmelle; 06.10.2010
comment
Ах, да, предлагая этот JS, я предполагал, что люди будут использовать интерпретатор cscript.exe. - person Cheeso; 19.10.2010

Создание версий Live, Test, Training, ... с использованием одних и тех же исходных файлов.

В двух словах: создайте уникальный код обновления для каждого установщика и автоматически определите первый символ каждого идентификатора Guid для каждого установщика, оставив оставшийся 31 уникальный.

Предпосылки

Предположения

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

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

  • Setup.Library
    • All wxs files (Components, Features, UI Dialogs, ...)
    • Common.Config.wxi (ProductCode = "*", ProductVersion, PlatformProgramFilesFolder, ...)
  • Setup.Live (wixproj)
    • Link all Setup.Library files using "Add Existing File" -> "Add As Link" (the little down arrow button right next to the Add button in Visual Studio)
    • Config.wxi (имеет уникальный код обновления, имя продукта, имя установки, ...)
  • Setup.Test, ...
    • as per live but Config.wxi is configured for Test environment.

Процесс

  • Создайте каталог Setup.Library и переместите все ваши файлы wxs и wxi (кроме Config.wxi) из существующего проекта.
  • Создайте Setup.Live, Setup.Test и т. Д. В соответствии с обычным wixproj.
  • Добавьте цель BeforeBuild в wixproj в Setup.Live и т. Д., Чтобы выполнить задачу сообщества MSBuild FileUpdate для изменения руководств (я использовал A для Live, B для тестирования и C для обучения)
  • Добавьте цель AfterBuild, чтобы вернуть Components.wxs Guids обратно к 0.
  • Проверьте с помощью Orca, что каждый компонент в каждом MSI имеет измененный guid.
  • Убедитесь, что исходные направляющие восстановлены.
  • Убедитесь, что каждый 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 вместо Training, если они находятся в одном корпусе, а вы просто используете функции для разных модулей слияния.
  • Если вы используете свой MSI для выполнения обновлений, а также для новых установок, то есть подход только для основного обновления, и вы сохраняете место установки в реестре, не забудьте создать переменную для имени ключа для каждой установки.
  • Мы также создаем переменные в каждом файле Config.wxi, чтобы включить уникальные имена виртуальных каталогов, пулы приложений, имена баз данных и т. Д. Для каждого установщика.

ОБНОВЛЕНИЕ 1: Автоматическое создание идентификаторов компонентов устраняет необходимость вызова задачи FileUpdate, если вы создаете компонент с Guid = "*" для каждого файла, устанавливая файл в качестве пути для ключей.

ОБНОВЛЕНИЕ 2: Одна из проблем, с которой мы столкнулись, заключается в том, что если вы не создаете автоматически Guid компонента и сборка завершается неудачно, временные файлы необходимо удалить вручную.

ОБНОВЛЕНИЕ 3. Обнаружен способ избавиться от зависимости от svn: externals и создания временных файлов. Это делает процесс сборки более устойчивым (и это лучший вариант, если вы не можете использовать подстановочные знаки для своих Guids) и менее хрупким, если происходит сбой сборки при свете или свече.

ОБНОВЛЕНИЕ 4: поддержка Множественные экземпляры, использующие преобразования экземпляров, есть в WiX 3.0+, определенно также заслуживают внимания.

person Community    schedule 23.02.2009
comment
+1 за справку по задачам сообщества MSBuild, мне нравится этот пакет - person BozoJoe; 12.11.2010

Использование журнала диагностики Msi для получения подробной информации об ошибке

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

Where

Package.msi
is the name of your package and
c:\Package.log
is where you want the output of the log

Коды ошибок MSI

Вводное видео Wix
О, и вступительное видео от Wix с участием мистера WiX Роба Меншинга представляет собой полезную концептуальную картину в целом.

person Community    schedule 03.06.2010
comment
+1 Было бы намного лучше, если бы мы могли включить ведение журнала из Wix, а не из командной строки. - person si618; 04.06.2010
comment
WiX делает. Установите свойство MsiLogging. Поддерживается только установщиком Windows 4.0+. - person Rob Mensching; 22.11.2010
comment
Большое спасибо, мистер Уикс. Надо это проверить. - person Terrance; 22.11.2010

Используйте Javascript CustomActions, потому что это так просто

Люди говорят, что Javascript не подходит для MSI CustomActions.. Приведенные причины: трудно отладить, сложно сделать его надежным. Я не согласен. Отладить несложно, конечно, не сложнее, чем C ++. Это просто другое. Я обнаружил, что писать CustomActions в Javascript очень просто, намного проще, чем с использованием C ++. Намного быстрее. И такой же надежный.

Есть только один недостаток: Javascript CustomActions может быть извлечен через 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 для выполнения работы. Легкий.

Связанный вопрос: О CustomActions Javascript

person Cheeso    schedule 26.11.2009
comment
+1 Я считаю, что подход DTF прост в настройке, но javascript тоже может быть полезен. - person si618; 26.11.2009

Питер Тейт уже показал, как можно определять повторно используемые определения 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». Он «просто работает» до тех пор, пока у вас нет циклических зависимостей.

Многоразовый wixlib

Вышеупомянутая идея графа зависимостей работает лучше всего, если вы скомпилируете компоненты big-pool-o-reusable-components в повторно используемый wixlib с помощью lit.exe. При создании настройки приложения вы можете ссылаться на этот wixlib так же, как на файл wixobj. Компоновщик Candle.exe автоматически удалит все фрагменты, которые не «втянуты» основным файлом (-ами) продукта wxs.

person Wim Coenen    schedule 26.02.2009

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

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

person Peter T. LaComb Jr.    schedule 14.12.2009
comment
+1 это действительно хорошо, я не особо беспокоюсь о сборках, но в наших веб-проектах могут быть проблемы со страницами aspx и другими артефактами (изображениями, css), которые добавляются в проект, но не WiX. - person si618; 15.12.2009
comment
Для будущих посетителей в Wix 3.5 есть утилита heat.exe, которая выполняет сбор данных. автоматически - person Mrchief; 23.08.2011
comment
@Mrchief - я не верю, что Heat собирает ссылочные сборки, которые копируются локально - хотя это, по-видимому, запланировано на 4.0. Ссылка: sourceforge.net/tracker/ - person Peter T. LaComb Jr.; 29.08.2011
comment
Тепло не принимает сборки, на которые имеются ссылки. - person tofutim; 24.04.2012
comment
Каковы хорошие примеры использования T4 для создания файла WXS? - person tofutim; 24.04.2012

Включая COM-объекты:

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

Включая управляемые COM-объекты (также известные как COM-объекты .NET или C #)

Использование heat на управляемом COM-объекте даст вам почти полный документ wix.

Если вам не нужна библиотека, доступная в GAC (т. Е. Доступная глобально: В большинстве случаев она вам не нужна для ваших сборок .NET), вы, вероятно, сделали что-то не так, если это не предназначено для разделяемая библиотека), вам нужно обязательно обновить раздел реестра CodeBase, чтобы он был установлен на [#ComponentName]. Если вы планируете установить его в GAC (например, вы создали новую замечательную общую библиотеку, которую все захотят использовать), вы должны удалить эту запись и добавить два новых атрибута к элементу File: Assembly и KeyPath. Сборка должна быть установлена ​​на ".net", а KeyPath должна быть установлена ​​на "да".

Однако в некоторых средах (особенно с управляемой памятью, например, с языками сценариев) также потребуется доступ к Typelib. Обязательно запустите heat в вашей библиотеке типов и включите его. heat сгенерирует все необходимые ключи реестра. Как это круто?

person Robert P    schedule 05.03.2009

Установка в 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>
person Community    schedule 18.08.2010
comment
Не было бы проще просто установить на WindowsVolume? - person Wim Coenen; 18.08.2010
comment
Да, но вам придется использовать обходной путь, потому что свойство WindowsVolume не может использоваться как Directory (компилятор выдает ошибку / предупреждение), как указано в здесь и здесь. Лично я нахожу этот обходной путь запутанным. - person gehho; 19.08.2010

Переменные среды

При компиляции документов Wxs в код wixobj вы можете использовать переменные среды для определения различной информации. Например, допустим, вы хотите изменить, какие файлы включаются в проект. Допустим, у вас есть переменная окружения под названием RELEASE_MODE, которую вы устанавливаете прямо перед сборкой MSI (с помощью скрипта или вручную, это не имеет значения). В исходном коде wix вы можете сделать что-то вроде:

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

а затем позже в вашем коде используйте его вместо того, чтобы на лету изменять ваш документ wxs, например:

<Icon Id="myicon.ico" SourceFile="$(var.FILESOURCE)" />
person Robert P    schedule 09.04.2009
comment
Также доступны переменные компиляции, такие как $ (Конфигурация) и $ (Платформа). Также еще много информации на msdn.microsoft.com/en-us/library/aa302186 .aspx - person si618; 10.04.2009
comment
@Si - раньше эта ссылка уже неактивна. Я не смог найти последнюю. - person Peter M; 06.07.2010

Использование специального шаблона RobM "Запомнить свойство"

http://robmensching.com/blog/posts/2010/5/2/The-WiX-toolsets-Remember-Property-pattern

person Community    schedule 15.11.2010

Создание настраиваемого действия для WIX, написанного в управляемом коде (C #) без Votive

http://www.codeproject.com/KB/install/wixcustomaction.aspx

person Community    schedule 02.12.2010

Диалоги редактирования

Одна хорошая возможность редактировать диалоги - использовать SharpDevelop в версии 4.0.1.7090 (или выше). С помощью этого инструмента можно открывать, просматривать и редактировать автономный диалог (файлы wxs из источников WiX, например InstallDirDlg.wxs) в представлении «Дизайн».

person Community    schedule 13.05.2011
comment
Замечательно, не знал, что SharpDevelop поддерживает это. - person anton.burger; 03.09.2012

Установка флага 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" />
person Community    schedule 08.07.2011

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

Выглядит это так:
альтернативный текст http://i46.tinypic.com/s4th7t.jpg < / а>

Сделайте это с помощью Javascript CustomAction:


Код 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 к кнопке. В этом примере CA запускается, когда в CustomizeDlg щелкают Next:

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

Связанный вопрос SO: Как установить во время выполнения текст, который будет отображаться в VerifyReadyDlg?

person Cheeso    schedule 26.11.2009
comment
Разумеется, это не должен быть JScript, язык сценариев Windows, а не JavaScript, язык сценариев DHTML. Возможно, немного педантичен, но некоторых может сбить с толку. - person caveman_dick; 16.05.2011

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

Это касается как установщиков продуктов, так и исправлений: если вы включаете какой-либо компонент во фрагмент, вы должны включать все компоненты в этот фрагмент. В случае создания установщика, если вы пропустите какие-либо ссылки на компоненты, вы получите сообщение об ошибке связывания от 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

Недостаточно просто иметь версию product.wixpdb 1.1, собранную с использованием компонентов в отдельных фрагментах. Поэтому не забудьте правильно фрагментировать ваш продукт перед отправкой.

person Community    schedule 25.06.2010

Печать лицензионного соглашения с 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» (с учетом регистра).

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

person Community    schedule 02.11.2010

  • Мы отображаем версию продукта где-нибудь (крошечную) на первом экране графического интерфейса. Потому что люди каждый раз склонны ошибаться, выбирая правильную версию. (И заставляют нас, разработчиков искать, целую вечность ..)

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

Поскольку исходный пост Гранта Холлидея в блоге недоступен, я скопировал его содержимое сюда:


Задача MSBuild для создания файлов преобразования MSI из XML 11 марта 2008 г.

В моем предыдущем посте я описал, как можно использовать файлы MSI Transform (* .mst) для отделения параметров конфигурации, зависящих от среды, от общего пакета MSI.

Хотя это обеспечивает уровень гибкости в вашей конфигурации, у файлов преобразования есть два недостатка:

  1. Это двоичный формат
  2. Вы не можете «редактировать» или «просматривать» файл преобразования. Вы должны применить его или воссоздать, чтобы увидеть, какие изменения он включает.

К счастью, мы можем использовать библиотеку объектов установщика Microsoft Windows (c: windowssystem32msi.dll), чтобы открывать «базы данных» MSI и создавать файлы преобразования.

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

Загрузить исходный код и пример transforms.xml здесь (решение VS2008, заархивированное ~ 7 КБ)


person thijs    schedule 23.01.2009
comment
Мы переопределяем WelcomeDlgTitle в моем файле локализации - отлично работает! ‹String Id = WelcomeDlgTitle› {\ WixUI_Font_Bigger} Добро пожаловать в мастер установки [ProductName] [ProductVersion] ‹/String› - person saschabeaumont; 20.08.2009

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

Это просто простой вызов в командной строке (согласно сообщению Терренса), откройте командную строку и введите

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

Это приведет к извлечению содержимого пакета в подкаталог «Извлечь» с текущим путем.

person Community    schedule 20.05.2011

Вместо ORCA используйте InstEd, который является хорошим инструментом для просмотра таблиц MSI. Также он имеет возможность сравнивать два пакета с помощью Transform -> Compare To ...

Кроме того, доступна версия Plus с дополнительными функциями. Но также бесплатная версия предлагает хорошую альтернативу для Orca.

person Community    schedule 20.05.2011

Регистрация сборок .NET для COM-взаимодействия с совместимостью x86 / x64

NB. Этот фрагмент по сути совпадает с 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 и x64. Моя сборка нацелена на «Любой процессор», поэтому в системе x64 мне нужно зарегистрировать ее дважды: один раз в 64-битном реестре и один раз в 32-битных Wow6432Node областях. Для этого меня настраивает if-then-else, значения используются в foreach цикле позже. Таким образом, мне нужно создать ключи реестра только один раз (принцип СУХОЙ).

Элемент файла указывает фактическую сборку 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), чтобы получить полное имя сборки.

person Community    schedule 19.07.2011

Задайте свойство DISABLEADVTSHORTCUTS, чтобы все объявленные ярлыки в вашем установщике стали обычными ярлыками, и вам не нужно включать фиктивный ключ reg, который будет использоваться в качестве пути к клавишам.

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

Я считаю, что установщик Windows 4.0 или выше является требованием < / а>.

person Community    schedule 16.06.2011

Это хорошая структура, но, исходя из моего опыта, мне интересно, как вы справляетесь с этими условиями:

A. Кажется, что все ваши установки попадают в одно и то же место назначения. Если пользователю необходимо установить все 3 версии одновременно, позволит ли это ваш процесс. Могут ли они однозначно сказать, какую версию каждого исполняемого файла запускают?

B. Как вы обрабатываете новые файлы, которые существуют в ТЕСТЕ и / или ОБУЧЕНИИ, но еще не находятся в LIVE?

person Community    schedule 23.02.2009
comment
Привет, Блейн, А. Нет, они этого не делают. InstallName находится в Config.wxi, это единственный файл, на который не ссылается svn: externals. Таким образом, это уникально для каждой установки, то есть для каждого продукта. Вот почему мы изменяем Guids для каждой версии. B. GOTO A. :) Это отдельные MSI-файлы со своим UpgradeCode. - person si618; 23.02.2009
comment
кстати, я понимаю, почему вы ответили на мой вопрос вопросом, но как только вы наберете достаточно очков репутации, переместите свой вопрос в комментарии к ответу, иначе будет сложно следить за темой. - person si618; 23.02.2009

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

Этот подход (просмотр таблицы файлов MSI путем подключения к цели AfterBuild проекта WiX) может работать для других типов приложений, где у вас есть доступ к полному списку ожидаемых файлов.

person si618    schedule 23.03.2009

Выполнение принудительной переустановки, когда установка не позволяет удалить или переустановить и не откатывается.

Сценарий 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)
person Community    schedule 03.06.2010

Создайте пользовательский интерфейс, который имеет настраиваемое действие, которое установит переменную, и пользовательский интерфейс будет отключать / включать следующую кнопку (или аналогичную) на основе переменной, установленной в настраиваемом действии.

Не так просто, как вы думаете, не так уж сложно, просто нигде не задокументировано!

Взаимодействие Wix с условиями, свойствами и настраиваемыми действиями

person Community    schedule 22.06.2011

Исправьте ProgressDlg, чтобы он отображался правильно.

Я увеличил размер шрифта для своего установщика с 8 до 10, чтобы сделать шрифт более человечным и удобным для использования на мониторах с высоким разрешением. Я делаю это с помощью этой магии XML:

<UI Id="MyCustomUI">
  <TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="10" />
  <TextStyle Id="WixUI_Font_Big"    FaceName="Tahoma" Size="12" />
  <TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="14" />
  <TextStyle Id="WixUI_Font_Title"  FaceName="Tahoma" Size="12" Bold="yes" />

  <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
</UI>

Но это означает, что ProgressDlg больше не отображается должным образом. Это тот, который отображает прогресс установки в самом конце. ActionText обрезается, поэтому нисходящие элементы на таких буквах, как g и j, не отображаются. Исправьте это, настроив размер и положение различных элементов управления в диалоговом окне Progressdialog в Javascript постобработке. Запустите этот сценарий после создания MSI:

var msiOpenDatabaseModeTransact = 1;
var filespec = WScript.Arguments(0);
var installer = new ActiveXObject("WindowsInstaller.Installer");
var database = installer.OpenDatabase(filespec, msiOpenDatabaseModeTransact);

// The text on the exit dialog is too close to the title.  This 
// step moves the text down from Y=70 to Y=90, about one line. 
sql = "UPDATE `Control` SET `Control`.`Y` = '90' " +
    "WHERE `Control`.`Dialog_`='ExitDialog' AND `Control`.`Control`='Description'";
view = database.OpenView(sql);
view.Execute();
view.Close();

// The progressbar is too close to the status text on the Progress dialog. 
// This step moves the progressbar down from Y=115 to Y=118, about 1/3 line. 
sql = "UPDATE `Control` SET `Control`.`Y` = '118' " +
    "WHERE `Control`.`Dialog_`='ProgressDlg' AND `Control`.`Control`='ProgressBar'";
view = database.OpenView(sql);
view.Execute();
view.Close();

// The StatusLabel and ActionText controls are too short on the Progress dialog,
// which means the bottom of the text is cut off.  This step
// increases the height from 10 to 16.
sql = "UPDATE `Control` SET `Control`.`Height` = '16' " +
    "WHERE `Control`.`Dialog_`='ProgressDlg' AND `Control`.`Control`='StatusLabel'";
view = database.OpenView(sql);
view.Execute();
view.Close();
sql = "UPDATE `Control` SET `Control`.`Height` = '16' " +
    "WHERE `Control`.`Dialog_`='ProgressDlg' AND `Control`.`Control`='ActionText'";
view = database.OpenView(sql);
view.Execute();
view.Close();

database.Commit();
person Cheeso    schedule 26.11.2009
comment
Иногда это бесценная возможность обновлять элементы управления диалоговым окном прямо в таблицах MSI. Но действительно ли это хорошая практика? Я считаю, что это совершенно непонятно для тех, кто будет использовать ваш код позже. Разве не проще создать собственную последовательность пользовательского интерфейса с нужными вам настраиваемыми диалогами? И гораздо более понятным и читаемым. - person Sasha; 16.11.2012

person    schedule
comment
Есть еще один полезный инструмент для немного других целей: Paraffin (wintellect.com/CS/blogs/jrobbins/archive/2010/03/10/4107.aspx) - person ralf.w.; 22.11.2011