Registering a COM without Admin rights

后端 未结 2 1465
迷失自我
迷失自我 2020-11-29 09:59

I want to register a .net assembly as COM.

In fact what that means as far as I know is, that instead of HKEY_CLASSES_ROOT I want the entries to be writt

2条回答
  •  慢半拍i
    慢半拍i (楼主)
    2020-11-29 10:30

    For what it's worth, I've written a set of C# utilities that register/unregister a .NET type (should be marked as ComVisible of course) in user's registry without requiring regasm, nor UAC prompts, you can use it like this:

    // register into current user registry, needs no specific rights
    ComUtilities.RegisterComObject(ComUtilities.Target.User, typeof(MyClass));
    
    // unregister from user registry, needs no specific rights
    ComUtilities.UnregisterComObject(ComUtilities.Target.User, typeof(MyClass));
    
    // register into machine registry (needs admin, UAC, etc.)
    ComUtilities.RegisterComObject(ComUtilities.Target.Machine, typeof(MyClass));
    
    // unregister from machine registry (needs admin, UAC, etc.)
    ComUtilities.UnregisterComObject(ComUtilities.Target.Machine, typeof(MyClass));
    
    
    public static class ComUtilities
    {
        private const string ClsidRegistryKey = @"Software\Classes\CLSID";
    
        public enum Target
        {
            Machine,    // registers or unregisters a .NET COM object in HKEY_LOCAL_MACHINE, for all users, needs proper rights
            User        // registers or unregisters a .NET COM object in HKEY_CURRENT_USER to avoid UAC prompts
        }
    
        public static void RegisterComObject(Target target, Type type)
        {
            RegisterComObject(target, type, null);
        }
    
        public static void RegisterComObject(Target target, Type type, string assemblyPath)
        {
            RegisterComObject(target, type, assemblyPath, null);
        }
    
        public static void RegisterComObject(Target target, Type type, string assemblyPath, string runtimeVersion)
        {
            if (type == null)
                throw new ArgumentNullException(nameof(type));
    
            if (type.Assembly == null)
                throw new ArgumentException(null, nameof(type));
    
            // note we don't check if the type is marked as ComVisible, maybe we should
    
            if (assemblyPath == null)
            {
                assemblyPath = new Uri(type.Assembly.Location).LocalPath;
            }
    
            if (runtimeVersion == null)
            {
                runtimeVersion = GetRuntimeVersion(type.Assembly);
            }
    
            var root = target == Target.User ? Registry.CurrentUser : Registry.LocalMachine;
    
            using (RegistryKey key = EnsureSubKey(root, Path.Combine(ClsidRegistryKey, type.GUID.ToString("B"), "InprocServer32")))
            {
                key.SetValue(null, "mscoree.dll");
                key.SetValue("Assembly", type.Assembly.FullName);
                key.SetValue("Class", type.FullName);
                key.SetValue("ThreadingModel", "Both");
                if (assemblyPath != null)
                {
                    key.SetValue("CodeBase", assemblyPath);
                }
    
                key.SetValue("RuntimeVersion", runtimeVersion);
            }
    
            using (RegistryKey key = EnsureSubKey(root, Path.Combine(ClsidRegistryKey, type.GUID.ToString("B"))))
            {
                // cf http://stackoverflow.com/questions/2070999/is-the-implemented-categories-key-needed-when-registering-a-managed-com-compon
                using (RegistryKey cats = EnsureSubKey(key, @"Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}"))
                {
                    // do nothing special
                }
    
                var att = type.GetCustomAttribute();
                if (att != null && !string.IsNullOrEmpty(att.Value))
                {
                    using (RegistryKey progid = EnsureSubKey(key, "ProgId"))
                    {
                        progid.SetValue(null, att.Value);
                    }
                }
            }
        }
    
        public static void UnregisterComObject(Target target, Type type)
        {
            if (type == null)
                throw new ArgumentNullException(nameof(type));
    
            var root = target == Target.User ? Registry.CurrentUser : Registry.LocalMachine;
            using (RegistryKey key = root.OpenSubKey(ClsidRegistryKey, true))
            {
                if (key == null)
                    return;
    
                key.DeleteSubKeyTree(type.GUID.ToString("B"), false);
            }
        }
    
        // kind of hack to determine clr version of an assembly
        private static string GetRuntimeVersion(Assembly asm)
        {
            string def = "v4.0.30319"; // use CLR4 as the default
            try
            {
                var mscorlib = asm.GetReferencedAssemblies().FirstOrDefault(a => a.Name == "mscorlib");
                if (mscorlib != null && mscorlib.Version.Major < 4)
                    return "v2.0.50727"; // use CLR2
            }
            catch
            {
                // too bad, assume CLR4
            }
            return def;
        }
    
        private static RegistryKey EnsureSubKey(RegistryKey root, string name)
        {
            RegistryKey key = root.OpenSubKey(name, true);
            if (key != null)
                return key;
    
            string parentName = Path.GetDirectoryName(name);
            if (string.IsNullOrEmpty(parentName))
                return root.CreateSubKey(name);
    
            using (RegistryKey parentKey = EnsureSubKey(root, parentName))
            {
                return parentKey.CreateSubKey(Path.GetFileName(name));
            }
        }
    }
    

提交回复
热议问题