2016-03-03 2 views
4

Я хочу зарегистрировать сборку .net как COM.Регистрация COM без прав администратора

Фактически, что это означает, насколько я знаю, что вместо HKEY_CLASSES_ROOT Я хочу, чтобы записи были записаны в HKEY_CURRENT_USER/Software/Classes, так что права UAC/Admin не нужны.

Найдено два решения этой проблемы, с как я изо всех сил:

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.

на боковой ноте: каждый раз, когда я запускаю RegOpenKeyEx, значение ключа отличается, это нормально?

2) с Regasm

с помощью regasm.exe с /regfile флагом, а затем заменить в генерируемый .reg файл все HKEY_CLASSES_ROOT вхождений с HKEY_CURRENT_USER/Software/Classes

это я думаю, что должно работать, но как я разрегистрировать такая сборка, когда я не удалю свой Outlook AddIn?

, как я вижу, я не могу сделать его таким же образом, как регистр, потому что:

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

ответ

2

Для чего это стоит, я написал набор утилит C#, которые регистрируются/unregister типа .NET (должен быть помечен как ComVisible of co urse) в реестре пользователя, не требуя regasm или приглашений UAC, вы можете использовать его следующим образом:

// register into current user registry, needs to specific rights 
ComUtilities.RegisterComObject(ComUtilities.Target.User, typeof(MyClass)); 

// unregister from user registry, needs to 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<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)); 
     } 
    } 
} 
+0

Точно то, что я разработал, только реализовано не так чисто :-) –

1

решаемые его вручную путем добавления необходимых ключей реестра HKLM оказалось, что это не так трудно сделать , и regasm.exe или Registrar.RegisterAssembly не так много (по крайней мере, когда речь заходит о моем случае использования Outlook AddIn без прав администратора)

Смежные вопросы