Register a dll into the GAC - but then it doesn't show up in the assembly window
Asked Answered
S

3

4

I have this code to register dlls into my gac

 Assembly asm = Assembly.LoadFrom(argument);
    RegistrationServices regAsm = new RegistrationServices();
    bool bResult = regAsm.RegisterAssembly(asm, AssemblyRegistrationFlags.SetCodeBase);

and that works fine, i'm getting true to bResult, but when i open the GAC window i expected to see the dll there, but it is not. Can anyone explain me why?

When i drop the dll into the GAC window i see it there.

Shrunk answered 9/4, 2010 at 21:36 Comment(0)
D
2

Your code doesn't register the assembly in GAC, but, as explained here,

Registers the classes in a managed assembly to enable creation from COM.

which is not the same.

Dissoluble answered 9/4, 2010 at 21:58 Comment(2)
so the right way to register is with regasm.exe? because i also tried that but still didn't see it in the GAC window.Shrunk
The right way is gacutil, not regasm (which is for registering .NET assemblies for COM creation).Dissoluble
E
21

It is rather strange that this isn't wrapped by the .NET framework. The necessary fusion declarations are readily available. This code worked well:

using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;

static class GacUtil {

    public static void InstallAssembly(string path, bool forceRefresh) {
        IAssemblyCache iac = null;
        CreateAssemblyCache(out iac, 0);
        try {
            uint flags = forceRefresh ? 2u : 1u;
            int hr = iac.InstallAssembly(flags, path, IntPtr.Zero);
            if (hr < 0) Marshal.ThrowExceptionForHR(hr);
        }
        finally {
            Marshal.FinalReleaseComObject(iac);
        }
    }

    public static void UninstallAssembly(string displayName) {
        IAssemblyCache iac = null;
        CreateAssemblyCache(out iac, 0);
        try {
            uint whatHappened;
            int hr = iac.UninstallAssembly(0, displayName, IntPtr.Zero, out whatHappened);
            if (hr < 0) Marshal.ThrowExceptionForHR(hr);
            switch (whatHappened) {
                case 2: throw new InvalidOperationException("Assembly still in use");
                case 5: throw new InvalidOperationException("Assembly still has install references");
                case 6: throw new System.IO.FileNotFoundException();    // Not actually raised
            }
        }
        finally {
            Marshal.FinalReleaseComObject(iac);
        }
    }


    [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("e707dcde-d1cd-11d2-bab9-00c04f8eceae")]
    internal interface IAssemblyCache {
        [PreserveSig]
        int UninstallAssembly(uint flags, [MarshalAs(UnmanagedType.LPWStr)] string assemblyName, IntPtr pvReserved, out uint pulDisposition);
        [PreserveSig]
        int QueryAssemblyInfo(uint dwFlags, [MarshalAs(UnmanagedType.LPWStr)] string pszAssemblyName, IntPtr pAsmInfo);
        [PreserveSig]
        int CreateAssemblyCacheItem(/* arguments omitted */);
        [PreserveSig]
        int CreateAssemblyScavenger(out object ppAsmScavenger);
        [PreserveSig]
        int InstallAssembly(uint dwFlags, [MarshalAs(UnmanagedType.LPWStr)] string pszManifestFilePath, IntPtr pvReserved);
    }

    [DllImport("mscorwks.dll", PreserveSig = false)]  // NOTE: use "clr.dll" in .NET 4+
    internal static extern void CreateAssemblyCache(out IAssemblyCache ppAsmCache, int reserved);
} 

Don't forget to press F5 in the Explorer window to refresh the view if you are adding and removing assemblies with this code.

Eared answered 9/4, 2010 at 22:43 Comment(2)
I think this is already wrapped in System.EnterpriseServices.dll just call new System.EnterpriseServices.Internal.Publish().GacInstall(assemblyPath); or new System.EnterpriseServices.Internal.Publish().GacRemove(assemblyPath)Hartwig
@ScottLerch Unfortunately, it wraps it too well -- there's no way of knowing the result of whether an uninstall succeeded or not. In GacRemove(), the result of UninstallAssembly() is discarded; you get an event log, but the exception never bubbles up to the calling code.Hodges
D
2

Your code doesn't register the assembly in GAC, but, as explained here,

Registers the classes in a managed assembly to enable creation from COM.

which is not the same.

Dissoluble answered 9/4, 2010 at 21:58 Comment(2)
so the right way to register is with regasm.exe? because i also tried that but still didn't see it in the GAC window.Shrunk
The right way is gacutil, not regasm (which is for registering .NET assemblies for COM creation).Dissoluble
J
1

The method you are using is intended for COM registration. There is no official way of doing this.

Microsoft has a knowledgebase about how to use the undocumented GAC API

hope this helps,

Johnsonian answered 9/4, 2010 at 22:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.