我使用 WiX 3.6 构建了一个 perMachine 安装程序来安装我没有开发的软件。不幸的是,该软件在执行期间会在 HKCU 下创建一些注册表项。
卸载时,还应删除自行创建的密钥。删除这些键似乎并不容易。我正在与 ICE57 和/或 ICE38 “战斗”。两者都抱怨 perUser 和 perMachine 数据之间的混合。
希望您能指出我解决此问题的正确方向。
要克服 ICE,您应该将 Per-User 注册表移动到单独的组件,并使用一些注册表项作为该组件的 keyPath,即:
<Component Id='PerUserRegistry' Guid='*'>
<RegistryValue Id="PerUserRegistry_KeyPAth" KeyPath="yes" Root="HKCU" Key="Software\[Manufacturer]\[ProductName]\[ProductCode]\PerUserRegistry" Name="[PackageCode]" Value="[ProductVersion]" Type="string" />
<!--Other Per-user registry goes here-->
</Component>
我完全同意 Christopher 的观点:通常的做法是在卸载时保留每个用户的数据,但如果需要删除,那么 Active Setup 是唯一真正的选择。
首先,我建议您在安装或重新安装时删除它们而不是卸载,您只需要添加 RemoveRegirty 条目和 Active Setup,即使用以下 WiX 代码:
<Component Id='ActiveSetup' Guid='*'>
<RegistryValue Id="ActiveSetup00" Root="HKLM" KeyPath="yes" Key="SOFTWARE\SOFTWARE\Microsoft\Active Setup\Installed Components\[PackageCode]\" Name="StubPath" Value="msiexec /fup [ProductCode] /qb-!" Type="string" />
<RegistryValue Id="ActiveSetup01" Root="HKLM" Key="SOFTWARE\SOFTWARE\Microsoft\Active Setup\Installed Components\[PackageCode]\" Value="[ProductName] [ProductVerion] Configuration" Type="string" />
</Component>
<Component Id='PerUserRegistryCleanup' Guid='*'>
<RegistryValue Id="PerUserRegistry_KeyPath" Root="HKCU" KeyPath="yes" Key="SOFTWARE\SOFTWARE\Microsoft\Active Setup\Installed Components\[PackageCode]\" Name="StubPath" Value="msiexec /fup [ProductCode] /qb-!" Type="string" />
<RemoveRegistryKey Id='PerUserRegCleanup' Root='HKCU' Action='removeOnInstall' Key='Key\To\Be\Removed'/>
</Component>
注意:非常推荐在 ActiveSetup 中使用 [PackageCode],因此对于 MSI 包的每个新版本(构建),您都添加单独的条目(另见我的最后说明)。我故意使用每个用户的活动设置注册表作为键路径,所以你不要为当前用户运行它两次。
至于卸载后删除它们,现在,希望您需要删除整个密钥,而不仅仅是一些值。在任何一种情况下,我都会创建自定义操作以在卸载期间为 Active Setup 添加注册表项(或者如果有许多这样的键/值,创建和部署 .CMD 文件并在卸载时启动它,然后在 RemoveFiles 操作之前添加所有其中注册)。
注意:我强烈建议在安装期间添加删除此注册表,否则您可能最终会在安装软件时删除每个用户的值。
所以这是所有这些的WiX代码:
<CustomAction Id="CA_UninstallRegistryCleanUp" Directory="SystemFolder" ExeCommand="REG.exe ADD "HKLM\SOFTWARE\Microsoft\Active Setup\Installed Components\MySoftName_CleanUp" /v StubPath /d "reg add ^"HKCU\Key\To\Be\Removed^" /va /f" /f" Return="ignore" />
<InstallExecuteSequence>
<Custom Action='CA_UninstallRegistryCleanUp' After='RemoveRegistryValues'>REMOVE~="ALL"</Custom>
</InstallExecuteSequence>
<Component Id='RegCleanup_Remover' Guid='*'>
<RegistryValue Id="PerUserRegistry_KeyPAth" Root="HKLM" KeyPath="yes" Key="SOFTWARE\[Manufacturer]\[ProductName]\[ProductCode]\" Name="DummyKey" Value="[ProductVersion]" Type="string" />
<RemoveRegistryKey Id='RegCleanup_Remover' Root='HKLM' Action='removeOnInstall' Key='SOFTWARE\Microsoft\Active Setup\Installed Components\MySoftName_CleanUp'/>
</Component>
最后说明:所有这些 Active Setup 的东西只有两个小问题:在 Windows 终端服务器上要小心;并且一旦为当前 .MSI 的一个用户运行了活动安装程序,如果您决定重新安装相同的软件包,它将不会再次运行,除非您更改其 PackageConde 或在 ActiveSetup 注册表项下提高版本。这些是另一天的主题,如果需要澄清,请告诉我。
并且不要忘记将上述所有组件添加到某些功能中。
Windows 安装程序会考虑此用户数据,最佳做法是不删除它。无论哪种方式,都很难尝试将其删除,因为其他用户配置文件超出了范围/上下文。理论上可以编写自定义操作来枚举配置文件和加载注册表配置单元,但在某些版本的 Windows ( Vista ) 上由于授予 Windows 安装程序服务的权限受限而无法工作。
如果您真的必须能够在卸载时删除自定义操作数据,请查看:
您将需要通过将组件标记为永久来留下程序(例如 exe)。然后,您将需要一个自定义操作来在卸载期间写入注册表值(因为 Windows Installer 不支持此操作)。
这个概念是在安装过程中你放下一个 EXE,在卸载过程中你离开你。然后,您写入 ActiveSetup 注册表项,告诉它为每个后续用户登录到计算机运行一次 EXE。EXE 然后删除您的注册表值。如果需要从资源管理器中卸载扩展,请重新启动(礼貌地)。
但老实说,一个设计更好的应用程序不需要所有这些。