注册没有管理员权限的 COM

Registering a COM without Admin rights(注册没有管理员权限的 COM)
本文介绍了注册没有管理员权限的 COM的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将 .net 程序集注册为 COM.

I want to register a .net assembly as COM.

事实上,据我所知,这意味着,我希望将条目写入 HKEY_CURRENT_USER/Software/Classes 而不是 HKEY_CLASSES_ROOT,以便 UAC不需要/Admin 权限.

In fact what that means as far as I know is, that instead of HKEY_CLASSES_ROOT I want the entries to be written in HKEY_CURRENT_USER/Software/Classes, so that UAC/Admin rights are not needed.

找到了该问题的两个解决方案,我都在苦苦挣扎:

Found two solutions of that problem, with both I'm struggling:

1) 编程方式,代码如下:

        IntPtr key;
        var openKeyresult = RegOpenKeyEx(HKEY_CURRENT_USER, "SOFTWARE\Classes", 0, (int)RegistrySecurity.KEY_WOW64_64KEY, out key);
        var overrideKeyResult = RegOverridePredefKey(HKEY_CLASSES_ROOT, key);
        var registerResult = Registrar.RegisterAssembly(GetAssembly(), AssemblyRegistrationFlags.SetCodeBase);

在这种方法中,overrideKeyResult 为 6,对应于 ERROR_INVALID_HANDLE,因此,RegisterAssembly 抛出拒绝访问"异常,因为它尝试写入 HKEY_CLASSES_ROOT.

in this approach, overrideKeyResult is 6 which corresponds to ERROR_INVALID_HANDLE, thus, the RegisterAssembly throw a "access denied" exception because it tries to write to HKEY_CLASSES_ROOT.

附带说明:每次我运行 RegOpenKeyEx 时,键值都不同,可以吗?

on a side note: each time I run the RegOpenKeyEx the key value is different, is that ok?

2) 再充气

通过使用带有 /regfile 标志的 regasm.exe,然后在生成的 .reg 文件中替换所有 HKEY_CLASSES_ROOT 出现在 HKEY_CURRENT_USER/Software/Classes

by using regasm.exe with the /regfile flag, and then replacing in the generated .reg file all HKEY_CLASSES_ROOT occurences with HKEY_CURRENT_USER/Software/Classes

我认为这应该可以,但是当我不想卸载 Outlook 插件时如何取消注册此类程序集?

this I think should work, but how do I unregister such assembly when I wan't to uninstall my Outlook AddIn?

正如我所见,我无法以与注册相同的方式进行注册,因为:

as I see I can't make it in the same way as register because:

var openKeyresult = RegOpenKeyEx(HKEY_CURRENT_USER, "SOFTWARE\Classes", 0, (int)RegistrySecurity.KEY_WOW64_64KEY, out key);

推荐答案

为了它的价值,我编写了一组 C# 实用程序,用于在用户的注册表不需要 regasm,也不需要 UAC 提示,你可以像这样使用它:

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 = @"SoftwareClassesCLSID";

    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<ProgIdAttribute>();
            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));
        }
    }
}

这篇关于注册没有管理员权限的 COM的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

c# Generic Setlt;Tgt; implementation to access objects by type(按类型访问对象的C#泛型集实现)
InvalidOperationException When using Context Injection in ASP.Net Core(在ASP.NET核心中使用上下文注入时发生InvalidOperationException)
quot;Overflowquot; compiler error with -9223372036854775808L(编译器错误-9223372036854775808L(Q;溢出Q))
Visual Studio 2010 ReportViewer Assembly References(Visual Studio 2010 ReportViewer程序集引用)
Weird behaviour when I open a reportviewer in WPF(在WPF中打开报表查看器时出现奇怪的行为)
how do i pass parameters to aspnet reportviewer(如何将参数传递给aspnet report查看器)