WiX/MSI 动态添加 CopyFile 元素
WiX/MSI dynamically add CopyFile elements
我是 Windows 编程的菜鸟,但我必须创建一个棘手的 MSI 安装程序,通过 WiX 工具集安装插件。
安装程序应通过 Windows 注册表 API 检测 运行 特定软件的所有已安装版本及其插件目录。之后,它应该在一个单独的页面(对话框)上显示所有这些,并带有适当的复选框。用户应选择他们希望将插件安装到的版本。
我创建了一个自定义操作(用 C++ 并将其放入 MSI 数据库中的 DLL 中),它与注册表交互 API 然后遍历结果并将临时记录添加到数据库 table秒:
- 添加路径属性以保留插件路径;
- 将记录添加到 CheckBox table;
- 为它们添加属性以保持它们的状态;
- 为他们添加条件而不是检查他们的 属性 状态和 enables/disables 他们;
- 添加事件以根据状态属性重置路径属性。
它在 AppSearch 之后运行
<InstallUISequence>
<Custom Action="PopulateVersions" After="AppSearch">Not Installed</Custom>
</InstallUISequence>
然后单击“下一步”按钮(我知道这样做是错误的)执行过滤活动的自定义操作 属性 路径获取其中的第一个并执行 SetTargetPath 操作(它工作正常).对于其余的,该操作将适当的临时记录插入到:
- DuplicateFile table,其中 DestFolder 是 属性 名称;
- 组件table,从原始组件复制所有字段值,将Component_Parent字段值设置为原始值;
- 目录table。每个路径一条记录 属性,Direcory_Parent 是 TARGETDIR;
它仅将插件安装到引用的第一个 属性 路径(已传递给 SetTargetPath 操作)。
很好...我在 WiX 标记中添加了一些引用我的自定义属性的 CopyFile 元素(我声明了一些属性以防止由于未知属性而导致 MSI 构建错误):
<Property Id="PathProperty0" Value="{}"/>
<Property Id="PathProperty1" Value="{}"/>
<Property Id="PathProperty2" Value="{}"/>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="INSTALLLOCATION" Name="MyPluginDir">
<Component Id="PluginExt" Guid="C112184A-307C-5E15-994F-0DFDA9DD427E">
<File Id="MyPlugin" Name="MyPlugin.dll" Source="MyPlugin.dll" Vital="yes" />
<CopyFile Id="MyPlugin_Copy1" FileId="MyPlugin" DestinationProperty="PathProperty1"/>
<CopyFile Id="MyPlugin_Copy2" FileId="MyPlugin" DestinationProperty="PathProperty2"/>
</Component>
</Directory>
</Directory>
</Directory>
现在 ProgressDialog 说“{}”是无效路径,但所有属性都设置为有效路径(我已经在调试中检查过了)! 在显示要求访问同一 MSI 文件的提升 UAC 提示后,它似乎忘记或忽略了所有临时数据库 changes/property 更改。 单击安装按钮 (带有盾牌图标)。可能它再次读取数据库并没有发现任何更改,因为它们在内存或缓存中,我不知道。
我做错了什么或如何正确制作该安装程序?恕我直言,我的实施过于复杂。我确实需要你的帮助。
我至少看到两个错误:
您要在 运行 时更改的路径属性应该是 PUBLIC properties (that is, their names must not include lower case letters. Furthermore they should probably be listed in the SecureCustomProperties
property, which you can ensure by declaring them in your source with or without a value, and specifying the Secure 属性。
您为目录相关 属性 指定的值实际上是 {}
。这是一个不寻常的值,而且很少是正确的。通常您需要一个空字符串。例外情况是,当您位于 Wix 源的 Formatted
context and need to specify a non-empty string that results in an empty string value, such as a property-setting ControlEvent. The Property 元素时,则不是这样的上下文。
我不确定你所描述的方法的全部复杂性(我还没有完全考虑清楚),但我确实想鼓励你采用编程方式创建 table 数据并让 Windows 安装程序完成剩下的工作。这种方法非常重要,因此被赋予了这样的名称:semi-custom action.
根据半自定义操作指南,您可能希望在 InstallUISequence 和 InstallExecuteSequence 中安排 PopulateVersions 操作(尤其是在它使用 RemoveFile 执行清理时),以确保安装、维护和静默所有删除都会添加适当的 table 数据。
我认为你把事情弄得太复杂了。您可以只创建一个带有一堆 AddInVersionXXXX 子功能的 AddIns 功能,并在功能条件中使用 AppSearch 的结果,然后显示自定义设置对话框。
在我的 IsWiX 中,我做了类似的事情,除了我总是安装到检测到的每个版本。诀窍是如果目录 属性 没有值,CopyFile 将优雅地跳过副本。它真的很简单,可以在这里看到:
我是 Windows 编程的菜鸟,但我必须创建一个棘手的 MSI 安装程序,通过 WiX 工具集安装插件。 安装程序应通过 Windows 注册表 API 检测 运行 特定软件的所有已安装版本及其插件目录。之后,它应该在一个单独的页面(对话框)上显示所有这些,并带有适当的复选框。用户应选择他们希望将插件安装到的版本。
我创建了一个自定义操作(用 C++ 并将其放入 MSI 数据库中的 DLL 中),它与注册表交互 API 然后遍历结果并将临时记录添加到数据库 table秒:
- 添加路径属性以保留插件路径;
- 将记录添加到 CheckBox table;
- 为它们添加属性以保持它们的状态;
- 为他们添加条件而不是检查他们的 属性 状态和 enables/disables 他们;
- 添加事件以根据状态属性重置路径属性。
它在 AppSearch 之后运行
<InstallUISequence>
<Custom Action="PopulateVersions" After="AppSearch">Not Installed</Custom>
</InstallUISequence>
然后单击“下一步”按钮(我知道这样做是错误的)执行过滤活动的自定义操作 属性 路径获取其中的第一个并执行 SetTargetPath 操作(它工作正常).对于其余的,该操作将适当的临时记录插入到:
- DuplicateFile table,其中 DestFolder 是 属性 名称;
- 组件table,从原始组件复制所有字段值,将Component_Parent字段值设置为原始值;
- 目录table。每个路径一条记录 属性,Direcory_Parent 是 TARGETDIR;
它仅将插件安装到引用的第一个 属性 路径(已传递给 SetTargetPath 操作)。
很好...我在 WiX 标记中添加了一些引用我的自定义属性的 CopyFile 元素(我声明了一些属性以防止由于未知属性而导致 MSI 构建错误):
<Property Id="PathProperty0" Value="{}"/>
<Property Id="PathProperty1" Value="{}"/>
<Property Id="PathProperty2" Value="{}"/>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="INSTALLLOCATION" Name="MyPluginDir">
<Component Id="PluginExt" Guid="C112184A-307C-5E15-994F-0DFDA9DD427E">
<File Id="MyPlugin" Name="MyPlugin.dll" Source="MyPlugin.dll" Vital="yes" />
<CopyFile Id="MyPlugin_Copy1" FileId="MyPlugin" DestinationProperty="PathProperty1"/>
<CopyFile Id="MyPlugin_Copy2" FileId="MyPlugin" DestinationProperty="PathProperty2"/>
</Component>
</Directory>
</Directory>
</Directory>
现在 ProgressDialog 说“{}”是无效路径,但所有属性都设置为有效路径(我已经在调试中检查过了)! 在显示要求访问同一 MSI 文件的提升 UAC 提示后,它似乎忘记或忽略了所有临时数据库 changes/property 更改。 单击安装按钮 (带有盾牌图标)。可能它再次读取数据库并没有发现任何更改,因为它们在内存或缓存中,我不知道。
我做错了什么或如何正确制作该安装程序?恕我直言,我的实施过于复杂。我确实需要你的帮助。
我至少看到两个错误:
您要在 运行 时更改的路径属性应该是 PUBLIC properties (that is, their names must not include lower case letters. Furthermore they should probably be listed in the
SecureCustomProperties
property, which you can ensure by declaring them in your source with or without a value, and specifying the Secure 属性。您为目录相关 属性 指定的值实际上是
{}
。这是一个不寻常的值,而且很少是正确的。通常您需要一个空字符串。例外情况是,当您位于 Wix 源的Formatted
context and need to specify a non-empty string that results in an empty string value, such as a property-setting ControlEvent. The Property 元素时,则不是这样的上下文。
我不确定你所描述的方法的全部复杂性(我还没有完全考虑清楚),但我确实想鼓励你采用编程方式创建 table 数据并让 Windows 安装程序完成剩下的工作。这种方法非常重要,因此被赋予了这样的名称:semi-custom action.
根据半自定义操作指南,您可能希望在 InstallUISequence 和 InstallExecuteSequence 中安排 PopulateVersions 操作(尤其是在它使用 RemoveFile 执行清理时),以确保安装、维护和静默所有删除都会添加适当的 table 数据。
我认为你把事情弄得太复杂了。您可以只创建一个带有一堆 AddInVersionXXXX 子功能的 AddIns 功能,并在功能条件中使用 AppSearch 的结果,然后显示自定义设置对话框。
在我的 IsWiX 中,我做了类似的事情,除了我总是安装到检测到的每个版本。诀窍是如果目录 属性 没有值,CopyFile 将优雅地跳过副本。它真的很简单,可以在这里看到: