WIX:使用DTF以编程方式向msi安装程序添加和读取cabinet文件,以允许动态自定义安装程序

时间:2016-04-05 12:56:24

标签: c# .net wix windows-installer dtf

我们使用WIX工具集创建了MSI安装程序。我们需要根据用户特定的文件动态自定义安装程序,例如主题和对话。 我们使用此链接添加Add Cabinet File to Installer 但我无法读懂它。 我们想知道读取Cabinet文件及其文件(自定义文件)的最佳位置。 我们应该在自定义操作中执行此操作,或者最佳位置是什么? 此外,我们需要一个示例代码,我们可以遵循它来完成此任务? 注意: - 我们的Cabinet文件将包含很多文件(txt文件,图像等)

1 个答案:

答案 0 :(得分:1)

我假设,因为你遵循了这个链接(至少我自己的问题)你现在将msi中嵌入的文件作为带有MediaID的新cabinet文件

警告:此回复中的代码现在都未经过测试

请注意,msi基本上只是一个数据库,可以使用SQL语句查询。可以在_Streams表中的数据库中嵌入cabfiles,并可以将其解压缩为原始的cab文件格式。

您可以使用ORCA和7zip验证这一点。

您提到的SO问题的解决方案旨在"替换"文件。 因此在msi构建中使用了一个虚拟文件,并且在wix中配置了放置。然后在msi构建之后,修改了文件表,将引用从wix生成的原始cab文件更改为注入的新cab文件。通过这种方式,虚拟文件​​在孤立的地方,但仍嵌入在msi中。

当知道为每个用户定制哪些文件,以及所有用户将具有相同的文件夹/文件结构时,这种方法很好,而与自定义无关。

我假设您为每个用户提供了不同数量的文件,或者每个用户都有不同的文件夹结构,因为您并不只是复制该解决方案。要实现此,需要进行几次msi表格编辑。

目录表: 如果尚未由wix配置定义目录,则需要在此表中创建目录。

这样的事情应该允许你插入新的目录:

    string query = "INSERT INTO `Directory` (`Directory`, `Directory_Parent`, `DefaultDir`) ";
    query += "VALUES ('" + The_Directory_ID + "', '" + The_Parents_ID + "', '" + FolderName + ")";
    pkg.Execute(query);

从现在开始,必须为新的cab文件中的所有文件重复所有内容

**组件表**

您需要创建一个控制文件的组件,以便msiexec可以安​​装/卸载它。

    string query = "INSERT INTO `Component` (`Component`, `ComponentId`, `Directory_`, `Attributes`, `Condition`, `KeyPath`) ";
    query += "VALUES ('" + The_new_files_name_or_Similar + "', '{" + FileGUID + "}', '" + The_Directory_ID + "0, \"\", "+ A_FILE_ID +" )";
    pkg.Execute(query);

其中:

  • 可以使用Guid.NewGuid() ..
  • 生成FileGUID
  • A_FILE_ID可以是文件名,如果wix生成MSI,则所有其他通常由" FileID ##"引用。所以它可能适合你,否则你需要确定你可以使用的文件表中没有的文件ID ..

CreateFolder表: 通常只有在你需要创建一个空文件夹时才需要,所以我们暂时忽略它,因为你可以在文件夹中转储自述文件或其他东西..

文件表 此表告诉msiexec在msi中找到该文件的位置,以及该文件所在的版本,因此它知道是否需要复制,更新,忽略它等等。

序列号用于告诉msi在哪里找到文件,媒体表将序列与cab文件或外部媒体相关联。

代码也只是插入,声明:

  • 文件: A_FILE_ID
  • 组件: The_new_files_name_or_Similar
  • 文件名:文件名,(安装时)
  • FileSize:这是文件大小,以字节为单位......
  • 版本:如果文件有版本号,请添加版本号,否则留空。如何检索文件版本取决于文件类型..
  • 语言:这是文件语言版本,通常为1033,但如果您不知道,可以将其留空。
  • 属性:这取决于媒体文件(cabinet)是嵌入式,外部还是文件是外部的等等。使用与msi中其他所有内容相同的编号,您和# 39;经常会好的。在构建之后嵌入cabinet文件时,我总是使用512。

然后是神奇的部分,我们将在稍后使用:

  • 序列:您需要获取已在File表中找到的最高序列值,并将其递增

FeatureComponent表 此表用于将其添加到功能树,使用户可以添加或删除此功能。 所有组件都应属于某个功能。

  • 功能_ 安装此组件的功能。你可以新建一个。我建议您使用现有的一个!
  • 组件_ The_new_files_name_or_Similar

媒体表 您引用的代码已经将一个cabinet文件添加到msi,并在媒体表中创建一个条目:

IList<int> sequences = pkg.ExecuteIntegerQuery("SELECT `LastSequence` FROM `Media` ORDER BY `LastSequence`");
lastIndex = sequences.Count - 1;
int LastSequence = sequences.ElementAt(lastIndex) + numberOfFilesToAdd;
query = "INSERT INTO `Media` (`DiskId`, `LastSequence`, `Cabinet`) VALUES (" + DiskId.ToString() + "," + LastSequence.ToString() + ",'#" + mediaCabinet + "')";
pkg.Execute(query);

所以这应该已经为你设置了.. 如果其他人偶然发现了这个答案,我在这里复制了相关的片段,以显示如何为新的cab文件制作序列号。

因此文件表的序列号大于msi中已有的序列号,但低于您已添加的新媒体中的序列号。

注意: cab文件中的文件与序列号的顺序非常重要,否则msiexec会抛出无法找到文件的错误。