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

创建一个包含先决条件的Wix#安装程序 - 第2部分

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.96/5 (9投票s)

2018 年 3 月 10 日

CPOL

4分钟阅读

viewsIcon

40338

这是“创建一个包含先决条件的Wix#安装程序”的第2部分

引言

本教程接续了《第 1 部分》的内容,但如果您对 C# 有基本了解,应该不难跟上。今天,我们将着眼于将 .NET Framework 添加为安装程序的先决条件。

本系列文章的组成部分是

  1. 使用 Wix# 创建 MSI 安装程序
  2. 创建包含先决条件的 EXE 安装程序(本文)
  3. 创建自定义操作以简化任务

背景

安装程序很棒,但要求用户查找并安装一个框架对于普通用户来说负担太重了。即使让他们去下载网站,对一些人来说也可能让人不知所措。使用 Wix#,可以轻松地添加一个安装包列表,其中包含用户入门所需的一切。

WiX 工具集依赖于一个名为 Burn 的工具(继续我们的 Candle 主题),用于构建安装先决条件并组合多个 MSI 的 EXE 包。这个过程被称为引导 (BootStrapping)。

假设

我将假设以下几点。 如果这些不正确,您的体验可能会有所不同。

  1. Visual Studio 2017 是您的 IDE
  2. WiX Toolset 已安装
  3. 您正在使用 C# 编码(VB.NET 将具有类似的原理,但需要进行一些翻译)
  4. 您正在使用 Visual Studio 的 WixSharp 项目模板扩展
  5. 您已阅读第 1 部分,并且拥有一个使用 Wix# 的基本 MSI 安装程序项目

使用 Wix# 构建 Bundle

Wix# 中安装程序的引导程序称为 Bundle,它使用 WiX 工具集的 BurnProject。在 WixSharp 项目模板扩展中,Burn Project 被称为 WixSharp Setup - BootStrapper。如果您已经完成了第 1 部分,那么直接对我们的入门项目进行一些更改是最容易的。

首先,将 `WixSharp.Bootstrapper` 添加为 `using` 语句,然后按如下方式重构您的安装程序:

private static void Main()
{
    string productMsi = BuildMsi();

    var bootstrapper =
      new Bundle("SampleInstaller",
          new MsiPackage(productMsi) { DisplayInternalUI = true, Compressed = true })
      {
          UpgradeCode = new Guid(<Insert Your Bundle GUID>),
          Version = new Version(1, 0, 0, 0),
      };
    bootstrapper.Build("SampleBootStrapper.exe");
}

private static string BuildMsi()
{
    var TestDir = new Dir(@"%ProgramFiles%\My Company\My Product");
    TestDir.Files = System.IO.Directory.GetFiles
     (@"D:\Checkouts\WixSharp Tutorial\WixSharp Tutorial\SampleApp\bin\Release").Where
     (file => file.EndsWith(".dll") || file.EndsWith(".exe")).Select(file => new File(file)).ToArray();

    var project = new Project("MyProduct", TestDir);

    project.GUID = new Guid(<Insert Your MSI GUID>);

    return project.BuildMsi();
}

正如您所注意到的,我们仍然以基本相同的方式构建安装程序的 MSI,但之后我们会返回新构建的 MSI 的路径,并围绕它构建一个 Bundle。

通过 Bundle 包含先决条件

现在我们已经构建了一个基本的 Bundle,我们意识到我们的应用程序需要安装 .NET 4.7,而用户可能没有安装。通过 WiX 工具集提供的 `PackageRefGroups`,我们可以检查并安装许多运行时。

private static void Main()
{
    string productMsi = BuildMsi();

    var bootstrapper =
     new Bundle("SampleInstaller",
       new PackageGroupRef("NetFx462Web"),
       new MsiPackage(productMsi) { DisplayInternalUI = true, Compressed = true })
     {
         UpgradeCode = new Guid(< Insert Your Bundle GUID >),
         Version = new Version(1, 0, 0, 0),
     };

    bootstrapper.IncludeWixExtension(WixExtension.NetFx);
    bootstrapper.Build("SampleBootStrapper.exe");
}

上面的关键行是 `new PackageGroupRef("NetFx462Web")` bootstrapper.IncludeWixExtension(WixExtension.NetFx);

`NetFx462Web` 告诉 WiX 通过捆绑 .NET Web 安装程序来安装 .NET 4.62。这可以减小安装程序的大小,但需要互联网连接和对 URL 的访问。您也可以使用 `NetFx462Redist`,它告诉 WiX 捆绑独立的安装程序。WiX 还有可以用来检查 .NET 4.62 是否已安装的变量,以避免不必要地将用户引入安装程序。

打包 .NET 4.7(或任何 .exe)

如果您的应用程序需要 .NET Framework 的 4.7+ 版本,在撰写本文时,WiX 的 NetFx 扩展不支持。但是,基础 WiX 工具包含了完成此任务所需的一切。正如“趣味关注点”中所述,Microsoft 提供了一个深入的指南,介绍如何检测已安装的框架版本。但在 WiX 中做到这一点,我们需要添加一个片段。这个片段结合另一个扩展(Util)基本上允许我们存储注册表搜索的结果。

bootstrapper.IncludeWixExtension(WixExtension.Util);

bootstrapper.AddWixFragment("Wix/Bundle",
    new UtilRegistrySearch
    {
        Root = Microsoft.Win32.RegistryHive.LocalMachine,
        Key = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full",
        Value = "Release",
        Variable = "NetVersion"
    });

此结果找到的值存储为 `NetVersion`,并在条件中使用以确定我们是否需要安装框架。这是重要的一步,直接从 WiX 示例翻译比较困难。

private static ExePackage Net471()
        {
            string currentN2t471webinstaller = 
              @"https://download.microsoft.com/download/8/E/2/8E2BDDE7-F06E-44CC-A145-56C6B9BBE5DD/
              NDP471-KB4033344-Web.exe";
            string Net471Installer = "Net471-web.exe";
            using (var client = new WebClient())
            {
                client.DownloadFile(currentN2t471webinstaller, Net471Installer);
            }
            ExePackage Net471exe = new ExePackage(Net471Installer)
            {
                Compressed = true,
                Vital = true,
                Name = "Net471-web.exe",
                DetectCondition = "NetVersion >= 460798",
                PerMachine = true,
                Permanent = true,
            };

            return Net471exe;
        }

现在我们已经声明了一个 `static` 方法,该方法生成一个 `ExePackage` 供我们的安装程序使用。从这段代码样本中需要注意几个关键点:

  • `WebClient` 来自 `System.Net` 命名空间,在此处用于在构建时下载文件。如果您使用的链接可能并非始终可用,您可能需要将其本地存储,并替换为将文件复制到工作目录的逻辑。
  • `Compressed` 如果为 `true`,则会压缩可执行文件并将其存储在生成的安装程序中,而不是作为单独的文件分发。
  • `Vital` 会导致如果此 EXE 失败,则安装失败并回滚。
  • `DetectCondition` 是我们使用上述变量的地方。根据 Microsoft 的说法,460798 是 .NET 4.7 的最低版本(取决于操作系统)。在这种情况下,我的应用程序是用 4.7 构建的,但我们在安装程序中安装 4.71,以防止在不久的将来决定升级时出现不必要的框架安装。

整合在一起 - 完整代码

using System;
using System.Linq;
using System.Net;
using WixSharp;
using WixSharp.Bootstrapper;

namespace WixSharp_Setup2
{
    class Program
    {
        private static void Main()
        {

            string productMsi = BuildMsi();


            var bootstrapper =
              new Bundle("SampleInstaller",
              Net471(),
                  new MsiPackage(productMsi) { DisplayInternalUI = true, Compressed = true })
              //new PackageGroupRef("NetFx47Web"))
              {
                  UpgradeCode = new Guid(<Insert Your Bundle GUID>),
                  Version = new Version(1, 0, 2, 0),
              };

            bootstrapper.IncludeWixExtension(WixExtension.Util);

            bootstrapper.AddWixFragment("Wix/Bundle",
                new UtilRegistrySearch
                {
                    Root = Microsoft.Win32.RegistryHive.LocalMachine,
                    Key = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full",
                    Value = "Release",
                    Variable = "NetVersion"

                });
            bootstrapper.PreserveTempFiles = true;
            bootstrapper.Application.LicensePath = null;
            bootstrapper.Build("SampleBootStrapper.exe");
        }

        private static string BuildMsi()
        {
            var TestDir = new Dir(@"%ProgramFiles%\My Company\My Product");

            TestDir.Files = System.IO.Directory.GetFiles
            (@"D:\Checkouts\WixSharp Tutorial\WixSharp Tutorial\SampleApp\bin\Release").Where
            (file => file.EndsWith(".dll") || file.EndsWith(".exe")).Select
            (file => new File(file)).ToArray();

            var project = new Project("MyProduct", TestDir);

            project.GUID = new Guid(<Insert Your MSI GUID>);
            //project.SourceBaseDir = "<input dir path>";
            //project.OutDir = "<output dir path>";

            return project.BuildMsi();
        }

        private static ExePackage Net471()
        {
            string currentN2t471webinstaller = 
               @"https://download.microsoft.com/download/8/E/2/8E2BDDE7-F06E-44CC-A145-56C6B9BBE5DD/
               NDP471-KB4033344-Web.exe";
            string Net471Installer = "Net471-web.exe";
            using (var client = new WebClient())
            {
                client.DownloadFile(currentN2t471webinstaller, Net471Installer);
            }
            ExePackage Net471exe = new ExePackage(Net471Installer)
            {
                Compressed = true,
                Vital = true,
                Name = "Net471-web.exe",
                DetectCondition = "NetVersion >= 460798",
                PerMachine = true,
                Permanent = true,
            };

            return Net471exe;
        }
    }
}

关注点

历史

  • 2018 年 3 月 10 日:首次发布
© . All rights reserved.