WIX:使用 DTF 以编程方式向 msi 安装程序添加和读取 cabinet 文件,以允许动态自定义安装程序
WIX : Adding and Reading cabinet file to msi Installer programatically with DTF to allow dynamic customization of installers
我们使用 WIX 工具集创建了 MSI 安装程序。我们需要根据用户特定文件(例如主题和对话)动态自定义安装程序。
我们用这个 link 添加
但我看不懂。
我们想知道阅读 Cabinet 文件及其文件(自定义文件)的最佳位置。
我们应该在自定义操作中执行此操作还是执行此操作的最佳位置?
另外,我们需要一个示例代码来完成这个任务吗?
注意:- 我们的 Cabinet 文件将包含很多文件(txt 文件、图像等)
我假设,因为你遵循了 link(我自己的问题 none 更少)你现在将文件作为一个新的 cabinet 文件嵌入到 msi 中,带有 MediaID
警告:此回复中的代码暂时未经过测试
请注意,msi 基本上只是一个数据库,可以使用 SQL 之类的语句进行查询。 cab 文件嵌入在数据库中,在 _Streams table 中,并且可以提取为其原始 cab 文件格式。
您可以使用 ORCA 和 7zip 验证这一点。
您提到的 SO 问题的解决方案是针对 "replace" 个文件设计的。
因此,在 msi 构建中使用了一个虚拟文件,并在 wix 中配置了位置。然后在 msi 构建之后,文件 table 被修改,将 wix 生成的原始 cab 文件的引用更改为注入的新 cab 文件。通过这种方式,虚拟文件成为孤立的,但仍嵌入到 msi 中。
如果知道将为每个用户自定义哪些文件,并且所有用户都将具有相同的 folder/file 结构(与自定义无关),则此方法很好。
我假设每个用户的文件数量不同,或者每个用户的文件夹结构不同,因为您不只是复制该解决方案。要实现此 需要进行多次 msi table 编辑。
目录Table:
如果您的 wix 配置尚未定义目录,您将需要在此 table 中创建目录。
类似这样的东西应该允许您插入新目录:
string query = "INSERT INTO `Directory` (`Directory`, `Directory_Parent`, `DefaultDir`) ";
query += "VALUES ('" + The_Directory_ID + "', '" + The_Parents_ID + "', '" + FolderName + ")";
pkg.Execute(query);
从这里开始,必须对新 cab 文件中的所有文件重复所有内容
** 组件 Table **
您需要创建一个组件来控制您的文件,以便它可以被 msiexec installed/uninstalled。
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##" 引用,所以它可能对你有用,否则你需要确定你可以使用的 FileID使用文件中尚未存在的 table..
创建文件夹Table:
通常只有在您需要创建一个空文件夹时才需要,所以我们暂时忽略它,因为您可以将自述文件或其他内容转储到文件夹中..
文件Table
这个 table 告诉 msiexec 在你的 msi 中找到文件的位置,以及文件的版本,所以它知道是否需要复制它、更新它、忽略它等等。
序列号用于告诉 msi 在哪里找到文件,媒体 Table 将序列与 cab 文件或外部媒体相关联..
代码也只是插入,声明:
- 文件: A_FILE_ID
- 分量: The_new_files_name_or_Similar
- 文件名:文件名,(安装时)
- FileSize: 文件大小,以字节为单位...
- 版本:如果文件有版本号就加一个版本号,否则留空。如何检索文件版本取决于文件类型..
- 语言:这是文件的语言版本,一般是1033,如果不知道可以留空..
- 属性: 这取决于媒体文件(柜)是嵌入的、外部的还是文件是外部的等等。使用与文件中其他所有内容相同的编号msi,你通常会没事的。我在build后嵌入cabinet文件时一直使用512。
然后是魔术部分,我们稍后将不得不使用它:
- 序列:您需要获取已在文件 table 中找到的最高序列值,并递增它
特征组件Table
此 table 用于将此添加到功能树中,使用户可以添加或删除此功能。
所有组件都应属于一个功能。
- Feature_ 安装此组件的功能。你可以做一个新的,也可以不做。我建议您使用现有的!
- Component_ The_new_files_name_or_Similar
媒体Table
您提到的代码已经向 msi 添加了一个 cabinet 文件,并在媒体 table:
中创建了一个条目
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 文件制作序列号。
因此文件 table 的序列号大于 msi 中已有的序列号,但低于您已添加的新媒体中的序列号。
注意:cab文件中的文件顺序与序号一致很重要,否则msiexec会报找不到的错误文件。
我们使用 WIX 工具集创建了 MSI 安装程序。我们需要根据用户特定文件(例如主题和对话)动态自定义安装程序。
我们用这个 link 添加
我假设,因为你遵循了 link(我自己的问题 none 更少)你现在将文件作为一个新的 cabinet 文件嵌入到 msi 中,带有 MediaID
警告:此回复中的代码暂时未经过测试
请注意,msi 基本上只是一个数据库,可以使用 SQL 之类的语句进行查询。 cab 文件嵌入在数据库中,在 _Streams table 中,并且可以提取为其原始 cab 文件格式。
您可以使用 ORCA 和 7zip 验证这一点。
您提到的 SO 问题的解决方案是针对 "replace" 个文件设计的。 因此,在 msi 构建中使用了一个虚拟文件,并在 wix 中配置了位置。然后在 msi 构建之后,文件 table 被修改,将 wix 生成的原始 cab 文件的引用更改为注入的新 cab 文件。通过这种方式,虚拟文件成为孤立的,但仍嵌入到 msi 中。
如果知道将为每个用户自定义哪些文件,并且所有用户都将具有相同的 folder/file 结构(与自定义无关),则此方法很好。
我假设每个用户的文件数量不同,或者每个用户的文件夹结构不同,因为您不只是复制该解决方案。要实现此 需要进行多次 msi table 编辑。
目录Table: 如果您的 wix 配置尚未定义目录,您将需要在此 table 中创建目录。
类似这样的东西应该允许您插入新目录:
string query = "INSERT INTO `Directory` (`Directory`, `Directory_Parent`, `DefaultDir`) ";
query += "VALUES ('" + The_Directory_ID + "', '" + The_Parents_ID + "', '" + FolderName + ")";
pkg.Execute(query);
从这里开始,必须对新 cab 文件中的所有文件重复所有内容
** 组件 Table **
您需要创建一个组件来控制您的文件,以便它可以被 msiexec installed/uninstalled。
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##" 引用,所以它可能对你有用,否则你需要确定你可以使用的 FileID使用文件中尚未存在的 table..
创建文件夹Table: 通常只有在您需要创建一个空文件夹时才需要,所以我们暂时忽略它,因为您可以将自述文件或其他内容转储到文件夹中..
文件Table 这个 table 告诉 msiexec 在你的 msi 中找到文件的位置,以及文件的版本,所以它知道是否需要复制它、更新它、忽略它等等。
序列号用于告诉 msi 在哪里找到文件,媒体 Table 将序列与 cab 文件或外部媒体相关联..
代码也只是插入,声明:
- 文件: A_FILE_ID
- 分量: The_new_files_name_or_Similar
- 文件名:文件名,(安装时)
- FileSize: 文件大小,以字节为单位...
- 版本:如果文件有版本号就加一个版本号,否则留空。如何检索文件版本取决于文件类型..
- 语言:这是文件的语言版本,一般是1033,如果不知道可以留空..
- 属性: 这取决于媒体文件(柜)是嵌入的、外部的还是文件是外部的等等。使用与文件中其他所有内容相同的编号msi,你通常会没事的。我在build后嵌入cabinet文件时一直使用512。
然后是魔术部分,我们稍后将不得不使用它:
- 序列:您需要获取已在文件 table 中找到的最高序列值,并递增它
特征组件Table 此 table 用于将此添加到功能树中,使用户可以添加或删除此功能。 所有组件都应属于一个功能。
- Feature_ 安装此组件的功能。你可以做一个新的,也可以不做。我建议您使用现有的!
- Component_ The_new_files_name_or_Similar
媒体Table 您提到的代码已经向 msi 添加了一个 cabinet 文件,并在媒体 table:
中创建了一个条目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 文件制作序列号。
因此文件 table 的序列号大于 msi 中已有的序列号,但低于您已添加的新媒体中的序列号。
注意:cab文件中的文件顺序与序号一致很重要,否则msiexec会报找不到的错误文件。