繁体   English   中英

枚举GAC中的程序集

[英]enumerating assemblies in GAC

如何在C#中枚举GAC中的所有可用程序集?

实际上我遇到了一个愚蠢的代码问题 - 在项目中引用并使用名为Telerik.Web.UI.dll的程序集 - 这个特定的DLL不存在于BIN文件夹中。 应用程序在服务器上工作正常 - 但在我的机器上,显然编译器会出错。 Ex-Developer坚持认为它不在服务器上的GAC中,而是“它就是这样”。 现在我需要检查这个DLL是否在GAC中注册。

帮助将不胜感激。

美好的一天;

如果您对服务器的访问权限有限,那么这可能有效:

// List of all the different types of GAC folders for both 32bit and 64bit
// environments.
List<string> gacFolders = new List<string>() { 
    "GAC", "GAC_32", "GAC_64", "GAC_MSIL", 
    "NativeImages_v2.0.50727_32", 
    "NativeImages_v2.0.50727_64",
    "NativeImages_v4.0.30319_32",
    "NativeImages_v4.0.30319_64"
};

foreach (string folder in gacFolders)
{
    string path = Path.Combine(
       Environment.ExpandEnvironmentVariables(@"%systemroot%\assembly"), 
       folder);

    if(Directory.Exists(path))
    {
        Response.Write("<hr/>" + folder + "<hr/>");

        string[] assemblyFolders = Directory.GetDirectories(path);
        foreach (string assemblyFolder in assemblyFolders)
        {
            Response.Write(assemblyFolder + "<br/>");
        }
    }
}

它基本上枚举了原始GAC文件夹。 它适用于DiscountASP共享主机,因此可能适用于您的托管环境。

它可以通过枚举更深入到每个程序集的文件夹来修饰版本号和公钥令牌。

查看此代码项目GAC API接口文章。 这使用未记录的fusion.dll来累积GAC。 但作者声称

已知此代码适用于.NET 1.1和2.0。 请注意,DLL fusion.dll在1.1和2.0中有所不同。 因此,如果您安装了两个框架,请确保将代码指向正确的DLL。 否则大多数API调用都将失败。 默认实现使用WINDOWS目录中的实现。

你真的不需要在C#中写一些东西来找出这个特定的dll是否在gac中。 您可以在命令行中使用带有/ l选项的gacutil.exe来列出GAC的内容。

枚举目录中dll文件的简单方法

public static string[] GetGlobalAssemblyCacheFiles(string path)
{
    List<string> files = new List<string>();

    DirectoryInfo di = new DirectoryInfo(path);

    foreach (FileInfo fi in di.GetFiles("*.dll"))
    {
        files.Add(fi.FullName);
    }

    foreach (DirectoryInfo diChild in di.GetDirectories())
    {
        var files2 = GetGlobalAssemblyCacheFiles(diChild.FullName);
        files.AddRange(files2);
    }

    return files.ToArray();
}

你可以得到所有文件

string gacPath = Environment.GetFolderPath(System.Environment.SpecialFolder.Windows) + "\\assembly";
var files = GetGlobalAssemblyCacheFiles(gacPath);

如果需要加载每个程序集,则会获得不同运行时版本的异常。 因此,您可以使用Assembly.ReflectionOnlyLoadFrom加载程序集,仅在反射中加载程序集。 然后,程序集不会加载到您的AppDomain中,也不会抛出异常。

如果它是普通的ASP.NET站点,并且程序集不在站点的bin文件夹中或服务器的GAC中(并且web.config中没有任何可疑内容),那么该站点可能是某种类型的子站点,其中一个网站的更高版本包含bin文件夹中的引用(或其web.config中的一些内容,因为子站点/文件夹继承了其父项的web.configs)?

现在,如果你有一个正确加载文件的环境(听起来像你这样做),你可以问.NET .dll来自哪里,然后显示它,例如:

Assembly a = Assembly.Load("Microsoft.VisualStudio.Shell, Version=2.0.0.0, "
           + "PublicKeyToken=b03f5f7f11d50a3a, Culture=Neutral");

Console.WriteLine(a.Location);

将加载程序集并显示其磁盘位置,我的输出是: C:\\Windows\\assembly\\GAC_MSIL\\Microsoft.VisualStudio.Shell\\2.0.0.0__b03f5f7f11d50a3a\\Microsoft.VisualStudio.Shell.dll

如果它在“C:\\ Windows \\ assembly \\”下,你知道它在GAC中。

如果你已经引用了程序集,你可以枚举加载到当前app.domain中的程)他们的.Location属性是什么。

编辑:代码看起来像这样:

foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
{
    Console.WriteLine(a.GetName().FullName);
    Console.WriteLine(a.Location);
    Console.WriteLine();
}

编辑:在完全信任环境中,以下代码(控制台应用程序)将枚举GAC并写出每个程序集,应该很容易将其修改为ASP.NET应用程序,但我不确定它是否可以在一个不完全信任的环境(只是在这里猜测,你可能会很幸运):

static void ProcessFile(string file)
{
    try
    {
        Assembly a = Assembly.LoadFile(file);

        Console.WriteLine(a.GetName().FullName);
    }
    catch { /* do nothing */ }
}

static void ProcessFolder(string folder)
{
    foreach (string file in Directory.GetFiles(folder))
    {
        ProcessFile(file);
    }

    foreach (string subFolder in Directory.GetDirectories(folder))
    {
        ProcessFolder(subFolder);
    }
}

static void Main(string[] args)
{
    ProcessFolder(@"C:\Windows\Assembly");
}

图我可以投入我的基于linq的解决方案(如果您只是寻找单个文件并且不想枚举每个文件,则很方便)

找到文件的功能:

    public static IEnumerable<string> FindFiles (string path, string filter = "", int depth = int.MaxValue) {
        DirectoryInfo di = new DirectoryInfo(path);

        IEnumerable<string> results = (! string.IsNullOrEmpty(filter) ? di.GetFiles(filter) : di.GetFiles()).Select(f => f.FullName);
        if (depth > 0) {
            results = results.Concat(di.GetDirectories().SelectMany(d => FindFiles(d.FullName, filter, depth - 1)));
        }

        return results;
    }

并调用(我没有Environment.SpecialFolder.Windows所以改为使用Environment.SpecialFolder.System)

string path = Environment.GetFolderPath(Environment.SpecialFolder.System) + "\\..\\assembly";
foreach (string s in FindFiles(path, "*.dll")) {
     Console.WriteLine(s);
}

此外,作为FYI,此方法枚举整个GAC,您可能会在tmp /和temp /中找到重复的DLL,Tmp用于安装,Temp用于卸载。

检查在ILSpy中如何使用fusion.dll枚举所有GAC程序集的方式。

Fusion COM Wrappers

using System;
using System.Runtime.InteropServices;
using System.Text;

namespace GacWithFusion
{
    // .NET Fusion COM interfaces
    [ComImport, Guid("CD193BC0-B4BC-11D2-9833-00C04FC31D2E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IAssemblyName
    {
        [PreserveSig]
        int SetProperty(uint PropertyId, IntPtr pvProperty, uint cbProperty);

        [PreserveSig]
        int GetProperty(uint PropertyId, IntPtr pvProperty, ref uint pcbProperty);

        [PreserveSig]
        int Finalize();

        [PreserveSig]
        int GetDisplayName([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder szDisplayName,
                           ref uint pccDisplayName,
                           uint dwDisplayFlags);

        [PreserveSig]
        int BindToObject(object refIID,
                         object pAsmBindSink,
                         IApplicationContext pApplicationContext,
                         [MarshalAs(UnmanagedType.LPWStr)] string szCodeBase,
                         long llFlags,
                         int pvReserved,
                         uint cbReserved,
                         out int ppv);

        [PreserveSig]
        int GetName(ref uint lpcwBuffer,
                    [Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwzName);

        [PreserveSig]
        int GetVersion(out uint pdwVersionHi, out uint pdwVersionLow);

        [PreserveSig]
        int IsEqual(IAssemblyName pName,
                    uint dwCmpFlags);

        [PreserveSig]
        int Clone(out IAssemblyName pName);
    }

    [ComImport(), Guid("7C23FF90-33AF-11D3-95DA-00A024A85B51"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IApplicationContext
    {
        void SetContextNameObject(IAssemblyName pName);

        void GetContextNameObject(out IAssemblyName ppName);

        void Set([MarshalAs(UnmanagedType.LPWStr)] string szName,
                 int pvValue,
                 uint cbValue,
                 uint dwFlags);

        void Get([MarshalAs(UnmanagedType.LPWStr)] string szName,
                 out int pvValue,
                 ref uint pcbValue,
                 uint dwFlags);

        void GetDynamicDirectory(out int wzDynamicDir,
                                 ref uint pdwSize);
    }

    [ComImport(), Guid("21B8916C-F28E-11D2-A473-00C04F8EF448"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IAssemblyEnum
    {
        [PreserveSig]
        int GetNextAssembly(out IApplicationContext ppAppCtx,
                            out IAssemblyName ppName,
                            uint dwFlags);

        [PreserveSig]
        int Reset();

        [PreserveSig]
        int Clone(out IAssemblyEnum ppEnum);
    }

    internal static class Fusion
    {
        // dwFlags: 1 = Enumerate native image (NGEN) assemblies
        //          2 = Enumerate GAC assemblies
        //          4 = Enumerate Downloaded assemblies
        //
        [DllImport("fusion.dll", CharSet = CharSet.Auto)]
        internal static extern int CreateAssemblyEnum(out IAssemblyEnum ppEnum,
                                                      IApplicationContext pAppCtx,
                                                      IAssemblyName pName,
                                                      uint dwFlags,
                                                      int pvReserved);
    }
}

主要

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace GacWithFusion
{
    public class Program
    {
        static void Main(string[] args)
        {
            foreach (var assemblyName in GetGacAssemblyFullNames())
            {
                Console.WriteLine(assemblyName.FullName);
            }
        }

        public static IEnumerable<AssemblyName> GetGacAssemblyFullNames()
        {
            IApplicationContext applicationContext;
            IAssemblyEnum assemblyEnum;
            IAssemblyName assemblyName;

            Fusion.CreateAssemblyEnum(out assemblyEnum, null, null, 2, 0);
            while (assemblyEnum.GetNextAssembly(out applicationContext, out assemblyName, 0) == 0)
            {
                uint nChars = 0;
                assemblyName.GetDisplayName(null, ref nChars, 0);

                StringBuilder name = new StringBuilder((int)nChars);
                assemblyName.GetDisplayName(name, ref nChars, 0);

                AssemblyName a = null;
                try
                {
                    a = new AssemblyName(name.ToString());
                }
                catch (Exception)
                {
                }

                if (a != null)
                {
                    yield return a;
                }
            }
        }
    }
}

可能你需要这样的GAC查看器:

替代文字

视频:如何使用“添加GAC引用”对话框

希望这可以帮助

小号

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM