如何以编程方式确定是否在GAC中安装了.NET程序集?

Sco*_*rch 11 .net c# global-assembly-cache .net-assembly

如果程序集在本地计算机上的GAC(全局程序集缓存)中注册,那么以编程方式检查的最简单方法是什么?是否有一些易于使用的.NET API,我可以给它一个程序集DLL或Assembly对象本身的位置,以检查它是否存在于本地机器上的GAC中?在我的情况下,我正在检查的程序集已经被加载到程序检查的当前AppDomain中,因此我不确定调用Assembly.ReflectionOnlyLoad和捕获异常将像我在其他帖子中看到的那样工作,加上这似乎有点hacky .

理想情况下,我想避免调用外部可执行文件gacutil.exe来检查.

Sco*_*rch 19

这个问题与以下问题非常相似,但我的问题更准确一些,而且没有一个接受的答案,所提供的答案似乎都不完整或最优:

最初我认为以下是最好的方法,但它不起作用,除非你指定程序集的全名,并且它有点hacky因为try/catch但它很简单,适用于很多情况:

public static class GacUtil
{
    public static bool IsAssemblyInGAC(string assemblyFullName)
    {
        try
        {
            return Assembly.ReflectionOnlyLoad(assemblyFullName)
                           .GlobalAssemblyCache;
        }
        catch
        {
            return false;
        }
    }

    public static bool IsAssemblyInGAC(Assembly assembly)
    {
        return assembly.GlobalAssemblyCache;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一种更好的方法,可以在没有try/catch的情况下使用Fusion API.这是一堆更多的代码,但它适用于部分程序集名称:

public static class GacUtil
{
    [DllImport("fusion.dll")]
    private static extern IntPtr CreateAssemblyCache(
        out IAssemblyCache ppAsmCache, 
        int reserved);

    [ComImport]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [Guid("e707dcde-d1cd-11d2-bab9-00c04f8eceae")]
    private interface IAssemblyCache
    {
        int Dummy1();

        [PreserveSig()]
        IntPtr QueryAssemblyInfo(
            int flags, 
            [MarshalAs(UnmanagedType.LPWStr)] string assemblyName, 
            ref AssemblyInfo assemblyInfo);

        int Dummy2();
        int Dummy3();
        int Dummy4();
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct AssemblyInfo
    {
        public int cbAssemblyInfo;
        public int assemblyFlags;
        public long assemblySizeInKB;

        [MarshalAs(UnmanagedType.LPWStr)]
        public string currentAssemblyPath;

        public int cchBuf;
    }

    public static bool IsAssemblyInGAC(string assemblyName)
    {
        var assembyInfo = new AssemblyInfo { cchBuf = 512 };
        assembyInfo.currentAssemblyPath = new string('\0', assembyInfo.cchBuf);

        IAssemblyCache assemblyCache;

        var hr = CreateAssemblyCache(out assemblyCache, 0);

        if (hr == IntPtr.Zero)
        {
            hr = assemblyCache.QueryAssemblyInfo(
                1, 
                assemblyName, 
                ref assembyInfo);

            if (hr != IntPtr.Zero)
            {
                return false;
            }

            return true;
        }

        Marshal.ThrowExceptionForHR(hr.ToInt32());
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 铌.根据我的经验,assemblyFullName必须是FULL.这包括processorArchitecture = MSIL等.所以在我的测试中,我在此测试中使用AssemblyName.FullName +",processorArchitecture = MSIL".在我说"不"之前,还要尝试其他两种选择.("AMD64"和"x86")我没有它的唯一匹配是"c:\ Windows\assembly\GAC"中的程序集,这是一组非常少的. (4认同)