以编程方式构建MSI

Pau*_*els 7 c# installation visual-studio-2008

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

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

mar*_*c_s 5

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


Dev*_*ica 5

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

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

对于安装OP描述的类型,"功能"的MSI /维克斯概念将seeem应用,例如,用户可以检查框以安装或删除某些功能(A"功能"可以是一组文件/程序,一组注册表项等)

在WiX#安装程序中,您在C#安装程序代码的顶部声明带有"ID"的"功能",例如二进制文件,docs,registryEntries等,然后在声明其他安装程序组件时引用该功能ID.(请参阅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%")),
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

虽然维克斯有看目标系统,并确定要安装的方式,我还没有看到维克斯#例子似乎直观,使用自定义操作(这维克斯#支持)的潜在例外,以适应安装程序的行为的一种方式到目标系统将使用自定义操作来设置属性,就像在Wix #sample中的Wix#sample,"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));
Run Code Online (Sandbox Code Playgroud)

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

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

请注意,大括号中的"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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

在这种情况下,我无法弄清楚如何让维克斯#做了一定的部署任务,我可以经常使用的只是包括在.wxs的维克斯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 = "    <SetDirectory Id=\"INSTALLDIR\" Value=\"D:\\Program Files\\DOL\\WA.DOL.HQSYS.ExecECL\" />";
    static string myWIX_INSERT_AFTER_TEXT = "    <InstallExecuteSequence >";
    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);
    }

    /// <summary>
    /// Post-process the Wix .wxs file before compiling it into an MSI
    /// </summary>
    /// <param name="wxsFileName"></param>
    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();
    }
Run Code Online (Sandbox Code Playgroud)

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

Compiler.BuildWxs(Project)
Run Code Online (Sandbox Code Playgroud)

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


hea*_*vyd 2

如果您确实想在代码中执行此操作,您需要查看Windows Installer API。然而,Wix构建了一个很好的托管工具集,这将使使用 XML 语言编写 MSI 变得更加容易。他们还将许多 Windows Installer API 封装在托管包装器中,但要获得 Windows Installer 的全部功能,您需要查看 API 文档。