【问题标题】:WiX Conditional Feature/Component Orphaned on Uninstall卸载时孤立的 WiX 条件功能/组件
【发布时间】:2011-09-15 15:43:02
【问题描述】:

编辑:引用我自己的话,因为我在下面的其中一个 cmets 中更好地总结了这个问题……

安装包时我有一个条件为真,但是 删除时不正确。我希望 MSI 记得它有 安装条件组件并通过卸载将其删除, 但这种情况并非如此。我试图找出 A) 正确的方法 清理这个孤立的组件,以及 B) 保护的最佳方法 以后再解决这个问题。

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

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

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>

【问题讨论】:

    标签: wix windows-installer global-assembly-cache


    【解决方案1】:

    只删除一个孤立的功能/组件是否安全 产品被卸载了吗?

    不,不是。如果只是删除它,它的组件注册信息仍然留在机器上。

    还有什么方法可以检查仍然引用的内容(如果有的话) 一个我认为是孤儿的组件?

    不是真的。但是,如果有东西引用了您的某个组件,则很可能是您开发的另一个产品或您当前产品的旧版本没有正确卸载。

    随机产品不太可能引用您的组件或组件。

    以及如何修复我的安装程序以防止这种情况发生在 未来?

    使用卸载旧组件并安装新组件的重大升级。没有特殊的策略文件,没有条件安装或删除。

    机器上可以安装多个版本的Foo库 一次,每个都将位于相应的文件夹中 在 Foo 下。

    为什么?如果你有一个单一的产品,你可以使用主要的升级。这样,用户将只安装一个版本,其中只有一个版本的程序集。

    并排安装的版本化程序集仅对不同的产品有意义。

    决定由于错误修复是唯一的更改,我们将 向 GAC 添加一个策略文件,该文件将重定向 Foo 的引用 2.0.0 到 Foo 2.0.1。此策略文件作为 新功能中的新组件。

    这是一个 hack,很可能是导致问题的原因。您新安装的应该已经卸载了旧版本以及 Foo 2.0.0。

    重大升级应始终是独立的。

    【讨论】:

    • 在这种情况下,Foo 是一个支持多个 Web 应用程序的独立框架库。如果我们不以允许在同一台机器上并行安装不同版本的方式构建它,那么每次更新库时,我们都会破坏每个发布的应用程序与以前的版本。我们不会冒险在 20 个应用程序中引入重大更改,因为应用程序 #21 需要该库来支持最初没有想到的新功能。这不是 hack,这正是 GAC 和策略文件旨在支持的场景。
    • 这些 Web 应用程序是否使用 MSI 安装程序?如果他们这样做,他们可以共享程序集。例如,Foo 2.0.0 可以在多个产品之间共享。这是通过在所有 MSI 包中使用相同的组件名称和 GUID 来完成的。在这种情况下,Windows Installer 将使用引用计数来管理组件。每个安装程序都应处理自己的组件。如果您正在安装 Foo 2.0.1,则不必担心 Foo 2.0.0。旧版本应由主要升级和引用计数自动处理。
    • 不,我们所做的一切都部署到内部服务器上,我们不会在公司之外分发任何代码。一些站点正在使用 Web 部署项目,但大多数站点直接从 VS 发布到开发服务器。从那里编译的代码被复制到 QA 和 Production 框。我们甚至将库放入安装程序包的唯一原因是因为其中一些具有需要考虑的依赖关系,并且它可以更轻松地确保所有内容最终都位于各种服务器和开发人员 PC 上的正确位置。
    • 也许他们应该:)。我不确定在这种情况下您将如何进行。如果您不想使用内置引用计数,Windows Installer 可能会感到困惑并留下旧组件或删除使用的组件。也许其他用户会有更适合您的场景的替代方法。
    • 关键是我试图依赖组件计数器,它不适用于条件组件。我有一个条件,在安装包时为真,但在删除它时不为真。我希望 MSI 记住它已经安装了条件组件并通过卸载将其删除,但事实并非如此。我正在尝试找出 A) 清理此孤立组件的正确方法,以及 B) 将来防止此问题的最佳方法。将每个项目都转移到 MSI 部署不是一种选择,在这种环境中不会发生。
    猜你喜欢
    • 1970-01-01
    • 2015-10-10
    • 2013-06-22
    • 1970-01-01
    • 2010-09-16
    • 2013-11-12
    • 1970-01-01
    • 2021-04-26
    • 2021-03-13
    相关资源
    最近更新 更多