我们已经使用WiX有一段时间了,尽管人们对它的易用性有一些抱怨,但它运行得相当不错。我想要的是有用的建议:

设置WiX项目(布局、引用、文件模式) 将WiX集成到解决方案中,并构建/发布流程 为新的安装和升级配置安装程序 任何你想分享的好的WiX技巧


当前回答

创建现场、测试、培训……使用相同源文件的版本。

简而言之:为每个安装程序创建唯一的UpgradeCode,并自动为每个安装程序定义每个Guid的第一个字符,其余31个字符是唯一的。

先决条件

MSBuild社区任务

假设

WiX变量用于定义UpgradeCode、ProductName、InstallName。 您已经有了一个工作的安装程序。你不动手我是不会动手的。 所有组件都保存在一个文件(Components.wxs)中。如果你有多个文件,这个过程是有效的,只是有更多的工作要做。

目录结构

设置。图书馆 所有wxs文件(组件,功能,UI对话框,…) Common.Config.wxi (ProductCode="*", ProductVersion, PlatformProgramFilesFolder,…) 设置。生活(wixproj) 链接所有安装程序。“添加为链接”(Visual Studio中“添加”按钮旁边的向下箭头按钮) 配置。wxi(有唯一的UpgradeCode, ProductName, InstallName,…) 设置。测试,… 按live但配置。wxi为测试环境配置。

过程

Create Setup.Library directory and move all your wxs and wxi files (except Config.wxi) from existing project. Create Setup.Live, Setup.Test, etc as per normal wixproj. Add BeforeBuild target in wixproj in Setup.Live, etc to perform MSBuild Community Task FileUpdate to modify Guids (I used A for Live, B for Test and C for training) Add AfterBuild target to revert Components.wxs Guids back to 0. Verify with Orca that each component in each MSI has the modified guid. Verify that original guids are restored. Verify that each MSI is installing (and upgrading) correct product and location.

例子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属性从Component中去掉(相当于*),每个组件使用一个文件,并将文件设置为小键盘。这样就不需要调用如下所示的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>

最终的想法

This process should also work for creating different installers for different merge modules (Live, Test, ... as features) for the same installer. I went with different installers as it seemed a safer option, there is more risk that someone might upgrade Live instead of Training if they're on the same box and you just use features for the different merge modules. If you use your MSI to perform upgrades as well as new installs i.e. the major upgrade only approach, and you save your installation location in the registry, remember to create a variable for the key name for each install. We also create variables in each Config.wxi to enable unique virtual directory names, application pools, database names, et cetera for each installer.

更新1:如果您为每个文件创建带有Guid="*"的组件,并将文件设置为小键盘,则自动生成组件Guid将不需要调用FileUpdate任务。

更新2:我们遇到的一个问题是,如果您没有自动生成组件Guid,并且构建失败,那么临时文件需要手动删除。

更新3:找到了一种方法来消除对svn的依赖:externals和临时文件创建。这使得构建过程更具弹性(如果您不能通配符您的guid,这是最好的选择),并且在灯光或蜡烛中构建失败时不那么脆弱。

更新4:WiX 3.0+支持使用实例转换的多实例,当然也值得一看。

其他回答

我们将产品版本显示在GUI的第一个屏幕的某个位置(很小)。因为人们每次都倾向于在选择正确版本时犯错误。(这让我们开发人员找了很长时间。) 我们已经设置了TFSBuild来生成转换(。MST文件)为我们不同的环境配置。(我们知道需要部署到的所有环境)。

由于Grant Holliday的原始博客帖子已经关闭,我复制粘贴了它的内容:


MSBuild任务从xml3月11日2008生成MSI转换文件

在我之前的文章中,我描述了如何使用MSI Transform (*.mst)文件将特定于环境的配置设置从通用MSI包中分离出来。

尽管这为您的配置提供了一定程度的灵活性,但Transform文件有两个缺点:

它们是二进制格式的 您不能“编辑”或“查看”转换文件。您必须应用它或重新创建它,以查看它包含哪些更改。

幸运的是,我们可以使用Microsoft Windows安装程序对象库(c:windowssystem32msi.dll)打开MSI“数据库”并创建转换文件。

感谢Alex Shevchuk -从MSI到WiX -第7部分-使用转换自定义安装,向我们展示如何用VbScript实现这一点。基本上,我所做的就是以Alex为例,使用Interop.WindowsInstaller.dll实现了一个MSBuild任务。 MSBuild任务

下载源代码和示例transforms.xml (~7Kb压缩VS2008解决方案)


这是一个很好的结构,但根据我的经验,我想知道你如何解决这些情况:

答:你的安装似乎都落在了同一个目的地。如果用户需要同时安装所有3个版本,您的进程是否允许这样做。它们能明确地说出它们正在触发的每个可执行文件的哪个版本吗?

B.如何处理TEST和/或TRAINING中存在但LIVE中还没有的新文件?

包括COM对象:

Heat生成所有(如果不是全部)注册表项和它们所需的其他配置。喜乐!

包括托管COM对象(又名。net或c# COM对象)

在托管COM对象上使用heat将为您提供一个几乎完整的wix文档。

If you don't need the library available in the GAC (ie, globally available: MOST of the time you do not need this with your .NET assemblies anyway - you've probably done something wrong at this point if it's not intended to be a shared library) you will want to make sure to update the CodeBase registry key to be set to [#ComponentName]. If you ARE planning on installing it to the GAC (eg, you've made some new awesome common library that everyone will want to use) you must remove this entry, and add two new attributes to the File element: Assembly and KeyPath. Assembly should be set to ".net" and KeyPath should be set to "yes".

然而,某些环境(特别是带有托管内存的环境,如脚本语言)也需要访问Typelib。确保在你的打字单上运行热度并包括它。Heat将生成所有需要的注册表项。多酷啊!

使用InstEd代替ORCA,这是一个查看MSI表的好工具。此外,它还具有区分两个包的能力 比较…

此外,一个附加版本与额外的功能是可用的。但免费版也为逆戟鲸提供了一个很好的选择。

创建一个具有自定义操作的UI,该操作将设置一个变量,并且UI将根据自定义操作中设置的变量禁用/启用下一个按钮(或类似的)。

不像你想的那么简单,也不是太难,只是没有任何文档!

Wix与条件,属性和自定义操作的交互