如何从 GAC 中找出哪个应用程序需要某个程序集?

How to find out which application requires a certain assembly from GAC?

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

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

该解决方案包含特定版本的 Microsoft Enterprise Library 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 安装程序 (MSI) 安装的应用程序引用。

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

如何找出哪个 MSI 安装产品在 gac 中安装了 DLL?

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

得到了高质量的答案

这里需要了解的东西很少。首先,GAC 将是获得大会的首选地点。因此,在您的开发机器上从 GAC 中删除 EL 程序集。将 EL 从 Nuget 包添加到您的项目。 GAC 中的程序集可以在那里手动添加。不一定使用 MSI。如果您希望您的项目忽略其他版本,例如 GAC 中的版本。在您项目的引用中,select 有问题的引用并将 "Specific Version" 设置为 true。现在,如果版本不匹配,您的项目将不再用 GAC 中的原始参考替换原始参考。此时,您可以将该版本的 EL 添加到容器中,或者添加到容器中的任何内容。

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

- 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,并且 generally/usually 都应具有 specific version = false

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

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

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

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

我使用脚本来枚举系统上的所有组件、它们的 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