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






4.96/5 (9投票s)
这是“创建一个包含先决条件的Wix#安装程序”的第2部分
引言
本教程接续了《第 1 部分》的内容,但如果您对 C# 有基本了解,应该不难跟上。今天,我们将着眼于将 .NET Framework 添加为安装程序的先决条件。
本系列文章的组成部分是
- 使用 Wix# 创建 MSI 安装程序
- 创建包含先决条件的 EXE 安装程序(本文)
- 创建自定义操作以简化任务
背景
安装程序很棒,但要求用户查找并安装一个框架对于普通用户来说负担太重了。即使让他们去下载网站,对一些人来说也可能让人不知所措。使用 Wix#,可以轻松地添加一个安装包列表,其中包含用户入门所需的一切。
WiX 工具集依赖于一个名为 Burn 的工具(继续我们的 Candle 主题),用于构建安装先决条件并组合多个 MSI 的 EXE 包。这个过程被称为引导 (BootStrapping)。
假设
我将假设以下几点。 如果这些不正确,您的体验可能会有所不同。
- Visual Studio 2017 是您的 IDE
- WiX Toolset 已安装
- 您正在使用 C# 编码(VB.NET 将具有类似的原理,但需要进行一些翻译)
- 您正在使用 Visual Studio 的 WixSharp 项目模板扩展
- 您已阅读第 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; } } }
关注点
- Microsoft 提供了一个出色的指南,介绍如何使用注册表项来检测已安装的 .NET Framework 版本(https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed)
- WiX 的 .NetFx 扩展包含许多预先构建的检测和安装 .NET 的方法(http://wixtoolset.org/documentation/manual/v3/customactions/wixnetfxextension.html)
- 在撰写本文时,WiX 不包含 .NET 4.7 的包。但是,可以通过将安装程序包含为 `ExePackage` 来将其与您的安装程序捆绑,如上所述。
- WiX 的 `ExePackage` 选项将直接映射到 Wix# 中使用的选项(http://wixtoolset.org/documentation/manual/v3/xsd/wix/exepackage.html)
历史
- 2018 年 3 月 10 日:首次发布