3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 /*=============================================================================
8 ** Class: RegistrationServices
11 ** Purpose: This class provides services for registering and unregistering
12 ** a managed server for use by COM.
17 ** Change the way how to register and unregister a managed server
19 =============================================================================*/
20 namespace System.Runtime.InteropServices {
23 using System.Collections;
25 using System.Reflection;
26 using System.Security;
27 using System.Security.Permissions;
29 using System.Threading;
30 using Microsoft.Win32;
31 using System.Runtime.CompilerServices;
32 using System.Globalization;
33 using System.Runtime.Versioning;
34 using System.Diagnostics.Contracts;
37 public enum RegistrationClassContext
41 InProcessServer = 0x1,
42 InProcessHandler = 0x2,
44 InProcessServer16 = 0x8,
46 InProcessHandler16 = 0x20,
51 NoCodeDownload = 0x400,
53 NoCustomMarshal = 0x1000,
54 EnableCodeDownload = 0x2000,
55 NoFailureLog = 0x4000,
56 DisableActivateAsActivator = 0x8000,
57 EnableActivateAsActivator = 0x10000,
58 FromDefaultContext = 0x20000
63 public enum RegistrationConnectionType
72 [Guid("475E398F-8AFA-43a7-A3BE-F4EF8D6787C9")]
73 [ClassInterface(ClassInterfaceType.None)]
74 [System.Runtime.InteropServices.ComVisible(true)]
75 public class RegistrationServices : IRegistrationServices
79 private const String strManagedCategoryGuid = "{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}";
80 private const String strDocStringPrefix = "";
81 private const String strManagedTypeThreadingModel = "Both";
82 private const String strComponentCategorySubKey = "Component Categories";
83 private const String strManagedCategoryDescription = ".NET Category";
84 private const String strImplementedCategoriesSubKey = "Implemented Categories";
85 private const String strMsCorEEFileName = "mscoree.dll";
86 private const String strRecordRootName = "Record";
87 private const String strClsIdRootName = "CLSID";
88 private const String strTlbRootName = "TypeLib";
89 private static Guid s_ManagedCategoryGuid = new Guid(strManagedCategoryGuid);
94 #region IRegistrationServices
96 [System.Security.SecurityCritical] // auto-generated_required
97 [ResourceExposure(ResourceScope.None)]
98 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
99 public virtual bool RegisterAssembly(Assembly assembly, AssemblyRegistrationFlags flags)
101 // Validate the arguments.
102 if (assembly == null)
103 throw new ArgumentNullException("assembly");
105 if (assembly.ReflectionOnly)
106 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AsmLoadedForReflectionOnly"));
107 Contract.EndContractBlock();
109 RuntimeAssembly rtAssembly = assembly as RuntimeAssembly;
110 if (rtAssembly == null)
111 throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeAssembly"));
113 // Retrieve the assembly names.
114 String strAsmName = assembly.FullName;
115 if (strAsmName == null)
116 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NoAsmName"));
118 // Retrieve the assembly codebase.
119 String strAsmCodeBase = null;
120 if ((flags & AssemblyRegistrationFlags.SetCodeBase) != 0)
122 strAsmCodeBase = rtAssembly.GetCodeBase(false);
123 if (strAsmCodeBase == null)
124 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NoAsmCodeBase"));
127 // Go through all the registerable types in the assembly and register them.
128 Type[] aTypes = GetRegistrableTypesInAssembly(assembly);
129 int NumTypes = aTypes.Length;
131 String strAsmVersion = rtAssembly.GetVersion().ToString();
133 // Retrieve the runtime version used to build the assembly.
134 String strRuntimeVersion = assembly.ImageRuntimeVersion;
136 for (int cTypes = 0; cTypes < NumTypes; cTypes++)
138 if (IsRegisteredAsValueType(aTypes[cTypes]))
139 RegisterValueType(aTypes[cTypes], strAsmName, strAsmVersion, strAsmCodeBase, strRuntimeVersion);
140 else if (TypeRepresentsComType(aTypes[cTypes]))
141 RegisterComImportedType(aTypes[cTypes], strAsmName, strAsmVersion, strAsmCodeBase, strRuntimeVersion);
143 RegisterManagedType(aTypes[cTypes], strAsmName, strAsmVersion, strAsmCodeBase, strRuntimeVersion);
145 CallUserDefinedRegistrationMethod(aTypes[cTypes], true);
148 // If this assembly has the PIA attribute, then register it as a PIA.
149 Object[] aPIAAttrs = assembly.GetCustomAttributes(typeof(PrimaryInteropAssemblyAttribute), false);
150 int NumPIAAttrs = aPIAAttrs.Length;
151 for (int cPIAAttrs = 0; cPIAAttrs < NumPIAAttrs; cPIAAttrs++)
152 RegisterPrimaryInteropAssembly(rtAssembly, strAsmCodeBase, (PrimaryInteropAssemblyAttribute)aPIAAttrs[cPIAAttrs]);
154 // Return value indicating if we actually registered any types.
155 if (aTypes.Length > 0 || NumPIAAttrs > 0)
161 [System.Security.SecurityCritical] // auto-generated_required
162 public virtual bool UnregisterAssembly(Assembly assembly)
164 // Validate the arguments.
165 if (assembly == null)
166 throw new ArgumentNullException("assembly");
168 if (assembly.ReflectionOnly)
169 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AsmLoadedForReflectionOnly"));
170 Contract.EndContractBlock();
172 RuntimeAssembly rtAssembly = assembly as RuntimeAssembly;
173 if (rtAssembly == null)
174 throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeAssembly"));
176 bool bAllVersionsGone = true;
178 // Go through all the registrable types in the assembly and register them.
179 Type[] aTypes = GetRegistrableTypesInAssembly(assembly);
180 int NumTypes = aTypes.Length;
182 // Retrieve the assembly version
183 String strAsmVersion = rtAssembly.GetVersion().ToString();
184 for (int cTypes = 0;cTypes < NumTypes;cTypes++)
186 CallUserDefinedRegistrationMethod(aTypes[cTypes], false);
188 if (IsRegisteredAsValueType(aTypes[cTypes]))
190 if (!UnregisterValueType(aTypes[cTypes], strAsmVersion))
191 bAllVersionsGone = false;
193 else if (TypeRepresentsComType(aTypes[cTypes]))
195 if (!UnregisterComImportedType(aTypes[cTypes], strAsmVersion))
196 bAllVersionsGone = false;
200 if (!UnregisterManagedType(aTypes[cTypes], strAsmVersion))
201 bAllVersionsGone = false;
205 // If this assembly has the PIA attribute, then unregister it as a PIA.
206 Object[] aPIAAttrs = assembly.GetCustomAttributes(typeof(PrimaryInteropAssemblyAttribute),false);
207 int NumPIAAttrs = aPIAAttrs.Length;
208 if (bAllVersionsGone)
210 for (int cPIAAttrs = 0;cPIAAttrs < NumPIAAttrs;cPIAAttrs++)
211 UnregisterPrimaryInteropAssembly(assembly, (PrimaryInteropAssemblyAttribute)aPIAAttrs[cPIAAttrs]);
214 // Return value indicating if we actually un-registered any types.
215 if (aTypes.Length > 0 || NumPIAAttrs > 0)
221 [System.Security.SecurityCritical] // auto-generated_required
222 public virtual Type[] GetRegistrableTypesInAssembly(Assembly assembly)
224 // Validate the arguments.
225 if (assembly == null)
226 throw new ArgumentNullException("assembly");
227 Contract.EndContractBlock();
229 if (!(assembly is RuntimeAssembly))
230 throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeAssembly"), "assembly");
232 // Retrieve the list of types in the assembly.
233 Type[] aTypes = assembly.GetExportedTypes();
234 int NumTypes = aTypes.Length;
236 // Create an array list that will be filled in.
237 ArrayList TypeList = new ArrayList();
239 // Register all the types that require registration.
240 for (int cTypes = 0; cTypes < NumTypes; cTypes++)
242 Type CurrentType = aTypes[cTypes];
243 if (TypeRequiresRegistration(CurrentType))
244 TypeList.Add(CurrentType);
247 // Copy the array list to an array and return it.
248 Type[] RetArray = new Type[TypeList.Count];
249 TypeList.CopyTo(RetArray);
253 [System.Security.SecurityCritical] // auto-generated_required
254 public virtual String GetProgIdForType(Type type)
256 return Marshal.GenerateProgIdForType(type);
259 [System.Security.SecurityCritical] // auto-generated_required
260 public virtual void RegisterTypeForComClients(Type type, ref Guid g)
262 #if FEATURE_COMINTEROP_MANAGED_ACTIVATION
264 throw new ArgumentNullException("type");
265 Contract.EndContractBlock();
266 if((type as RuntimeType) == null)
267 throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"),"type");
268 if(!TypeRequiresRegistration(type))
269 throw new ArgumentException(Environment.GetResourceString("Argument_TypeMustBeComCreatable"),"type");
271 // Call the native method to do CoRegisterClassObject
272 RegisterTypeForComClientsNative(type, ref g);
273 #else // FEATURE_COMINTEROP_MANAGED_ACTIVATION
274 throw new NotImplementedException("CoreCLR_REMOVED -- managed activation removed"); // @
275 #endif // FEATURE_COMINTEROP_MANAGED_ACTIVATION
278 public virtual Guid GetManagedCategoryGuid()
280 return s_ManagedCategoryGuid;
283 [System.Security.SecurityCritical] // auto-generated_required
284 public virtual bool TypeRequiresRegistration(Type type)
286 return TypeRequiresRegistrationHelper(type);
289 [System.Security.SecuritySafeCritical] // auto-generated
290 public virtual bool TypeRepresentsComType(Type type)
292 // If the type is not a COM import, then it does not represent a COM type.
293 if (!type.IsCOMObject)
296 // If it is marked as tdImport, then it represents a COM type directly.
300 // If the type is derived from a tdImport class and has the same GUID as the
301 // imported class, then it represents a COM type.
302 Type baseComImportType = GetBaseComImportType(type);
303 Contract.Assert(baseComImportType != null, "baseComImportType != null");
304 if (Marshal.GenerateGuidForType(type) == Marshal.GenerateGuidForType(baseComImportType))
313 #region Public methods not on IRegistrationServices
314 [System.Security.SecurityCritical] // auto-generated_required
316 public virtual int RegisterTypeForComClients(Type type, RegistrationClassContext classContext, RegistrationConnectionType flags)
318 #if FEATURE_COMINTEROP_MANAGED_ACTIVATION
320 throw new ArgumentNullException("type");
321 Contract.EndContractBlock();
322 if ((type as RuntimeType) == null)
323 throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"),"type");
324 if (!TypeRequiresRegistration(type))
325 throw new ArgumentException(Environment.GetResourceString("Argument_TypeMustBeComCreatable"),"type");
327 // Call the native method to do CoRegisterClassObject
328 return RegisterTypeForComClientsExNative(type, classContext, flags);
329 #else // FEATURE_COMINTEROP_MANAGED_ACTIVATION
330 throw new NotImplementedException("CoreCLR_REMOVED -- managed activation removed"); // @
331 #endif // FEATURE_COMINTEROP_MANAGED_ACTIVATION
334 [System.Security.SecurityCritical] // auto-generated_required
336 public virtual void UnregisterTypeForComClients(int cookie)
338 // Call the native method to do CoRevokeClassObject.
339 CoRevokeClassObject(cookie);
345 #region Internal helpers
347 [System.Security.SecurityCritical] // auto-generated_required
348 internal static bool TypeRequiresRegistrationHelper(Type type)
350 // If the type is not a class or a value class, then it does not get registered.
351 if (!type.IsClass && !type.IsValueType)
354 // If the type is abstract then it does not get registered.
358 // If the does not have a public default constructor then is not creatable from COM so
359 // it does not require registration unless it is a value class.
360 if (!type.IsValueType && type.GetConstructor(BindingFlags.Instance | BindingFlags.Public,null,new Type[0],null) == null)
363 // All other conditions are met so check to see if the type is visible from COM.
364 return Marshal.IsTypeVisibleFromCom(type);
370 #region Private helpers
372 [System.Security.SecurityCritical] // auto-generated
373 [ResourceExposure(ResourceScope.Machine)]
374 [ResourceConsumption(ResourceScope.Machine)]
375 private void RegisterValueType(Type type, String strAsmName, String strAsmVersion, String strAsmCodeBase, String strRuntimeVersion)
377 // Retrieve some information that will be used during the registration process.
378 String strRecordId = "{" + Marshal.GenerateGuidForType(type).ToString().ToUpper(CultureInfo.InvariantCulture) + "}";
380 // Create the HKEY_CLASS_ROOT\Record key.
381 using (RegistryKey RecordRootKey = Registry.ClassesRoot.CreateSubKey(strRecordRootName))
383 // Create the HKEY_CLASS_ROOT\Record\<RecordID> key.
384 using (RegistryKey RecordKey = RecordRootKey.CreateSubKey(strRecordId))
386 // Create the HKEY_CLASS_ROOT\Record\<RecordId>\<version> key.
387 using (RegistryKey RecordVersionKey = RecordKey.CreateSubKey(strAsmVersion))
389 // Set the class value.
390 RecordVersionKey.SetValue("Class", type.FullName);
392 // Set the assembly value.
393 RecordVersionKey.SetValue("Assembly", strAsmName);
395 // Set the runtime version value.
396 RecordVersionKey.SetValue("RuntimeVersion", strRuntimeVersion);
398 // Set the assembly code base value if a code base was specified.
399 if (strAsmCodeBase != null)
400 RecordVersionKey.SetValue("CodeBase", strAsmCodeBase);
406 [System.Security.SecurityCritical] // auto-generated
407 [ResourceExposure(ResourceScope.Machine)]
408 [ResourceConsumption(ResourceScope.Machine)]
409 private void RegisterManagedType(Type type, String strAsmName, String strAsmVersion, String strAsmCodeBase, String strRuntimeVersion)
412 // Retrieve some information that will be used during the registration process.
415 String strDocString = strDocStringPrefix + type.FullName;
416 String strClsId = "{" + Marshal.GenerateGuidForType(type).ToString().ToUpper(CultureInfo.InvariantCulture) + "}";
417 String strProgId = GetProgIdForType(type);
421 // Write the actual type information in the registry.
424 if (strProgId != String.Empty)
426 // Create the HKEY_CLASS_ROOT\<wzProgId> key.
427 using (RegistryKey TypeNameKey = Registry.ClassesRoot.CreateSubKey(strProgId))
429 TypeNameKey.SetValue("", strDocString);
431 // Create the HKEY_CLASS_ROOT\<wzProgId>\CLSID key.
432 using (RegistryKey ProgIdClsIdKey = TypeNameKey.CreateSubKey("CLSID"))
434 ProgIdClsIdKey.SetValue("", strClsId);
439 // Create the HKEY_CLASS_ROOT\CLSID key.
440 using (RegistryKey ClsIdRootKey = Registry.ClassesRoot.CreateSubKey(strClsIdRootName))
442 // Create the HKEY_CLASS_ROOT\CLSID\<CLSID> key.
443 using (RegistryKey ClsIdKey = ClsIdRootKey.CreateSubKey(strClsId))
445 ClsIdKey.SetValue("", strDocString);
447 // Create the HKEY_CLASS_ROOT\CLSID\<CLSID>\InprocServer32 key.
448 using (RegistryKey InProcServerKey = ClsIdKey.CreateSubKey("InprocServer32"))
450 InProcServerKey.SetValue("", strMsCorEEFileName);
451 InProcServerKey.SetValue("ThreadingModel", strManagedTypeThreadingModel);
452 InProcServerKey.SetValue("Class", type.FullName);
453 InProcServerKey.SetValue("Assembly", strAsmName);
454 InProcServerKey.SetValue("RuntimeVersion", strRuntimeVersion);
455 if (strAsmCodeBase != null)
456 InProcServerKey.SetValue("CodeBase", strAsmCodeBase);
458 // Create the HKEY_CLASS_ROOT\CLSID\<CLSID>\InprocServer32\<Version> subkey
459 using (RegistryKey VersionSubKey = InProcServerKey.CreateSubKey(strAsmVersion))
461 VersionSubKey.SetValue("Class", type.FullName);
462 VersionSubKey.SetValue("Assembly", strAsmName);
463 VersionSubKey.SetValue("RuntimeVersion", strRuntimeVersion);
464 if (strAsmCodeBase != null)
465 VersionSubKey.SetValue("CodeBase", strAsmCodeBase);
468 if (strProgId != String.Empty)
470 // Create the HKEY_CLASS_ROOT\CLSID\<CLSID>\ProdId key.
471 using (RegistryKey ProgIdKey = ClsIdKey.CreateSubKey("ProgId"))
473 ProgIdKey.SetValue("", strProgId);
478 // Create the HKEY_CLASS_ROOT\CLSID\<CLSID>\Implemented Categories\<Managed Category Guid> key.
479 using (RegistryKey CategoryKey = ClsIdKey.CreateSubKey(strImplementedCategoriesSubKey))
481 using (RegistryKey ManagedCategoryKey = CategoryKey.CreateSubKey(strManagedCategoryGuid)) {}
488 // Ensure that the managed category exists.
491 EnsureManagedCategoryExists();
494 [System.Security.SecurityCritical] // auto-generated
495 [ResourceExposure(ResourceScope.Machine)]
496 [ResourceConsumption(ResourceScope.Machine)]
497 private void RegisterComImportedType(Type type, String strAsmName, String strAsmVersion, String strAsmCodeBase, String strRuntimeVersion)
499 // Retrieve some information that will be used during the registration process.
500 String strClsId = "{" + Marshal.GenerateGuidForType(type).ToString().ToUpper(CultureInfo.InvariantCulture) + "}";
502 // Create the HKEY_CLASS_ROOT\CLSID key.
503 using (RegistryKey ClsIdRootKey = Registry.ClassesRoot.CreateSubKey(strClsIdRootName))
505 // Create the HKEY_CLASS_ROOT\CLSID\<CLSID> key.
506 using (RegistryKey ClsIdKey = ClsIdRootKey.CreateSubKey(strClsId))
508 // Create the HKEY_CLASS_ROOT\CLSID\<CLSID>\InProcServer32 key.
509 using (RegistryKey InProcServerKey = ClsIdKey.CreateSubKey("InprocServer32"))
511 // Set the class value.
512 InProcServerKey.SetValue("Class", type.FullName);
514 // Set the assembly value.
515 InProcServerKey.SetValue("Assembly", strAsmName);
517 // Set the runtime version value.
518 InProcServerKey.SetValue("RuntimeVersion", strRuntimeVersion);
520 // Set the assembly code base value if a code base was specified.
521 if (strAsmCodeBase != null)
522 InProcServerKey.SetValue("CodeBase", strAsmCodeBase);
524 // Create the HKEY_CLASS_ROOT\CLSID\<CLSID>\InprocServer32\<Version> subkey
525 using (RegistryKey VersionSubKey = InProcServerKey.CreateSubKey(strAsmVersion))
527 VersionSubKey.SetValue("Class", type.FullName);
528 VersionSubKey.SetValue("Assembly", strAsmName);
529 VersionSubKey.SetValue("RuntimeVersion", strRuntimeVersion);
530 if (strAsmCodeBase != null)
531 VersionSubKey.SetValue("CodeBase", strAsmCodeBase);
538 [System.Security.SecurityCritical] // auto-generated
539 [ResourceExposure(ResourceScope.None)]
540 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
541 private bool UnregisterValueType(Type type, String strAsmVersion)
543 bool bAllVersionsGone = true;
545 // Try to open the HKEY_CLASS_ROOT\Record key.
546 String strRecordId = "{" + Marshal.GenerateGuidForType(type).ToString().ToUpper(CultureInfo.InvariantCulture) + "}";
548 using (RegistryKey RecordRootKey = Registry.ClassesRoot.OpenSubKey(strRecordRootName, true))
550 if (RecordRootKey != null)
552 // Open the HKEY_CLASS_ROOT\Record\{RecordId} key.
553 using (RegistryKey RecordKey = RecordRootKey.OpenSubKey(strRecordId,true))
555 if (RecordKey != null)
557 using (RegistryKey VersionSubKey = RecordKey.OpenSubKey(strAsmVersion,true))
559 if (VersionSubKey != null)
561 // Delete the values we created.
562 VersionSubKey.DeleteValue("Assembly",false);
563 VersionSubKey.DeleteValue("Class",false);
564 VersionSubKey.DeleteValue("CodeBase",false);
565 VersionSubKey.DeleteValue("RuntimeVersion",false);
567 // delete the version sub key if no value or subkeys under it
568 if ((VersionSubKey.SubKeyCount == 0) && (VersionSubKey.ValueCount == 0))
569 RecordKey.DeleteSubKey(strAsmVersion);
573 // If there are sub keys left then there are versions left.
574 if (RecordKey.SubKeyCount != 0)
575 bAllVersionsGone = false;
577 // If there are no other values or subkeys then we can delete the HKEY_CLASS_ROOT\Record\{RecordId}.
578 if ((RecordKey.SubKeyCount == 0) && (RecordKey.ValueCount == 0))
579 RecordRootKey.DeleteSubKey(strRecordId);
583 // If there are no other values or subkeys then we can delete the HKEY_CLASS_ROOT\Record.
584 if ((RecordRootKey.SubKeyCount == 0) && (RecordRootKey.ValueCount == 0))
585 Registry.ClassesRoot.DeleteSubKey(strRecordRootName);
589 return bAllVersionsGone;
592 // UnregisterManagedType
595 // true: All versions are gone.
596 // false: Some versions are still left in registry
597 [System.Security.SecurityCritical] // auto-generated
598 [ResourceExposure(ResourceScope.None)]
599 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
600 private bool UnregisterManagedType(Type type,String strAsmVersion)
602 bool bAllVersionsGone = true;
605 // Create the CLSID string.
608 String strClsId = "{" + Marshal.GenerateGuidForType(type).ToString().ToUpper(CultureInfo.InvariantCulture) + "}";
609 String strProgId = GetProgIdForType(type);
613 // Remove the entries under HKEY_CLASS_ROOT\CLSID key.
616 using (RegistryKey ClsIdRootKey = Registry.ClassesRoot.OpenSubKey(strClsIdRootName, true))
618 if (ClsIdRootKey != null)
621 // Remove the entries under HKEY_CLASS_ROOT\CLSID\<CLSID> key.
624 using (RegistryKey ClsIdKey = ClsIdRootKey.OpenSubKey(strClsId, true))
626 if (ClsIdKey != null)
629 // Remove the entries in the HKEY_CLASS_ROOT\CLSID\<CLSID>\InprocServer32 key.
632 using (RegistryKey InProcServerKey = ClsIdKey.OpenSubKey("InprocServer32", true))
634 if (InProcServerKey != null)
637 // Remove the entries in HKEY_CLASS_ROOT\CLSID\<CLSID>\InprocServer32\<Version>
640 using (RegistryKey VersionSubKey = InProcServerKey.OpenSubKey(strAsmVersion, true))
642 if (VersionSubKey != null)
644 // Delete the values we created
645 VersionSubKey.DeleteValue("Assembly",false);
646 VersionSubKey.DeleteValue("Class",false);
647 VersionSubKey.DeleteValue("RuntimeVersion",false);
648 VersionSubKey.DeleteValue("CodeBase",false);
650 // If there are no other values or subkeys then we can delete the VersionSubKey.
651 if ((VersionSubKey.SubKeyCount == 0) && (VersionSubKey.ValueCount == 0))
652 InProcServerKey.DeleteSubKey(strAsmVersion);
656 // If there are sub keys left then there are versions left.
657 if (InProcServerKey.SubKeyCount != 0)
658 bAllVersionsGone = false;
660 // If there are no versions left, then delete the threading model and default value.
661 if (bAllVersionsGone)
663 InProcServerKey.DeleteValue("",false);
664 InProcServerKey.DeleteValue("ThreadingModel",false);
667 InProcServerKey.DeleteValue("Assembly",false);
668 InProcServerKey.DeleteValue("Class",false);
669 InProcServerKey.DeleteValue("RuntimeVersion",false);
670 InProcServerKey.DeleteValue("CodeBase",false);
672 // If there are no other values or subkeys then we can delete the InProcServerKey.
673 if ((InProcServerKey.SubKeyCount == 0) && (InProcServerKey.ValueCount == 0))
674 ClsIdKey.DeleteSubKey("InprocServer32");
678 // remove HKEY_CLASS_ROOT\CLSID\<CLSID>\ProgId
679 // and HKEY_CLASS_ROOT\CLSID\<CLSID>\Implemented Category
680 // only when all versions are removed
681 if (bAllVersionsGone)
683 // Delete the value we created.
684 ClsIdKey.DeleteValue("",false);
686 if (strProgId != String.Empty)
689 // Remove the entries in the HKEY_CLASS_ROOT\CLSID\<CLSID>\ProgId key.
692 using (RegistryKey ProgIdKey = ClsIdKey.OpenSubKey("ProgId", true))
694 if (ProgIdKey != null)
696 // Delete the value we created.
697 ProgIdKey.DeleteValue("",false);
699 // If there are no other values or subkeys then we can delete the ProgIdSubKey.
700 if ((ProgIdKey.SubKeyCount == 0) && (ProgIdKey.ValueCount == 0))
701 ClsIdKey.DeleteSubKey("ProgId");
708 // Remove entries in the HKEY_CLASS_ROOT\CLSID\<CLSID>\Implemented Categories\<Managed Category Guid> key.
711 using (RegistryKey CategoryKey = ClsIdKey.OpenSubKey(strImplementedCategoriesSubKey, true))
713 if (CategoryKey != null)
715 using (RegistryKey ManagedCategoryKey = CategoryKey.OpenSubKey(strManagedCategoryGuid, true))
717 if (ManagedCategoryKey != null)
719 // If there are no other values or subkeys then we can delete the ManagedCategoryKey.
720 if ((ManagedCategoryKey.SubKeyCount == 0) && (ManagedCategoryKey.ValueCount == 0))
721 CategoryKey.DeleteSubKey(strManagedCategoryGuid);
725 // If there are no other values or subkeys then we can delete the CategoryKey.
726 if ((CategoryKey.SubKeyCount == 0) && (CategoryKey.ValueCount == 0))
727 ClsIdKey.DeleteSubKey(strImplementedCategoriesSubKey);
732 // If there are no other values or subkeys then we can delete the ClsIdKey.
733 if ((ClsIdKey.SubKeyCount == 0) && (ClsIdKey.ValueCount == 0))
734 ClsIdRootKey.DeleteSubKey(strClsId);
738 // If there are no other values or subkeys then we can delete the CLSID key.
739 if ((ClsIdRootKey.SubKeyCount == 0) && (ClsIdRootKey.ValueCount == 0))
740 Registry.ClassesRoot.DeleteSubKey(strClsIdRootName);
745 // Remove the entries under HKEY_CLASS_ROOT\<wzProgId> key.
748 if (bAllVersionsGone)
750 if (strProgId != String.Empty)
752 using (RegistryKey TypeNameKey = Registry.ClassesRoot.OpenSubKey(strProgId, true))
754 if (TypeNameKey != null)
756 // Delete the values we created.
757 TypeNameKey.DeleteValue("",false);
761 // Remove the entries in the HKEY_CLASS_ROOT\<wzProgId>\CLSID key.
764 using (RegistryKey ProgIdClsIdKey = TypeNameKey.OpenSubKey("CLSID", true))
766 if (ProgIdClsIdKey != null)
768 // Delete the values we created.
769 ProgIdClsIdKey.DeleteValue("",false);
771 // If there are no other values or subkeys then we can delete the ProgIdClsIdKey.
772 if ((ProgIdClsIdKey.SubKeyCount == 0) && (ProgIdClsIdKey.ValueCount == 0))
773 TypeNameKey.DeleteSubKey("CLSID");
777 // If there are no other values or subkeys then we can delete the TypeNameKey.
778 if ((TypeNameKey.SubKeyCount == 0) && (TypeNameKey.ValueCount == 0))
779 Registry.ClassesRoot.DeleteSubKey(strProgId);
786 return bAllVersionsGone;
789 // UnregisterComImportedType
791 // true: All version information are gone.
792 // false: There are still some version left in registry
793 [System.Security.SecurityCritical] // auto-generated
794 [ResourceExposure(ResourceScope.None)]
795 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
796 private bool UnregisterComImportedType(Type type, String strAsmVersion)
798 bool bAllVersionsGone = true;
800 String strClsId = "{" + Marshal.GenerateGuidForType(type).ToString().ToUpper(CultureInfo.InvariantCulture) + "}";
802 // Try to open the HKEY_CLASS_ROOT\CLSID key.
803 using (RegistryKey ClsIdRootKey = Registry.ClassesRoot.OpenSubKey(strClsIdRootName, true))
805 if (ClsIdRootKey != null)
807 // Try to open the HKEY_CLASS_ROOT\CLSID\<CLSID> key.
808 using (RegistryKey ClsIdKey = ClsIdRootKey.OpenSubKey(strClsId, true))
810 if (ClsIdKey != null)
812 // Try to open the HKEY_CLASS_ROOT\CLSID\<CLSID>\InProcServer32 key.
813 using (RegistryKey InProcServerKey = ClsIdKey.OpenSubKey("InprocServer32", true))
815 if (InProcServerKey != null)
817 // Delete the values we created.
818 InProcServerKey.DeleteValue("Assembly",false);
819 InProcServerKey.DeleteValue("Class",false);
820 InProcServerKey.DeleteValue("RuntimeVersion",false);
821 InProcServerKey.DeleteValue("CodeBase",false);
823 // Try to open the entries in HKEY_CLASS_ROOT\CLSID\<CLSID>\InProcServer32\<Version>
824 using (RegistryKey VersionSubKey = InProcServerKey.OpenSubKey(strAsmVersion,true))
826 if (VersionSubKey != null)
828 // Delete the value we created
829 VersionSubKey.DeleteValue("Assembly",false);
830 VersionSubKey.DeleteValue("Class",false);
831 VersionSubKey.DeleteValue("RuntimeVersion",false);
832 VersionSubKey.DeleteValue("CodeBase",false);
834 // If there are no other values or subkeys then we can delete the VersionSubKey
835 if ((VersionSubKey.SubKeyCount == 0) && (VersionSubKey.ValueCount == 0))
836 InProcServerKey.DeleteSubKey(strAsmVersion);
840 // If there are sub keys left then there are versions left.
841 if (InProcServerKey.SubKeyCount != 0)
842 bAllVersionsGone = false;
844 // If there are no other values or subkeys then we can delete the InProcServerKey.
845 if ((InProcServerKey.SubKeyCount == 0) && (InProcServerKey.ValueCount == 0))
846 ClsIdKey.DeleteSubKey("InprocServer32");
850 // If there are no other values or subkeys then we can delete the ClsIdKey.
851 if ((ClsIdKey.SubKeyCount == 0) && (ClsIdKey.ValueCount == 0))
852 ClsIdRootKey.DeleteSubKey(strClsId);
856 // If there are no other values or subkeys then we can delete the CLSID key.
857 if ((ClsIdRootKey.SubKeyCount == 0) && (ClsIdRootKey.ValueCount == 0))
858 Registry.ClassesRoot.DeleteSubKey(strClsIdRootName);
862 return bAllVersionsGone;
865 [System.Security.SecurityCritical] // auto-generated
866 [ResourceExposure(ResourceScope.Machine)]
867 [ResourceConsumption(ResourceScope.Machine)]
868 private void RegisterPrimaryInteropAssembly(RuntimeAssembly assembly, String strAsmCodeBase, PrimaryInteropAssemblyAttribute attr)
870 // Validate that the PIA has a strong name.
871 if (assembly.GetPublicKey().Length == 0)
872 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_PIAMustBeStrongNamed"));
874 String strTlbId = "{" + Marshal.GetTypeLibGuidForAssembly(assembly).ToString().ToUpper(CultureInfo.InvariantCulture) + "}";
875 String strVersion = attr.MajorVersion.ToString("x", CultureInfo.InvariantCulture) + "." + attr.MinorVersion.ToString("x", CultureInfo.InvariantCulture);
877 // Create the HKEY_CLASS_ROOT\TypeLib key.
878 using (RegistryKey TypeLibRootKey = Registry.ClassesRoot.CreateSubKey(strTlbRootName))
880 // Create the HKEY_CLASS_ROOT\TypeLib\<TLBID> key.
881 using (RegistryKey TypeLibKey = TypeLibRootKey.CreateSubKey(strTlbId))
883 // Create the HKEY_CLASS_ROOT\TypeLib\<TLBID>\<Major.Minor> key.
884 using (RegistryKey VersionSubKey = TypeLibKey.CreateSubKey(strVersion))
886 // Create the HKEY_CLASS_ROOT\TypeLib\<TLBID>\PrimaryInteropAssembly key.
887 VersionSubKey.SetValue("PrimaryInteropAssemblyName", assembly.FullName);
888 if (strAsmCodeBase != null)
889 VersionSubKey.SetValue("PrimaryInteropAssemblyCodeBase", strAsmCodeBase);
895 [System.Security.SecurityCritical] // auto-generated
896 [ResourceExposure(ResourceScope.None)]
897 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
898 private void UnregisterPrimaryInteropAssembly(Assembly assembly, PrimaryInteropAssemblyAttribute attr)
900 String strTlbId = "{" + Marshal.GetTypeLibGuidForAssembly(assembly).ToString().ToUpper(CultureInfo.InvariantCulture) + "}";
901 String strVersion = attr.MajorVersion.ToString("x", CultureInfo.InvariantCulture) + "." + attr.MinorVersion.ToString("x", CultureInfo.InvariantCulture);
903 // Try to open the HKEY_CLASS_ROOT\TypeLib key.
904 using (RegistryKey TypeLibRootKey = Registry.ClassesRoot.OpenSubKey(strTlbRootName, true))
906 if (TypeLibRootKey != null)
908 // Try to open the HKEY_CLASS_ROOT\TypeLib\<TLBID> key.
909 using (RegistryKey TypeLibKey = TypeLibRootKey.OpenSubKey(strTlbId, true))
911 if (TypeLibKey != null)
913 // Try to open the HKEY_CLASS_ROOT\TypeLib<TLBID>\<Major.Minor> key.
914 using (RegistryKey VersionSubKey = TypeLibKey.OpenSubKey(strVersion, true))
916 if (VersionSubKey != null)
918 // Delete the values we created.
919 VersionSubKey.DeleteValue("PrimaryInteropAssemblyName",false);
920 VersionSubKey.DeleteValue("PrimaryInteropAssemblyCodeBase",false);
922 // If there are no other values or subkeys then we can delete the VersionKey.
923 if ((VersionSubKey.SubKeyCount == 0) && (VersionSubKey.ValueCount == 0))
924 TypeLibKey.DeleteSubKey(strVersion);
928 // If there are no other values or subkeys then we can delete the TypeLibKey.
929 if ((TypeLibKey.SubKeyCount == 0) && (TypeLibKey.ValueCount == 0))
930 TypeLibRootKey.DeleteSubKey(strTlbId);
934 // If there are no other values or subkeys then we can delete the TypeLib key.
935 if ((TypeLibRootKey.SubKeyCount == 0) && (TypeLibRootKey.ValueCount == 0))
936 Registry.ClassesRoot.DeleteSubKey(strTlbRootName);
941 [ResourceExposure(ResourceScope.None)]
942 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
943 private void EnsureManagedCategoryExists()
945 if (!ManagedCategoryExists())
947 // Create the HKEY_CLASS_ROOT\Component Category key.
948 using (RegistryKey ComponentCategoryKey = Registry.ClassesRoot.CreateSubKey(strComponentCategorySubKey))
950 // Create the HKEY_CLASS_ROOT\Component Category\<Managed Category Guid> key.
951 using (RegistryKey ManagedCategoryKey = ComponentCategoryKey.CreateSubKey(strManagedCategoryGuid))
953 ManagedCategoryKey.SetValue("0", strManagedCategoryDescription);
959 [ResourceExposure(ResourceScope.None)]
960 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
961 private static bool ManagedCategoryExists()
963 using (RegistryKey componentCategoryKey = Registry.ClassesRoot.OpenSubKey(strComponentCategorySubKey,
965 RegistryKeyPermissionCheck.ReadSubTree))
970 if (componentCategoryKey == null)
972 using (RegistryKey managedCategoryKey = componentCategoryKey.OpenSubKey(strManagedCategoryGuid,
974 RegistryKeyPermissionCheck.ReadSubTree))
979 if (managedCategoryKey == null)
981 object value = managedCategoryKey.GetValue("0");
982 if (value == null || value.GetType() != typeof(string))
984 string stringValue = (string)value;
985 if (stringValue != strManagedCategoryDescription)
993 [System.Security.SecurityCritical] // auto-generated
994 private void CallUserDefinedRegistrationMethod(Type type, bool bRegister)
996 bool bFunctionCalled = false;
998 // Retrieve the attribute type to use to determine if a function is the requested user defined
999 // registration function.
1000 Type RegFuncAttrType = null;
1002 RegFuncAttrType = typeof(ComRegisterFunctionAttribute);
1004 RegFuncAttrType = typeof(ComUnregisterFunctionAttribute);
1006 for(Type currType = type; !bFunctionCalled && currType != null; currType = currType.BaseType)
1008 // Retrieve all the methods.
1009 MethodInfo[] aMethods = currType.GetMethods(BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static);
1010 int NumMethods = aMethods.Length;
1012 // Go through all the methods and check for the ComRegisterMethod custom attribute.
1013 for(int cMethods = 0;cMethods < NumMethods;cMethods++)
1015 MethodInfo CurrentMethod = aMethods[cMethods];
1017 // Check to see if the method has the custom attribute.
1018 if(CurrentMethod.GetCustomAttributes(RegFuncAttrType, true).Length != 0)
1020 // Check to see if the method is static before we call it.
1021 if(!CurrentMethod.IsStatic)
1024 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NonStaticComRegFunction",CurrentMethod.Name,currType.Name));
1026 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NonStaticComUnRegFunction",CurrentMethod.Name,currType.Name));
1029 // Finally check that the signature is string ret void.
1030 ParameterInfo[] aParams = CurrentMethod.GetParameters();
1031 if (CurrentMethod.ReturnType != typeof(void) ||
1033 aParams.Length != 1 ||
1034 (aParams[0].ParameterType != typeof(String) && aParams[0].ParameterType != typeof(Type)))
1037 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_InvalidComRegFunctionSig",CurrentMethod.Name,currType.Name));
1039 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_InvalidComUnRegFunctionSig",CurrentMethod.Name,currType.Name));
1042 // There can only be one register and one unregister function per type.
1046 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_MultipleComRegFunctions",currType.Name));
1048 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_MultipleComUnRegFunctions",currType.Name));
1051 // The function is valid so set up the arguments to call it.
1052 Object[] objs = new Object[1];
1053 if(aParams[0].ParameterType == typeof(String))
1055 // We are dealing with the string overload of the function.
1056 objs[0] = "HKEY_CLASSES_ROOT\\CLSID\\{" + Marshal.GenerateGuidForType(type).ToString().ToUpper(CultureInfo.InvariantCulture) + "}";
1060 // We are dealing with the type overload of the function.
1064 // Invoke the COM register function.
1065 CurrentMethod.Invoke(null, objs);
1067 // Mark the function as having been called.
1068 bFunctionCalled = true;
1074 private Type GetBaseComImportType(Type type)
1076 for (; type != null && !type.IsImport; type = type.BaseType);
1080 private bool IsRegisteredAsValueType(Type type)
1082 if (!type.IsValueType)
1091 #region FCalls and DllImports
1093 #if FEATURE_COMINTEROP_MANAGED_ACTIVATION
1094 // GUID versioning can be controlled by using the GuidAttribute or
1095 // letting the runtime generate it based on type and assembly strong name.
1096 [System.Security.SecurityCritical] // auto-generated
1097 [ResourceExposure(ResourceScope.None)]
1098 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1099 private static extern void RegisterTypeForComClientsNative(Type type,ref Guid g);
1101 // GUID versioning can be controlled by using the GuidAttribute or
1102 // letting the runtime generate it based on type and assembly strong name.
1103 [System.Security.SecurityCritical] // auto-generated
1104 [ResourceExposure(ResourceScope.None)]
1105 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1106 private static extern int RegisterTypeForComClientsExNative(Type t, RegistrationClassContext clsContext, RegistrationConnectionType flags);
1107 #endif // FEATURE_COMINTEROP_MANAGED_ACTIVATION
1109 [DllImport(Win32Native.OLE32,CharSet=CharSet.Auto,PreserveSig=false)]
1110 [ResourceExposure(ResourceScope.None)]
1111 private static extern void CoRevokeClassObject(int cookie);