以编程方式构建MSI

我想创建一个C#程序,它根据许多参数创建一个MSI。 例如,基于用户设置,将包括某些文件,或设置运行时参数。

任何人都可以向我指出任何可能有用的文档,或者让我知道我可能从哪里开始这样的事情?

如果您真的想在代码中执行此操作,则需要查看Windows Installer API 。 但是, Wix构建了一个很好的托管工具集,可以使用XML语言更轻松地创建MSI。 他们还在托管包装器中包装了许多Windows Installer API,但为了获得Windows Installer的全部function,您需要查看API文档。

我一直在使用WixSharp(WiX#),原因只是你描述的原因。 我发现XML驱动的安装程序太丑陋而且不直观,即编辑XML文件作为构建安装程序的一种方式。 我挖掘了基于C#的WiX#作为一种更平易近人的选择。 在我的例子中,我需要生成一个MSI来在服务器上安装.NET DLL(不在GAC中),然后将其注册到COM Interop。

有关Wix#的CodePlex主页的更多信息, 请访问 : http ://wixsharp.codeplex.com/

对于OP描述的安装类型,“function”的MSI / WiX概念将适用于,例如,用户可以选中一个框来安装或省略某些function(“function”可以是一组文件/程序,一组注册表项等)

在WiX#安装程序中,您在C#安装程序代码的顶部声明带有“ID”的“function”,例如二进制文件,docs,registryEntries等,然后在声明其他安装程序组件时引用该functionID。 (请参阅Wix #install附带的“Samples”文件夹中的“AllInOne”Wix#代码),

Feature binaries = new Feature("MyApp Binaries"); Feature docs = new Feature("MyApp Documentation"); ... new File(binaries, @"AppFiles\MyApp.exe", new FileShortcut(binaries, "MyApp", @"%ProgramMenu%\My Company\My Product"), new FileShortcut(binaries, "MyApp", @"%Desktop%")), 

请注意functionID“二进制文件”是声明File和FileShortcut组件的第一个参数,即“新文件(二进制文件……)”,并将这些组件链接到要素ID“二进制文件”中。

此外,MSI安装程序允许您在命令行上指定functionID,例如,

msiexec / i install.msi ADDLOCAL =二进制文件

另请参阅此文章: WIX:如何从命令行选择function

虽然WiX有办法查看目标系统并确定要安装的内容,但我还没有看到Wix#示例看起来很直观,可能除了使用自定义操作(Wix#支持)之外。还有一种方法可以调整安装程序的行为到目标系统将使用自定义操作来设置属性,就像在Wix#deployment中的Wix#samples,“Conditional Installation”中一样。

  //setting property to be used in install condition new Property("INSTALLDESKTOPSHORTCUT", "no"), new ManagedAction(@"MyAction", Return.ignore, When.Before, Step.LaunchConditions, Condition.NOT_Installed, Sequence.InstallUISequence)); 

以前在Wix#installer中返回此代码的链接:

  new Dir(@"%Desktop%", new ExeFileShortcut("MyApp", "[INSTALLDIR]MyApp.exe", "") { Condition = new Condition("INSTALLDESKTOPSHORTCUT=\"yes\"") //property based condition }), 

请注意,花括号中的“Condition”设置为测试属性“INSTALLDESKTOPSHORTCUT”的值为“yes”,它被设置为自定义操作的结果。 自定义操作的C#代码如下所示。

 public class CustomActions { [CustomAction] public static ActionResult MyAction(Session session) { if (DialogResult.Yes == MessageBox.Show("Do you want to install desktop shortcut", "Installation", MessageBoxButtons.YesNo)) session["INSTALLDESKTOPSHORTCUT"] = "yes"; return ActionResult.Success; } } 

对于C#技能组,另一种方法是使用C#程序对msi安装程序进行前端操作,该程序执行如下操作:

  • 查看目标系统用户设置,确定哪些function适合在该系统上安装。
  • 为所选function组装和格式化msiexec命令行和function参数。
  • 执行MSIExec命令行。

可能还有其他“更简洁”的方法,例如,涉及自定义操作等。但是,来自C#技能集,这种方式是平易近人的,可以帮助Windows Installer / WiX学习曲线。 我在Wix#安装程序上工作的结果是,它帮助我逐步学习了一些WiX和Windows Installer。 我经常在WiX中查找如何执行某个部署任务,然后将Wix方式转换为Wix#,以使Wix#在其生成的.wxs文件中生成所需的XML。

在我无法弄清楚如何让Wix#执行某个部署任务的情况下,我经常可以使用简单地在Wix#生成的.wxs文件中包含WiX XML语句,例如通过手动编辑.wxs文件。

例如,WiX和Wix#,提供不是“支持”目标之一的特定驱动器和路径的方式并不直观。 我发现将这个xml片段从Wix#添加到生成的.wxs文件中,然后手动运行Candle然后再运行Light,这对我来说很有用。

我记得跑步时遇到了一些例子,说明如何让Wix#C#代码以编程方式在.wxs语句中包含XML,然后编译.wxs以生成msi。 如果我再次找到Wix#示例,我将更新此答案。

更新我确实找到了示例代码…在Wix#附带的Wix #examples文件夹中的Wix#代码示例中有一对。 但是……它们没有按照我想要的方式工作,并涉及到我还不熟悉的其他Wix#类和对象。 我希望使用“标准”XML C#工具集,而不是Wix#-specific类,将Wix#输出用作XML文本。 因此,我尝试解析.wxs文档XML,并且未能成功使用XPath导航到我想要插入其他WiX XML语句的位置。 (也许我会发布一个SO问题来寻求帮助)。 但是,我确实通过使用WiX XML的文本替换来实现我想要的,将其视为文本字符串。 以下是我成功的工作。

代码所做的是将委托分配给Compiler.WixSourceSaved事件,并且当Wix#代码中调用“Compiler.BuildMsi”方法时,会触发此事件。 在读取了创建的.wxs文件之后(但是在从wxs构建MSI文件之前),我更新了文件中的文本以包含我想要包含的XML行。

然后,基础Wix#事件序列继续并将修改后的wxs构建到最终的MSI中。

  // ... internal class Script static string myWIX_SET_DIRECTORY_STATEMENT = " "; static string myWIX_INSERT_AFTER_TEXT = " "; public static void Main() { // ... (your other Wix# code goes here...) // Hook an event to Wix# save of .wxs file to post-process the .wxs Compiler.WixSourceSaved += PostProcessWxsXMLOutput; // Trigger the MSI file build Compiler.BuildMsi(project); } ///  /// Post-process the Wix .wxs file before compiling it into an MSI ///  ///  private static void PostProcessWxsXMLOutput(string wxsFileName) { StreamReader sr = new StreamReader(wxsFileName); string myWixDocument = sr.ReadToEnd(); sr.Close(); string myProcessedWixDocument = WiXHelpers.InsertFragmentInWiXDocument(myWixDocument, myWIX_INSERT_AFTER_TEXT, myWIX_SET_DIRECTORY_STATEMENT); StreamWriter sw = new StreamWriter(wxsFileName); sw.Write(myProcessedWixDocument); sw.Close(); } 

注意:BuildMsi完成后,将删除.wxs文件。 要强制保存生成的.wxs文件,您需要在Compiler.BuildMsi行之后的Wix#代码中添加一行,如下所示:

 Compiler.BuildWxs(Project) 

这实际上做的是重新激活WixSourceSaved事件,然后调用我的PostProcessXMLOutput委托,该委托重新生成.wxs文件的新的,内容相同的副本。 这次,wxs文件不会自动删除。 生成的wxs文件也将具有比构建中的相应MSI文件更晚的时间戳。

我会看看WiX 。 它有一个相当陡峭的学习曲线,但它会产生msi作为项目构建周期的一部分。

查看WixSharp – 一组C#库,它允许您用C#代码表示安装。 然后将其转换为WiX(XML)文件,该文件又被编译和链接以创建标准MSI(Windows Installer)文件。