3

编辑:引用我自己的话,因为我在下面的评论之一中更好地总结了这个问题......</p>

我有一个条件,在安装包时为真,但在删除它时不为真。我希望 MSI 记住它已经安装了条件组件并通过卸载将其删除,但事实并非如此。我正在尝试找出 A) 清理此孤立组件的正确方法,以及 B) 将来防止此问题的最佳方法。

我想我的问题归结为,在卸载产品后删除孤立的功能/组件是否安全?有没有办法检查什么(如果有的话)仍在引用我认为是孤儿的组件?以及如何修复我的安装程序以防止将来发生这种情况?

我们有一个 wix 项目来安装库 Foo。默认情况下,此安装程序将 Foo.dll 的副本放入 GAC 和文件夹中Program Files\Reference Assemblies\Foo\<version>。安装程序还添加了两个注册表项,一个是自定义键,用于存储 Foo 文件夹的路径以供将来安装时重复使用,另一个告诉 Visual Studio<version>在其搜索已安装库时包含完整文件夹路径,以便 Foo 显示在“添加引用”对话框。可以一次在机器上安装多个版本的 Foo 库,每个版本都位于<version>Foo 下的相应文件夹中。

Foo 2.0.0 有一个错误通过测试,Foo 2.0.1 包含错误修复,没有其他更改。决定由于错误修复是唯一的更改,我们将向 GAC 添加一个策略文件,它将 Foo 2.0.0 的引用重定向到 Foo 2.0.1。此策略文件已作为新功能中的新组件添加到安装程序中。添加了升级标签以在安装 Foo 2.0.1 时检测和删除 Foo 2.0.0。策略功能的安装以检测到 Foo 2.0.0 为条件。一切似乎都正常,Foo 2.0.1 被推出。

现在,一年后,我们发现我们再次错过了注意到一个错误,这次是在安装程序设置而不是库代码中。事实证明,当 Foo 2.0.1 替换 2.0.0,然后被卸载时,策略文件是孤立的并保留在 GAC 中,而所有其他文件和密钥都被删除。我已经在全新安装的 Windows 上对此进行了测试(虚拟机非常有用),并确认该问题可以被复制,即没有对组件的额外引用偷偷进入以使其落后。

所有这些最初都是在 WiX 3.0 中完成的,但我们最近升级到使用 WiX 3.5。我们的 WiX 代码如下所示:

<Product Id="Guid 1" Name="Foo v2.0.1" Language="1033" Version="2.0.1" Manufacturer="My Team" UpgradeCode="Guid 2">

  <Package InstallerVersion="300" Compressed="yes" />

  <Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />

  <Upgrade Id="Guid 2">
    <UpgradeVersion Minimum="2.0.0" Maximum="2.0.0" IncludeMaximum="yes" IncludeMinimum="yes" OnlyDetect="no" Property="UPGRADE2X0X0"></UpgradeVersion>
  </Upgrade>

  <Property Id="FOODIR">
    <RegistrySearch Id="FooPath" Type="directory" Root="HKLM" Key="Software\Foo" Name="InstallPath"></RegistrySearch>
  </Property>

  <Directory Id="TARGETDIR" Name="SourceDir">
    <Directory Id="ProgramFilesFolder">
      <Directory Id="RefAssemb" Name="Reference Assemblies">
        <Directory Id="FOODIR" Name="Foo">
          <Component Id="FooLibPath" Guid="Guid 3">
            <RegistryKey Root="HKLM" Key="Software\Foo" Action="createAndRemoveOnUninstall">
              <RegistryValue Name="InstallPath" Type="string" Value="[FOODIR]" KeyPath="yes"></RegistryValue>
            </RegistryKey>
          </Component>
          <Directory Id="FOOVERSION" Name="v2.0.1">
            <Component Id="Foo_VSFile" Guid="Guid 4">
              <File Id="Foo_DLL" Source="$(sys.CURRENTDIR)2.0.1\Foo.dll" KeyPath="yes"></File>
            </Component>
            <Component Id="Foo_VSRegKey" Guid="Guid 5">
              <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\.NETFramework\v3.5\AssemblyFoldersEx\Foo v2.0.1" Action="createAndRemoveOnUninstall">
                <RegistryValue Type="string" Value="[FOOVERSION]" KeyPath="yes"></RegistryValue>
              </RegistryKey>
            </Component>
            <Directory Id="FOOGAC" Name="GAC">
              <Component Id="Foo_GAC" Guid="Guid 6">
                <File Id="Foo" Source="$(sys.CURRENTDIR)2.0.1\Foo.dll" KeyPath="yes" Assembly=".net"></File>
              </Component>
              <Component Id="Foo_Policy_2x0x1" Guid="Guid 7">
                <File Id="Foo_PolicyDLL" Source="$(sys.CURRENTDIR)2.0.1\policy.2.0.Foo.dll" KeyPath="yes" Assembly=".net"></File>
                <File Id="Foo_PolicyConfig" Source="$(sys.CURRENTDIR)2.0.1\policy.2.0.Foo.config" CompanionFile="Foo_PolicyDLL"></File>
              </Component>
            </Directory>
          </Directory>
        </Directory>
      </Directory>
    </Directory>
  </Directory>

  <Feature Id="ProductFoo" Level="1">

      <ComponentRef Id="Foo_GAC"/>

      <Feature Id="Foo_VSSupport" Level="1">
        <ComponentRef Id="FooLibPath"/>
        <ComponentRef Id="Foo_VSFile"/>
        <ComponentRef Id="Foo_VSRegKey"/>
      </Feature>

      <Feature Id="Foo_Policy_v2x0x1" Level="0">
        <ComponentRef Id="Foo_Policy_2x0x1"/>
        <Condition Level="1">UPGRADE2X0X0</Condition>
      </Feature>

  </Feature>

</Product>
4

1 回答 1

1

is it safe to just delete an orphaned feature/component after a product is uninstalled?

No, it's not. If you just delete it, its component registration information is still left on the machine.

And is there any way to check what, if anything, is still referencing a component that I believe to be an orphan?

Not really. But if there is something referencing one of your components, it's most likely another product developed by you or an older version of your current product which wasn't uninstalled correctly.

It's very unlikely that a random product would reference your component or assembly.

And how do I fix my installer to keep this from happening in the future?

Use major upgrades which uninstall the old component and install the new one. No special policy files, no conditional installations or removals.

Multiple versions of the Foo library can be installed on the machine at a time, each will be located in the appropriate folder under Foo.

Why? If you have a single product, you can use major upgrades. This way the user will have only one version installed with only one version of your assembly.

Versioned assemblies installed side by side make sense only for different products.

It was decided that since the bug fix was the only change, we would add a policy file to the GAC which would redirected references for Foo 2.0.0 to Foo 2.0.1. This policy file was added to the installer as a new component inside of a new feature.

This is a hack and most likely this is what is causing the problem. Your new installed should have uninstalled the old version along with Foo 2.0.0.

Major upgrades should always be standalone.

于 2011-09-15T18:00:56.807 回答