在每台计算机安装程序中删除 HKCU 下的注册表键。

12

我使用WiX 3.6构建了一个针对单台计算机的安装程序,以安装我没有开发的软件。不幸的是,在执行过程中,该软件会在HKCU下创建一些注册表键。

在卸载时,这些自创的键也应该被删除。但似乎不太容易删除这些键。我正在与ICE57和/或ICE38进行“斗争”。它们都抱怨perUser和perMachine数据的混合。

希望您可以指导我解决此问题的正确方向。

2个回答

9

为了克服ICEs,您应该将每个用户注册表移动到单独的组件中,并使用一些注册表项作为该组件的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是唯一可行的选择。

首先,我建议您在安装或重新安装时删除它们,而不是在卸载时删除它们,您只需要添加RemoveRegistry条目和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 &quot;HKLM\SOFTWARE\Microsoft\Active Setup\Installed Components\MySoftName_CleanUp&quot; /v StubPath /d &quot;reg add ^&quot;HKCU\Key\To\Be\Removed^&quot; /va /f&quot; /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运行了Active Setup,并且你决定重新安装相同的软件包,它将不会再次运行,除非你更改其PackageConde或在ActiveSetup注册表键下提高版本。这些是另一个时间讨论的主题,如果需要澄清,请告诉我。

而且不要忘记将以上所有组件添加到某个功能中。


1
Windows Installer将其视为用户数据,最佳实践是不要删除它。无论如何,由于其他用户配置文件不在范围/上下文之内,尝试删除它非常困难。理论上说,可以编写自定义操作以枚举配置文件并加载注册表文件,但在某些Windows版本(如Vista)中,由于Windows Installer服务授予了受限权限,这种方法将行不通。
如果您确实必须能够在卸载时删除自定义操作数据,请查看: Active Setup Explained 您需要标记一个组件为永久性,留下一个程序(例如exe)。然后,您需要通过自定义操作在卸载期间写入注册表值(因为Windows Installer不支持此操作)。
概念是在安装期间放置一个EXE,在卸载期间离开您。然后,您编写ActiveSetup注册表键,告诉它为每个后续登录到计算机的用户运行您的EXE一次。然后,EXE会删除您的注册表值。如果需要从资源管理器中卸载扩展名,则重新启动(有礼貌地)。
但是,老实说,一个更好设计的应用程序不需要所有这些。

扩展资源管理器上下文菜单的注册表键。如果不删除它,将导致废弃的菜单。 - tequila slammer
为什么它是按用户而不是按机器进行扩展的? - Christopher Painter
更新答案以包括对hack的引用。 - Christopher Painter
在我的当前解决方案中,我在安装时创建密钥,以便在卸载时删除它们。但如果用户通过软件配置了他们的上下文菜单,则不是所有用户都会这样做。感谢您指出了活动设置的方法。 - tequila slammer
引用的链接文章似乎已经不再可用,我在谷歌上搜到的是这篇文章Active Setup Explained • Helge Klein,它是同一篇吗? - Wolf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接