65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Wix v3.0、Votive 和 Visual Studio 2005/2008 创建安装程序 - 第二部分,GUI

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (55投票s)

2007 年 11 月 28 日

CPL

11分钟阅读

viewsIcon

209099

downloadIcon

1978

介绍如何使用 Visual Studio 2005/2008 创建带 GUI 的 Wix 安装程序。

引言

我们已经看过如何使用 Wix 创建一个基本的安装程序,但对最终用户来说,结果并不令人满意。我们工作所能展示的就是一个带有标题和进度条的小框。在本文中,我们将介绍如何为安装程序添加一个更具吸引力的 GUI。本节将介绍 Wix 内置的 GUI 功能。Wix 的一个强大之处在于其可扩展性,GUI 尤其如此。然而,这种可扩展性超出了本文的范围。

必备组件

假设您已经按照本系列第一篇文章中的步骤进行操作。本文基于第一篇文章的项目,因此如果您打算继续学习,应获取第一篇文章的副本。第一篇文章的先决条件(Wix、安装了 Votive 插件的 Visual Studio)也适用于本文。

入门

我们有 Windows Forms 应用程序,也有 Wix 项目。目前,安装程序不提供用户交互机制。为了提供此功能,我们将为安装程序添加 GUI。

Wix 安装的程序集提供了额外功能。为了使用它们,我们必须将对相应程序集的引用添加到我们的 Wix 项目中。在解决方案资源管理器中选择 ExampleInstaller 项目文件,然后单击项目 --> 添加引用。将出现以下对话框

Screenshot - addReference.png

我们想要的程序集名为 WixUIExtension.dll。它将位于您安装 Wix 的同一目录中。

选中此程序集,单击添加,然后单击确定。这将把 UI 扩展添加到您的 Wix 项目中。现在我们可以为安装程序添加 UI 功能。为此,我们将 <UIRef> 元素添加为 <Product> 元素的子元素。<UIRef> 元素有一个属性 Id,分配给此属性的值控制着所生成 GUI 的样式。属性的可能值为(按复杂度递增顺序)

  • WixUI_Minimal
  • WixUi_InstallDir
  • WixUI_FeatureTree
  • WixUI_Mondo

我们将逐一介绍 GUI 类型,并分析每种类型的功能。

WixUI_Minimal

正如从名称可以推断的那样,这是 UIRef ID 属性可用的最简单的设置。我们将 <UIRef Id="WixUI_Minimal"/> 添加到我们的 wxs 文件中。我们的 wxs 文件现在看起来如下

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
 <Product Id="07cdd126-8d87-46cf-87b0-8731980619fa" 
   Name="Wix installer walkthrough" 
   Language="1033" Version="1.0.0.0" Manufacturer="Duncan Lundie" 
   UpgradeCode="4b2952e6-8ce6-4254-9796-aa510afe5fc0">
  <Package InstallerVersion="200" Compressed="yes" />

  <Media Id="1" Cabinet="ExampleInstaller.cab" EmbedCab="yes" />

  <Directory Id="TARGETDIR" Name="SourceDir">
   <Directory Id="ProgramFilesFolder">
    <Directory Id="INSTALLLOCATION" Name="Installer Example">

     <Component Id="ProductComponent" Guid="17e13748-8d44-47f6-b020-66d29f8a84fe">
      <File d="InstallationTarget.exe"
         Source="../InstallationTarget/InstallationTarget/bin/
                $(var.BUILD)/InstallationTarget.exe">
      </File>
     </Component>
    </Directory>
   </Directory>
  </Directory>

  <Feature Id="ProductFeature" Title="Installation Target" Level="1">
   <ComponentRef Id="ProductComponent" />
  </Feature>
        
  <UIRef Id="WixUI_Minimal"/>
  </Product>
</Wix>

现在我们可以尝试构建安装程序,看看结果是什么样的。不幸的是,此时构建会失败,并出现令人望而生畏的 207 错误。不要惊慌!所有这些错误都源于同一个根本原因,即我们没有为项目设置本地化区域性。在我们不使用 GUI 时,这不成问题,但 GUI 扩展要求设置区域性。这在 Wix 项目属性页的链接器选项卡中完成。似乎目前唯一支持的英语区域性是 en-US(美国英语),因此我们将此值放入区域性文本框中。可以在此处添加多个值,用分号分隔。如果您还记得上一篇文章,这些设置是每个配置的,并且必须为每个构建配置添加。添加了适当的区域性后,我们可以再次尝试构建项目。如果我们一切都做得正确,项目应该会成功构建。

现在我们可以运行我们的最小 GUI 安装程序,应该会看到这个

Screenshot - minimalStart.png

安装程序默认显示 Common Public License 1.0。稍后我们将看到如何更改它。当我们勾选接受许可条款并单击安装时,将出现下一个窗口

Screenshot - minimalMiddle.png

完成后,我们将看到最终确认屏幕

Screenshot - minimalFinish.png

然后,我们单击完成以完成安装。

如您所见,WixUI_Minimal 名副其实。它比非 GUI 安装程序有所改进,如果您不想允许用户自定义安装,它就足够了。如果不是这种情况,那么我们需要一些更具交互性的东西。

WixUi_InstallDir

此属性值允许用户选择应用程序将安装到的目录。为了使用此 GUI 类型,我们首先需要对 wxs 文件进行一些调整,以便安装程序知道它正在自定义哪个目录。

我们将一个 <Property> 类型的元素添加到 wxs 文件中;此元素有两个属性:一个 Id,我们将其设置为 "WIXUI_INSTALLDIR",以及一个 Value,我们将其设置为 "INSTALLLOCATION"。WIXUI_INSTALLDIR Id 让 Wix 知道此属性将告诉它安装到哪个目录。INSTALLLOCATION 值让安装程序知道我们默认使用哪个目录(我们使用嵌套的 <directory> 元素设置的路径)以及该目录的内容(在本例中,是包含我们应用程序的组件)。我们的 wxs 文件现在应该如下所示

 <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Product Id="07cdd126-8d87-46cf-87b0-8731980619fa" 
    Name="Wix installer walkthrough" 
    Language="1033" Version="1.0.0.0" 
    Manufacturer="Duncan Lundie" 
    UpgradeCode="4b2952e6-8ce6-4254-9796-aa510afe5fc0">
  <Package InstallerVersion="200" Compressed="yes" />

  <Media Id="1" Cabinet="ExampleInstaller.cab" EmbedCab="yes" />

  <Directory Id="TARGETDIR" Name="SourceDir">
   <Directory Id="ProgramFilesFolder">
    <Directory Id="INSTALLLOCATION" Name="Installer Example">

     <Component Id="ProductComponent" Guid="17e13748-8d44-47f6-b020-66d29f8a84fe">
      <File Id="InstallationTarget.exe" 
        Source="../InstallationTarget/InstallationTarget/bin/
                $(var.BUILD)/InstallationTarget.exe">
      </File>
     </Component>

    </Directory>
   </Directory>
  </Directory>

  <Feature Id="ProductFeature" Title="Installation Target" Level="1">
   <ComponentRef Id="ProductComponent" />
  </Feature>

   <Property Id="WIXUI_INSTALLDIR" Value="INSTALLLOCATION" ></Property>
  <UIRef Id="WixUI_InstallDir"/>
        
 </Product>
</Wix>

现在我们可以构建安装程序,看看我们所做的更改如何影响我们 GUI 的外观和感觉。

Screenshot - installdirFirst.png

Screenshot - installDirSecond.png

Screenshot - installDirThird.png

这是与最小 GUI 的第一个主要区别——显示了我们的默认安装位置,并提供了更改目录(或键入新目录)的选项。如果我们选择更改,我们将看到这个

Screenshot - installDirChange.png

然后我们可以更改安装目录

Screenshot - installDirChanged.png

然后,完成安装程序。

最后两个窗体与最小安装程序的相同。如果您现在检查在对话框中指定的安装目录,应该会看到一个示例安装目标副本。

WixUI_FeatureTree

WixUI_FeatureTreeWixUI_Mondo 都是 GUI 选项,旨在允许用户自定义安装包运行时安装的功能。我们的安装程序只包含一个功能,因此选择不会太多,但我们至少可以演示一下原理。

要使用 WixUI_FeatureTree,我们需要配置我们提供的功能。用户可以选择安装或不安装功能,因此,我们不定义安装目录属性,而是向功能定义添加一个可配置目录属性。这允许用户为每个功能自定义安装目录。

我们的 wxs 文件现在如下所示

  <?xml version="1.0" encoding="UTF-8"?>
  <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Product Id="07cdd126-8d87-46cf-87b0-8731980619fa" 
     Name="Wix installer walkthrough" Language="1033" 
     Version="1.0.0.0" Manufacturer="Duncan Lundie" 
     UpgradeCode="4b2952e6-8ce6-4254-9796-aa510afe5fc0">
  <Package InstallerVersion="200" Compressed="yes" />

  <Media Id="1" Cabinet="ExampleInstaller.cab" EmbedCab="yes" />

  <Directory Id="TARGETDIR" Name="SourceDir">
   <Directory Id="ProgramFilesFolder">
    <Directory Id="INSTALLLOCATION" Name="Installer Example">

     <Component Id="ProductComponent" Guid="17e13748-8d44-47f6-b020-66d29f8a84fe">
      <File Id="InstallationTarget.exe" 
        Source="../InstallationTarget/InstallationTarget/bin/
               $(var.BUILD)/InstallationTarget.exe"></File>
     </Component>

    </Directory>
   </Directory>
  </Directory>

  <Feature Id="ProductFeature" Title="Installation Target" 
          Level="1" ConfigurableDirectory="INSTALLLOCATION">
   <ComponentRef Id="ProductComponent" />
  </Feature>

  <UIRef Id="WixUI_FeatureTree"/>
        
 </Product>
</Wix>

我们已将 ConfigurableDirectory 属性添加到我们的功能,并将其值设置为 "INSTALLLOCATION",这是我们在嵌套的 <Directory> 元素中描述的安装目录的标识符。现在,当我们构建安装程序时,将有机会自定义此功能的安装位置。我们可以立即尝试。

前两个窗体与 InstallDir 设置中的窗体相似。

Screenshot - installdirFirst.png

Screenshot - installDirSecond.png

第三个窗体是事情变得更有趣的地方

Screenshot - featureTree.png

我们在 wxs 文件中定义的功能已成为我们安装程序中的一个可配置元素,我们为其分配的标题是其标签。从这个屏幕上,我们可以配置安装目录,甚至可以选择是否安装该功能。

Screenshot - featureChoices.png

多个功能

此 GUI 设置还不错,但如果没有其他功能来演示其功能,就显得有些空洞。在这种情况下,我们将仅向项目中添加一些虚拟文本文件,然后将它们定义为功能。

因此,要添加文件,请右键单击 InstallationTarget 项目文件,然后选择添加新项,切换到常规类别(VS2008),然后选择文本文件。将其重命名为 subfeature1.txt。重复此过程三次,以便我们得到 subfeature1.txtsubfeature2.txtsubfeature3.txtsubfeature4.txt

现在我们需要为每个子功能定义一个组件。请记住,一个功能至少需要一个组件。我们将把子功能放在与主安装目标相同的目录中,尽管我们也可以轻松定义子目录。

我们将代码添加到 wxs 文件中,使其现在如下所示

<?xml version="1.0" encoding="UTF-8"?>
 <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Product Id="07cdd126-8d87-46cf-87b0-8731980619fa" 
    Name="Wix installer walkthrough" Language="1033" 
    Version="1.0.0.0" Manufacturer="Duncan Lundie" 
    UpgradeCode="4b2952e6-8ce6-4254-9796-aa510afe5fc0">
  <Package InstallerVersion="200" Compressed="yes" />

  <Media Id="1" Cabinet="ExampleInstaller.cab" EmbedCab="yes" />

  <Directory Id="TARGETDIR" Name="SourceDir">
   <Directory Id="ProgramFilesFolder">
    <Directory Id="INSTALLLOCATION" Name="Installer Example">

     <Component Id="ProductComponent" Guid="17e13748-8d44-47f6-b020-66d29f8a84fe">
      <File Id="InstallationTarget.exe" 
         Source="../InstallationTarget/InstallationTarget/bin/
                $(var.BUILD)/InstallationTarget.exe"></File>
     </Component>
     <Component Id="SubComponent1" 
        Guid="0B01C426-7562-4073-833B-265EE4A31FCD">
      <File Id="Subfeature1.txt" 
        Source="../InstallationTarget/InstallationTarget/Subfeature1.txt"></File>
     </Component>
     <Component Id="SubComponent2" Guid="C481566D-4CA8-4b10-B08D-EF29ACDC10B5">
      <File Id="Subfeature2.txt" 
        Source="../InstallationTarget/InstallationTarget/Subfeature2.txt">
      </File>
     </Component>
     <Component Id="SubComponent3" Guid="44E233A0-CDA2-4adf-B2AF-935A0174325B">
      <File Id="Subfeature3.txt" 
        Source="../InstallationTarget/InstallationTarget/Subfeature3.txt">
      </File>
     </Component>
     <Component Id="SubComponent4" Guid="7F75F6A5-3F09-4921-96F3-D8019FD3954B">
      <File Id="Subfeature4.txt" 
        Source="../InstallationTarget/InstallationTarget/Subfeature4.txt">
      </File>
     </Component>
    </Directory>
   </Directory>
  </Directory>

  <Feature Id="ProductFeature" Title="Installation Target" Level="1" 
         ConfigurableDirectory="INSTALLLOCATION" TypicalDefault="install" >
   <ComponentRef Id="ProductComponent" />
   <Feature Id="SubFeature1" Title="First Subfeature" Level="1" >
    <ComponentRef Id="SubComponent1"/>
    </Feature>
   <Feature Id="SubFeature2" Title="Second Subfeature" Level="1" >
    <ComponentRef Id="SubComponent2"/>
   </Feature>
   <Feature Id="SubFeature3" Title="Third Subfeature" Level="1" >
    <ComponentRef Id="SubComponent3"/>
   </Feature>
   <Feature Id="SubFeature4" Title="FourthSubfeature" Level="1" >
    <ComponentRef Id="SubComponent4"/>
   </Feature>
  </Feature>
</Wix>

构建 Wix 项目。现在,在安装过程中,功能树将如下所示

Screenshot - featuretreenested.png

子功能已嵌套在原始功能下,可以单独或分组安装。尝试一下,您会发现只有选定的子功能(即文本文件)会被放入安装目录。您可能还会注意到,您无法修改子功能的安装位置,只能修改父功能的。

WixUI_Mondo

这是 Wix GUI 的“全部”选项,包括 FeatureTree 选项的元素,以及一个额外的窗体,该窗体为用户提供了安装类型选择——自定义、典型和完整。该窗体看起来如下

Screenshot - mondo.png

选择典型或完整将开始安装,接受默认安装位置(目前)并安装所有可用功能。选择自定义将带我们进入 FeatureTree 部分显示的相同窗体。

定义典型设置

目前,我们安装程序中的“典型”设置与完整设置相同。为了使区分有意义,我们必须定义哪些功能应被视为“典型”。为此,我们使用 INSTALLLEVEL 属性。

INSTALLLEVEL 是 Windows Installer 的内部值,而不是 Wix 的一部分。它是一个整数值。我们 wxs 文件中定义的每个功能都有一个 Level 属性,这也是一个整数。当功能的级别小于或等于 INSTALLLEVEL 时,该功能将被安装。

默认情况下,INSTALLLEVEL 为 1。在使用 WixUI_Mondo 时,单击“典型”按钮会将 INSTALLLEVEL 值设置为 3。反之,单击“完整”会将 INSTALLLEVEL 设置为 1000。

这使我们可以通过更改要包含的功能的 Level 变量(小于或等于 3)和要排除的功能(大于 3)来定义“典型”是什么。

假设我们不喜欢奇数。我们将 SubFeature1SubFeature3Level 属性设置为 4。

   <Feature Id="ProductFeature" Title="Installation Target" Level="1" 
    ConfigurableDirectory="INSTALLLOCATION" TypicalDefault="install" >
   <ComponentRef Id="ProductComponent" />
   <Feature Id="SubFeature1" Title="First Subfeature" Level="4" >
    <ComponentRef Id="SubComponent1"/>
   </Feature>
   <Feature Id="SubFeature2" Title="Second Subfeature" Level="1" >
    <ComponentRef Id="SubComponent2"/>
   </Feature>
   <Feature Id="SubFeature3" Title="Third Subfeature" Level="4" >
    <ComponentRef Id="SubComponent3"/>
   </Feature>
   <Feature Id="SubFeature4" Title="FourthSubfeature" Level="1">
    <ComponentRef Id="SubComponent4"/>
   </Feature>
  </Feature>

现在,当我们构建项目时,我们的典型安装将不包括子功能 1 或 3。

何时使用 GUI 类型

选择哪种 GUI 类型应取决于您希望允许最终用户自定义的程度。

  • 如果您不希望进行任何自定义,但仍希望 GUI 显示许可证协议,则应选择 WixUI_Minimal
  • 如果您只想让用户更改安装目录,请选择 WixUI_InstallDir
  • 如果您的产品默认安装所有功能,但您希望您的用户可以选择禁用某些功能,则应选择 WixUI_FeatureTree
  • 如果您的产品的某些功能默认禁用,并且您希望您的用户能够自定义安装的功能,则应选择 WixUI_Mondo

自定义标准 GUI

更改标准 GUI 的功能超出了本文的范围。但是,我们可以通过多种方式更改 GUI 的外观和感觉。

请记住,将任何变量定义添加到所有构建配置中,因为 Wix 为每个配置都有单独的变量。变量用分号分隔。

许可证

除非您计划将所有软件都发布在 Common Public License 下,否则您首先要更改的可能是许可证文本。

第一步是创建一个包含您要使用的许可证文本的 RTF 文档。我不会回避争议,我选择了 GLP v3。不要使用 Word 创建 RTF(请使用 Wordpad),因为 Wix 在读取 Word RTF 文件时似乎有问题(许可证区域将为空白)。

创建 RTF 文档后,将其保存为 GPL3.rtf 并将其添加到您的 Wix 项目中。

现在,我们必须告诉 Wix 在哪里查找新的许可证文本。在 Wix 项目属性的链接器选项卡中,将文本 WixUILicenseRtf=GPL3.rtf 添加到“定义 Wix 变量”字段中。此变量告诉 Wix 在哪里查找 RTF 文件。如果找不到文件,构建将失败。

开始和完成窗体背景

与许可证文本非常相似,我们可以通过添加新文件来更改 GUI 开始和完成窗体的背景。文件应为位图,尺寸为 493 像素 x 312 像素。我称我的为 bigback.bmp。在这种情况下,您无法更改文本布局,因此我建议将图像的右侧留空,以免干扰可读性。

将位图添加到您的项目,然后设置变量 WixUIDialogBmp=bigback.bmp。重新构建安装程序,背景图像应更改为您指定的位图。

Screenshot - customisedInstaller.png

顶部横幅

此文件的格式应为位图,尺寸为 493 x 58 像素。我称我的为 banner.bmp。相应的变量设置为 WixUIBannerBmp

Screenshot - custombanner.png

© . All rights reserved.