我们使用 WIX 工具集创建了我们的 MSI 安装程序。我们需要根据用户特定的文件(例如主题和对话)动态自定义安装程序。我们使用此链接将添加内阁文件添加到安装程序 ,但我无法阅读它。我们想知道阅读内阁文件及其文件(自定义文件)的最佳位置。我们应该在自定义操作中执行此操作还是最好的位置是什么?另外,我们需要一个可以遵循的示例代码来完成此任务吗?注意:- 我们的内阁文件将包含很多文件(txt 文件,图像等)
1 回答
我假设,因为您点击了该链接(仍然是我自己的问题)您现在将文件嵌入到 msi 中,作为具有 MediaID 的新文件柜文件
警告:此回复中的代码暂时未经测试
请注意,msi 基本上只是一个数据库,可以使用类似 SQL 的语句进行查询。cabfiles 嵌入在数据库中的 _Streams 表中,可以提取为其原始 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);
在哪里:
- FileGUID 可以使用
Guid.NewGuid()
.. - A_FILE_ID 可以是文件名,如果 wix 生成 MSI,则所有其他文件通常由“FileID##”引用,因此它可能对您有用,否则您需要确定您可以使用的 FileID 尚未在文件表中..
CreateFolder Table: 通常仅在您需要创建一个空文件夹时才需要,因此我们现在将忽略它,因为您可以在文件夹中转储自述文件或其他内容..
文件表 这个表告诉 msiexec 在你的 msi 中找到文件的位置,以及文件所在的版本,所以它知道是否需要复制它、更新它、忽略它等等。
序列号用于告诉 msi 文件的位置,媒体表将序列与 cab 文件或外部媒体相关联。
该代码也只是一个insert into , 语句:
- 文件: A_FILE_ID
- 组件: The_new_files_name_or_Similar
- 文件名:文件名,(安装时)
- FileSize:它是文件大小,以字节为单位...
- 版本:如果文件有版本号,则添加版本号,否则留空。如何检索文件版本取决于文件类型。
- 语言:这是文件语言版本,通常为 1033,但如果您不知道,可以将其留空。
- 属性:这取决于媒体文件(机柜)是嵌入的、外部的还是文件是外部的等。使用与 msi 中其他所有内容相同的编号,您通常会没事的。构建后嵌入cabinet文件时,我一直使用512。
然后是魔术部分,我们稍后将不得不使用它:
- 序列:您需要获取文件表中已经找到的最高序列值,并将其递增
FeatureComponent Table 此表用于将其添加到特征树中,使用户可以添加或删除此特征。所有组件都应该属于一个特征。
- Feature_安装此组件的功能。你可以做一个新的,也可以不做。我建议您使用现有的!
- Component_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会抛出找不到文件的错误。