【问题标题】:How to find out which application requires a certain assembly from GAC?如何找出哪个应用程序需要 GAC 的某个程序集?
【发布时间】:2015-12-10 00:21:01
【问题描述】:

我继承了一个使用 Microsoft Enterprise Library 的应用程序。应用程序的VS解决方案包含大约200个项目。

我一直在重组解决方案,移动项目并删除过时的项目。我需要整理一下,以便为其他开发人员做好准备。

该解决方案包含特定版本的 Microsoft 企业库 dll,但是当我四处移动时,我注意到有些项目没有引用这些 dll,而是引用了我的 GAC 中的 dll。

我需要确保解决方案不依赖于安装的任何其他东西(在 GAC 中或其他方式中)或记录它,因此下一个人在从源代码管理中提取它时不会有令人讨厌的惊喜。

我试图从 GAC 中删除企业库 dll。它是这样失败的:

C:\WINDOWS\system32>gacutil /u Microsoft.Practices.EnterpriseLibrary.Common
Microsoft (R) .NET Global Assembly Cache Utility.  Version 4.0.30319.0
Copyright (c) Microsoft Corporation.  All rights reserved.


Assembly: Microsoft.Practices.EnterpriseLibrary.Common, Version=4.1.0.0, Culture=neutral, PublicKeyToken=e44a2bc38ed2c13c, processorArchitecture=MSIL
Unable to uninstall: assembly is required by one or more applications
Pending references:
              SCHEME: <WINDOWS_INSTALLER>  ID: <MSI>  DESCRIPTION : <Windows Installer>
Number of assemblies uninstalled = 0
Number of failures = 0

此消息让我认为此 dll 被安装了 Windows Installer (MSI) 的应用程序引用。

我的机器没有 Microsoft Enterprise Library 作为控制面板/程序和功能中的一项。

如何找出在 gac 中安装 DLL 的 MSI 安装产品?

编辑:不是骗子。另一个问题是关于进程资源管理器没有在 GAC 中显示程序集的情况,而 KB 正在讨论即使程序集没有被任何东西引用也无法删除的情况。另一个问题的进程资源管理器部分与我无关,因为我不希望程序集一直被加载。 kb 响应也无济于事,因为我不想删除我想找出安装它的程序的程序集。其他问题的答案没有回答这个问题(因为那不是那里所问的),但幸运的是我得到了高质量的答案here

【问题讨论】:

标签: .net dll windows-installer gac


【解决方案1】:

对我来说一直有效的快速而肮脏的方法是打开一个 cmd 提示符,转到 c:\windows\installer 并执行 findstr:

findstr /s -i -m AssemblyName.dll *.msi

如果您找到任何匹配项,您将返回一个或多个文件,其中包含一个以 .msi 结尾的短散列名称。使用 Windows Installer 数据库编辑器“ORCA”(安装平台 SDK 或 google ORCA.msi)检查这些数据库中的每一个,并查看其中哪些具有将所述文件安装到 GlobalAssemblyCache 目录的组件。如果程序集存在于 MsiAssembly 表中并且 File_Application 字段为空,则它正在安装到 GAC。 找到后,查看属性表和摘要信息流(顶部菜单 -> 查看 -> 摘要信息)以确定缓存的 MSI 代表什么产品。

【讨论】:

  • 听起来像是一个计划,谢谢。我会尝试(明天)并会回复你!再次感谢您!
【解决方案2】:

我使用脚本来枚举系统上的所有组件、它们的 guid、它们的安装位置以及拥有的产品代码和名称。运行可能需要一段时间。

Option Explicit
Public installer, fullmsg, comp, a, prod, fso, pname, ploc, pid, psorce

Set fso = CreateObject("Scripting.FileSystemObject")
Set a = fso.CreateTextFile("comps.txt", True)

' Connect to Windows Installer object
Set installer = CreateObject("WindowsInstaller.Installer")
a.writeline ("MSI Components")
on error resume next
For Each comp In installer.components
   a.writeline (comp & " is used by the product:")
   for each prod in Installer.ComponentClients (comp) 
      pid = installer.componentpath (prod, comp) 
      pname = installer.productinfo (prod, "InstalledProductName")
      a.Writeline ("     " & pname & " " & prod & "and is installed at " & pid)
   Next
Next

【讨论】:

  • 这是执行此操作的 API 方法,但我发现 findstr 方法运行速度更快,并且在需要时更容易记住。
  • @ChristopherPainter 这取决于命中了多少 msi 文件。如果你得到 10 次点击,这种方法会比你的更快,因为你不需要在 orca 中单独打开每个 msi。
  • 两个答案都非常有用 - 方法也不同,很遗憾我不能同时接受。
  • 毫无疑问。这一切都取决于情况。 findstr 将花费您 5 秒的时间来确定要优化的场景。 FWIW,如果您确实走这条路,既然您提到了 GAC,我假设您是 .NET 开发人员。 Windows Installer XML (WiX) 有一个名为 Deployment Tools Foundation (DTF) 的 SDK,它具有 Windows Installer 互操作库,使 C# 中的这些类型的查询非常容易。甚至还有一个 LinqToMSI 提供程序。 :)
【解决方案3】:

这里有几件事要理解。首先,GAC 将是获取程序集的首选地点。因此,在您的开发机器上从 GAC 中删除 EL 程序集。将 Nuget 包中的 EL 添加到您的项目中。 GAC 中的程序集可以在那里手动添加。不一定使用 MSI。如果您希望您的项目忽略其他版本,例如 GAC 中的版本。在项目的引用中,选择有问题的引用并将“特定版本”设置为true。现在,如果版本不匹配,您的项目将不再用来自 GAC 的参考替换原始参考。此时,您可以将该版本的 EL 添加到 bin 或您那里的任何内容中。

对于这么大的解决方案,我的建议是创建以下结构

- Solution
  - packages(nuget)
  - bin
  - Project 1
  - . . . .  .
  - Project N
  • 删除所有项目引用并将其替换为对bin 中的 dll 的引用。
  • 将您的项目设置为构建输出为bin
  • 创建构建顺序。
  • 从 GAC 中删除任何 dll,从 GAC 中删除任何第 3 方 dll 并放入 bin。只有以“system”开头的 dll 可以在 GAC 或“Project Files”等中。任何其他的都应该在 packagesbin 中。 (虽然在某些情况下,从packages 获取并移至bin 会很有用)
  • 在您的项目引用中,将任何非系统 dll 设置为 copy local = true,并且通常/通常都应该有 specific version = false

一旦你做了这些事情,你的生活就会变得美好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多