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






4.86/5 (3投票s)
学习使用自定义操作,使 Wix# 更加灵活。
引言
在第 3 部分中,我们的安装程序变得更加复杂。在第 2 部分中确保 .Net 4.7 已安装后,我们将通过利用自定义操作来编写 Apache Tomcat 作为 Windows 服务的安装脚本。
本系列文章的组成部分是
- 使用 Wix# 创建 MSI 安装程序
- 创建捆绑先决条件的 EXE 安装程序
- 创建自定义操作以简化任务(本篇)
背景
WiX 允许 MSI 和 EXE 安装程序执行的操作不仅仅是运行可执行文件和复制文件。 CustomAction
允许您编写各种形式的操作,这些操作可用于诸如在升级期间备份和恢复应用程序设置、设置先决条件或向远程服务器报告安装等操作。
假设
我将假设以下几点。 如果这些不正确,您的体验可能会有所不同。
- WiX Toolset 已安装
- 您正在使用 C# 编码(VB.NET 将具有类似的原理,但需要进行一些翻译)
- 您已经阅读了第 2 部分。如果我们即将使用的某个操作缺少所需的运行时,则会失败。
入门
在这种情况下,我们需要从 MSI 而不是引导程序中为我们的应用程序安装一个先决条件,例如 Apache Tomcat。这与使用 单独的安装程序不同,就像我们从引导程序中使用它一样。
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("6fe30b47-2577-43ad-9095-1861ba25889b");
//project.SourceBaseDir = "<input dir path>";
//project.OutDir = "<output dir path>";
project.Actions = new WixSharp.Action[] {
new ElevatedManagedAction(CustomActions.CheckForApache, "%this%"),
};
return project.BuildMsi();
}
请注意,上面我们向代码添加了一个新 Section。 project.Action
添加了一个操作列表,可以通过多种方式定义。 WiX 的方式主要是 vbs 或 Jscript,但对于 .NET 开发人员来说,Managed Actions 会感觉更熟悉并且更容易维护。 我们已经在下面的单独类中定义了这些操作。
public class CustomActions { [CustomAction] public static ActionResult CheckForApache(Session session) { //check for apache return ActionResult.Success; } }
CustomAction 属性将这些方法标记为安装程序的入口点。 但这不是 WiX/Wix# 的功能,因此您需要在文件顶部添加一个 using 语句。
using Microsoft.Deployment.WindowsInstaller;
实施自定义操作
以下是有关如何选择实现自定义操作(例如上面显示的自定义操作)的代码示例。
检查 Apache
public class CustomActions
{
[CustomAction]
public static ActionResult CheckForApache(Session session)
{
ActionResult result = ActionResult.Success;
try
{
System.ServiceProcess.ServiceController apache = ServiceController.GetServices()
.FirstOrDefault(s => s.ServiceName == "Tomcat8");
if (apache == null)
{
if (System.IO.File.Exists(@"C:\ProgramData\chocolatey\choco.exe"))
{
CmdRunner(@"@"" % SystemRoot %\System32\WindowsPowerShell\v1.0\powershell.exe"" - NoProfile - InputFormat None - ExecutionPolicy Bypass - Command ""iex((New - Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))"" && SET ""PATH =% PATH %;% ALLUSERSPROFILE %\chocolatey\bin");
}
CmdRunner("Choco install Tomcat");
}
}
catch
{
result = ActionResult.Failure;
}
return result;
}
public static void CmdRunner(string cmd)
{
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = @"/C" + cmd ;
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo = startInfo;
process.Start();
process.WaitForExit();
}
}
上面的代码存在一些问题。我们正在强制我们的用户安装 Chocolatey (Windows 的软件包管理器),我们正在检查默认服务名称,并且我们正在安装一个作为安装程序提供的先决条件(此处)。这意味着我们应该将其捆绑在引导程序中。
关注点
- Wix# 自定义操作具有多种风格,如 github 上所示,但对于 .NET 开发人员来说,
ManagedAction
和ElevatedManagedAction
更容易处理。 - 自定义操作仅可在 MSI 中使用,而不能在引导程序中使用。
- WiX Toolset 文档中有关 CustomAction 元素的说明 详细介绍了许多选项,例如
Return
和Execute
。
自定义自定义操作
自定义操作可以不仅仅是我们上面展示的内容。 例如,如果您想在安装后立即启动应用程序怎么办?
new InstalledFileAction("sample_exe", "", Return.asyncNoWait, When.After, Step.InstallFinalize, Condition.NOT_Installed),
这表明此 MSI 安装的文件将在 InstallFinalizes 之后运行,即使在安装程序退出后也会继续运行,但前提是尚未安装该应用程序。
有助于决定何时和什么的关键要素是
Return
告诉 MSI 是否需要处理操作完成,如果是,则如何处理。Execute
确定何时计划执行 CustomAction,例如在失败的 MSI 回滚时。When
与Step
结合使用表示与应执行步骤的时间的关系。
处理错误
请务必将您的 CustomActions 适当地包装在 try/catch
中,并妥善处理错误。 可能需要将错误通知给用户,如果由于异常而未执行 MSI 的重要部分,您将希望使该操作失败。 用于通知用户的选项可能包括弹出错误和/或事件日志消息。
历史
- 2018 年 3 月 16 日:首次发布