// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== /*============================================================================= ** ** Class: RegistrationServices ** ** ** Purpose: This class provides services for registering and unregistering ** a managed server for use by COM. ** ** ** ** ** Change the way how to register and unregister a managed server ** =============================================================================*/ namespace System.Runtime.InteropServices { using System; using System.Collections; using System.IO; using System.Reflection; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using Microsoft.Win32; using System.Runtime.CompilerServices; using System.Globalization; using System.Runtime.Versioning; using System.Diagnostics.Contracts; [Flags] public enum RegistrationClassContext { InProcessServer = 0x1, InProcessHandler = 0x2, LocalServer = 0x4, InProcessServer16 = 0x8, RemoteServer = 0x10, InProcessHandler16 = 0x20, Reserved1 = 0x40, Reserved2 = 0x80, Reserved3 = 0x100, Reserved4 = 0x200, NoCodeDownload = 0x400, Reserved5 = 0x800, NoCustomMarshal = 0x1000, EnableCodeDownload = 0x2000, NoFailureLog = 0x4000, DisableActivateAsActivator = 0x8000, EnableActivateAsActivator = 0x10000, FromDefaultContext = 0x20000 } [Flags] public enum RegistrationConnectionType { SingleUse = 0, MultipleUse = 1, MultiSeparate = 2, Suspended = 4, Surrogate = 8, } [Guid("475E398F-8AFA-43a7-A3BE-F4EF8D6787C9")] [ClassInterface(ClassInterfaceType.None)] [System.Runtime.InteropServices.ComVisible(true)] public class RegistrationServices : IRegistrationServices { #region Constants private const String strManagedCategoryGuid = "{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}"; private const String strDocStringPrefix = ""; private const String strManagedTypeThreadingModel = "Both"; private const String strComponentCategorySubKey = "Component Categories"; private const String strManagedCategoryDescription = ".NET Category"; private const String strImplementedCategoriesSubKey = "Implemented Categories"; private const String strMsCorEEFileName = "mscoree.dll"; private const String strRecordRootName = "Record"; private const String strClsIdRootName = "CLSID"; private const String strTlbRootName = "TypeLib"; private static Guid s_ManagedCategoryGuid = new Guid(strManagedCategoryGuid); #endregion #region IRegistrationServices [System.Security.SecurityCritical] // auto-generated_required [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] public virtual bool RegisterAssembly(Assembly assembly, AssemblyRegistrationFlags flags) { // Validate the arguments. if (assembly == null) throw new ArgumentNullException("assembly"); if (assembly.ReflectionOnly) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AsmLoadedForReflectionOnly")); Contract.EndContractBlock(); RuntimeAssembly rtAssembly = assembly as RuntimeAssembly; if (rtAssembly == null) throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeAssembly")); // Retrieve the assembly names. String strAsmName = assembly.FullName; if (strAsmName == null) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NoAsmName")); // Retrieve the assembly codebase. String strAsmCodeBase = null; if ((flags & AssemblyRegistrationFlags.SetCodeBase) != 0) { strAsmCodeBase = rtAssembly.GetCodeBase(false); if (strAsmCodeBase == null) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NoAsmCodeBase")); } // Go through all the registerable types in the assembly and register them. Type[] aTypes = GetRegistrableTypesInAssembly(assembly); int NumTypes = aTypes.Length; String strAsmVersion = rtAssembly.GetVersion().ToString(); // Retrieve the runtime version used to build the assembly. String strRuntimeVersion = assembly.ImageRuntimeVersion; for (int cTypes = 0; cTypes < NumTypes; cTypes++) { if (IsRegisteredAsValueType(aTypes[cTypes])) RegisterValueType(aTypes[cTypes], strAsmName, strAsmVersion, strAsmCodeBase, strRuntimeVersion); else if (TypeRepresentsComType(aTypes[cTypes])) RegisterComImportedType(aTypes[cTypes], strAsmName, strAsmVersion, strAsmCodeBase, strRuntimeVersion); else RegisterManagedType(aTypes[cTypes], strAsmName, strAsmVersion, strAsmCodeBase, strRuntimeVersion); CallUserDefinedRegistrationMethod(aTypes[cTypes], true); } // If this assembly has the PIA attribute, then register it as a PIA. Object[] aPIAAttrs = assembly.GetCustomAttributes(typeof(PrimaryInteropAssemblyAttribute), false); int NumPIAAttrs = aPIAAttrs.Length; for (int cPIAAttrs = 0; cPIAAttrs < NumPIAAttrs; cPIAAttrs++) RegisterPrimaryInteropAssembly(rtAssembly, strAsmCodeBase, (PrimaryInteropAssemblyAttribute)aPIAAttrs[cPIAAttrs]); // Return value indicating if we actually registered any types. if (aTypes.Length > 0 || NumPIAAttrs > 0) return true; else return false; } [System.Security.SecurityCritical] // auto-generated_required public virtual bool UnregisterAssembly(Assembly assembly) { // Validate the arguments. if (assembly == null) throw new ArgumentNullException("assembly"); if (assembly.ReflectionOnly) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AsmLoadedForReflectionOnly")); Contract.EndContractBlock(); RuntimeAssembly rtAssembly = assembly as RuntimeAssembly; if (rtAssembly == null) throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeAssembly")); bool bAllVersionsGone = true; // Go through all the registrable types in the assembly and register them. Type[] aTypes = GetRegistrableTypesInAssembly(assembly); int NumTypes = aTypes.Length; // Retrieve the assembly version String strAsmVersion = rtAssembly.GetVersion().ToString(); for (int cTypes = 0;cTypes < NumTypes;cTypes++) { CallUserDefinedRegistrationMethod(aTypes[cTypes], false); if (IsRegisteredAsValueType(aTypes[cTypes])) { if (!UnregisterValueType(aTypes[cTypes], strAsmVersion)) bAllVersionsGone = false; } else if (TypeRepresentsComType(aTypes[cTypes])) { if (!UnregisterComImportedType(aTypes[cTypes], strAsmVersion)) bAllVersionsGone = false; } else { if (!UnregisterManagedType(aTypes[cTypes], strAsmVersion)) bAllVersionsGone = false; } } // If this assembly has the PIA attribute, then unregister it as a PIA. Object[] aPIAAttrs = assembly.GetCustomAttributes(typeof(PrimaryInteropAssemblyAttribute),false); int NumPIAAttrs = aPIAAttrs.Length; if (bAllVersionsGone) { for (int cPIAAttrs = 0;cPIAAttrs < NumPIAAttrs;cPIAAttrs++) UnregisterPrimaryInteropAssembly(assembly, (PrimaryInteropAssemblyAttribute)aPIAAttrs[cPIAAttrs]); } // Return value indicating if we actually un-registered any types. if (aTypes.Length > 0 || NumPIAAttrs > 0) return true; else return false; } [System.Security.SecurityCritical] // auto-generated_required public virtual Type[] GetRegistrableTypesInAssembly(Assembly assembly) { // Validate the arguments. if (assembly == null) throw new ArgumentNullException("assembly"); Contract.EndContractBlock(); if (!(assembly is RuntimeAssembly)) throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeAssembly"), "assembly"); // Retrieve the list of types in the assembly. Type[] aTypes = assembly.GetExportedTypes(); int NumTypes = aTypes.Length; // Create an array list that will be filled in. ArrayList TypeList = new ArrayList(); // Register all the types that require registration. for (int cTypes = 0; cTypes < NumTypes; cTypes++) { Type CurrentType = aTypes[cTypes]; if (TypeRequiresRegistration(CurrentType)) TypeList.Add(CurrentType); } // Copy the array list to an array and return it. Type[] RetArray = new Type[TypeList.Count]; TypeList.CopyTo(RetArray); return RetArray; } [System.Security.SecurityCritical] // auto-generated_required public virtual String GetProgIdForType(Type type) { return Marshal.GenerateProgIdForType(type); } [System.Security.SecurityCritical] // auto-generated_required public virtual void RegisterTypeForComClients(Type type, ref Guid g) { #if FEATURE_COMINTEROP_MANAGED_ACTIVATION if(type == null) throw new ArgumentNullException("type"); Contract.EndContractBlock(); if((type as RuntimeType) == null) throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"),"type"); if(!TypeRequiresRegistration(type)) throw new ArgumentException(Environment.GetResourceString("Argument_TypeMustBeComCreatable"),"type"); // Call the native method to do CoRegisterClassObject RegisterTypeForComClientsNative(type, ref g); #else // FEATURE_COMINTEROP_MANAGED_ACTIVATION throw new NotImplementedException("CoreCLR_REMOVED -- managed activation removed"); // @ #endif // FEATURE_COMINTEROP_MANAGED_ACTIVATION } public virtual Guid GetManagedCategoryGuid() { return s_ManagedCategoryGuid; } [System.Security.SecurityCritical] // auto-generated_required public virtual bool TypeRequiresRegistration(Type type) { return TypeRequiresRegistrationHelper(type); } [System.Security.SecuritySafeCritical] // auto-generated public virtual bool TypeRepresentsComType(Type type) { // If the type is not a COM import, then it does not represent a COM type. if (!type.IsCOMObject) return false; // If it is marked as tdImport, then it represents a COM type directly. if (type.IsImport) return true; // If the type is derived from a tdImport class and has the same GUID as the // imported class, then it represents a COM type. Type baseComImportType = GetBaseComImportType(type); Contract.Assert(baseComImportType != null, "baseComImportType != null"); if (Marshal.GenerateGuidForType(type) == Marshal.GenerateGuidForType(baseComImportType)) return true; return false; } #endregion #region Public methods not on IRegistrationServices [System.Security.SecurityCritical] // auto-generated_required [ComVisible(false)] public virtual int RegisterTypeForComClients(Type type, RegistrationClassContext classContext, RegistrationConnectionType flags) { #if FEATURE_COMINTEROP_MANAGED_ACTIVATION if (type == null) throw new ArgumentNullException("type"); Contract.EndContractBlock(); if ((type as RuntimeType) == null) throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"),"type"); if (!TypeRequiresRegistration(type)) throw new ArgumentException(Environment.GetResourceString("Argument_TypeMustBeComCreatable"),"type"); // Call the native method to do CoRegisterClassObject return RegisterTypeForComClientsExNative(type, classContext, flags); #else // FEATURE_COMINTEROP_MANAGED_ACTIVATION throw new NotImplementedException("CoreCLR_REMOVED -- managed activation removed"); // @ #endif // FEATURE_COMINTEROP_MANAGED_ACTIVATION } [System.Security.SecurityCritical] // auto-generated_required [ComVisible(false)] public virtual void UnregisterTypeForComClients(int cookie) { // Call the native method to do CoRevokeClassObject. CoRevokeClassObject(cookie); } #endregion #region Internal helpers [System.Security.SecurityCritical] // auto-generated_required internal static bool TypeRequiresRegistrationHelper(Type type) { // If the type is not a class or a value class, then it does not get registered. if (!type.IsClass && !type.IsValueType) return false; // If the type is abstract then it does not get registered. if (type.IsAbstract) return false; // If the does not have a public default constructor then is not creatable from COM so // it does not require registration unless it is a value class. if (!type.IsValueType && type.GetConstructor(BindingFlags.Instance | BindingFlags.Public,null,new Type[0],null) == null) return false; // All other conditions are met so check to see if the type is visible from COM. return Marshal.IsTypeVisibleFromCom(type); } #endregion #region Private helpers [System.Security.SecurityCritical] // auto-generated [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] private void RegisterValueType(Type type, String strAsmName, String strAsmVersion, String strAsmCodeBase, String strRuntimeVersion) { // Retrieve some information that will be used during the registration process. String strRecordId = "{" + Marshal.GenerateGuidForType(type).ToString().ToUpper(CultureInfo.InvariantCulture) + "}"; // Create the HKEY_CLASS_ROOT\Record key. using (RegistryKey RecordRootKey = Registry.ClassesRoot.CreateSubKey(strRecordRootName)) { // Create the HKEY_CLASS_ROOT\Record\ key. using (RegistryKey RecordKey = RecordRootKey.CreateSubKey(strRecordId)) { // Create the HKEY_CLASS_ROOT\Record\\ key. using (RegistryKey RecordVersionKey = RecordKey.CreateSubKey(strAsmVersion)) { // Set the class value. RecordVersionKey.SetValue("Class", type.FullName); // Set the assembly value. RecordVersionKey.SetValue("Assembly", strAsmName); // Set the runtime version value. RecordVersionKey.SetValue("RuntimeVersion", strRuntimeVersion); // Set the assembly code base value if a code base was specified. if (strAsmCodeBase != null) RecordVersionKey.SetValue("CodeBase", strAsmCodeBase); } } } } [System.Security.SecurityCritical] // auto-generated [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] private void RegisterManagedType(Type type, String strAsmName, String strAsmVersion, String strAsmCodeBase, String strRuntimeVersion) { // // Retrieve some information that will be used during the registration process. // String strDocString = strDocStringPrefix + type.FullName; String strClsId = "{" + Marshal.GenerateGuidForType(type).ToString().ToUpper(CultureInfo.InvariantCulture) + "}"; String strProgId = GetProgIdForType(type); // // Write the actual type information in the registry. // if (strProgId != String.Empty) { // Create the HKEY_CLASS_ROOT\ key. using (RegistryKey TypeNameKey = Registry.ClassesRoot.CreateSubKey(strProgId)) { TypeNameKey.SetValue("", strDocString); // Create the HKEY_CLASS_ROOT\\CLSID key. using (RegistryKey ProgIdClsIdKey = TypeNameKey.CreateSubKey("CLSID")) { ProgIdClsIdKey.SetValue("", strClsId); } } } // Create the HKEY_CLASS_ROOT\CLSID key. using (RegistryKey ClsIdRootKey = Registry.ClassesRoot.CreateSubKey(strClsIdRootName)) { // Create the HKEY_CLASS_ROOT\CLSID\ key. using (RegistryKey ClsIdKey = ClsIdRootKey.CreateSubKey(strClsId)) { ClsIdKey.SetValue("", strDocString); // Create the HKEY_CLASS_ROOT\CLSID\\InprocServer32 key. using (RegistryKey InProcServerKey = ClsIdKey.CreateSubKey("InprocServer32")) { InProcServerKey.SetValue("", strMsCorEEFileName); InProcServerKey.SetValue("ThreadingModel", strManagedTypeThreadingModel); InProcServerKey.SetValue("Class", type.FullName); InProcServerKey.SetValue("Assembly", strAsmName); InProcServerKey.SetValue("RuntimeVersion", strRuntimeVersion); if (strAsmCodeBase != null) InProcServerKey.SetValue("CodeBase", strAsmCodeBase); // Create the HKEY_CLASS_ROOT\CLSID\\InprocServer32\ subkey using (RegistryKey VersionSubKey = InProcServerKey.CreateSubKey(strAsmVersion)) { VersionSubKey.SetValue("Class", type.FullName); VersionSubKey.SetValue("Assembly", strAsmName); VersionSubKey.SetValue("RuntimeVersion", strRuntimeVersion); if (strAsmCodeBase != null) VersionSubKey.SetValue("CodeBase", strAsmCodeBase); } if (strProgId != String.Empty) { // Create the HKEY_CLASS_ROOT\CLSID\\ProdId key. using (RegistryKey ProgIdKey = ClsIdKey.CreateSubKey("ProgId")) { ProgIdKey.SetValue("", strProgId); } } } // Create the HKEY_CLASS_ROOT\CLSID\\Implemented Categories\ key. using (RegistryKey CategoryKey = ClsIdKey.CreateSubKey(strImplementedCategoriesSubKey)) { using (RegistryKey ManagedCategoryKey = CategoryKey.CreateSubKey(strManagedCategoryGuid)) {} } } } // // Ensure that the managed category exists. // EnsureManagedCategoryExists(); } [System.Security.SecurityCritical] // auto-generated [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] private void RegisterComImportedType(Type type, String strAsmName, String strAsmVersion, String strAsmCodeBase, String strRuntimeVersion) { // Retrieve some information that will be used during the registration process. String strClsId = "{" + Marshal.GenerateGuidForType(type).ToString().ToUpper(CultureInfo.InvariantCulture) + "}"; // Create the HKEY_CLASS_ROOT\CLSID key. using (RegistryKey ClsIdRootKey = Registry.ClassesRoot.CreateSubKey(strClsIdRootName)) { // Create the HKEY_CLASS_ROOT\CLSID\ key. using (RegistryKey ClsIdKey = ClsIdRootKey.CreateSubKey(strClsId)) { // Create the HKEY_CLASS_ROOT\CLSID\\InProcServer32 key. using (RegistryKey InProcServerKey = ClsIdKey.CreateSubKey("InprocServer32")) { // Set the class value. InProcServerKey.SetValue("Class", type.FullName); // Set the assembly value. InProcServerKey.SetValue("Assembly", strAsmName); // Set the runtime version value. InProcServerKey.SetValue("RuntimeVersion", strRuntimeVersion); // Set the assembly code base value if a code base was specified. if (strAsmCodeBase != null) InProcServerKey.SetValue("CodeBase", strAsmCodeBase); // Create the HKEY_CLASS_ROOT\CLSID\\InprocServer32\ subkey using (RegistryKey VersionSubKey = InProcServerKey.CreateSubKey(strAsmVersion)) { VersionSubKey.SetValue("Class", type.FullName); VersionSubKey.SetValue("Assembly", strAsmName); VersionSubKey.SetValue("RuntimeVersion", strRuntimeVersion); if (strAsmCodeBase != null) VersionSubKey.SetValue("CodeBase", strAsmCodeBase); } } } } } [System.Security.SecurityCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] private bool UnregisterValueType(Type type, String strAsmVersion) { bool bAllVersionsGone = true; // Try to open the HKEY_CLASS_ROOT\Record key. String strRecordId = "{" + Marshal.GenerateGuidForType(type).ToString().ToUpper(CultureInfo.InvariantCulture) + "}"; using (RegistryKey RecordRootKey = Registry.ClassesRoot.OpenSubKey(strRecordRootName, true)) { if (RecordRootKey != null) { // Open the HKEY_CLASS_ROOT\Record\{RecordId} key. using (RegistryKey RecordKey = RecordRootKey.OpenSubKey(strRecordId,true)) { if (RecordKey != null) { using (RegistryKey VersionSubKey = RecordKey.OpenSubKey(strAsmVersion,true)) { if (VersionSubKey != null) { // Delete the values we created. VersionSubKey.DeleteValue("Assembly",false); VersionSubKey.DeleteValue("Class",false); VersionSubKey.DeleteValue("CodeBase",false); VersionSubKey.DeleteValue("RuntimeVersion",false); // delete the version sub key if no value or subkeys under it if ((VersionSubKey.SubKeyCount == 0) && (VersionSubKey.ValueCount == 0)) RecordKey.DeleteSubKey(strAsmVersion); } } // If there are sub keys left then there are versions left. if (RecordKey.SubKeyCount != 0) bAllVersionsGone = false; // If there are no other values or subkeys then we can delete the HKEY_CLASS_ROOT\Record\{RecordId}. if ((RecordKey.SubKeyCount == 0) && (RecordKey.ValueCount == 0)) RecordRootKey.DeleteSubKey(strRecordId); } } // If there are no other values or subkeys then we can delete the HKEY_CLASS_ROOT\Record. if ((RecordRootKey.SubKeyCount == 0) && (RecordRootKey.ValueCount == 0)) Registry.ClassesRoot.DeleteSubKey(strRecordRootName); } } return bAllVersionsGone; } // UnregisterManagedType // // Return : // true: All versions are gone. // false: Some versions are still left in registry [System.Security.SecurityCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] private bool UnregisterManagedType(Type type,String strAsmVersion) { bool bAllVersionsGone = true; // // Create the CLSID string. // String strClsId = "{" + Marshal.GenerateGuidForType(type).ToString().ToUpper(CultureInfo.InvariantCulture) + "}"; String strProgId = GetProgIdForType(type); // // Remove the entries under HKEY_CLASS_ROOT\CLSID key. // using (RegistryKey ClsIdRootKey = Registry.ClassesRoot.OpenSubKey(strClsIdRootName, true)) { if (ClsIdRootKey != null) { // // Remove the entries under HKEY_CLASS_ROOT\CLSID\ key. // using (RegistryKey ClsIdKey = ClsIdRootKey.OpenSubKey(strClsId, true)) { if (ClsIdKey != null) { // // Remove the entries in the HKEY_CLASS_ROOT\CLSID\\InprocServer32 key. // using (RegistryKey InProcServerKey = ClsIdKey.OpenSubKey("InprocServer32", true)) { if (InProcServerKey != null) { // // Remove the entries in HKEY_CLASS_ROOT\CLSID\\InprocServer32\ // using (RegistryKey VersionSubKey = InProcServerKey.OpenSubKey(strAsmVersion, true)) { if (VersionSubKey != null) { // Delete the values we created VersionSubKey.DeleteValue("Assembly",false); VersionSubKey.DeleteValue("Class",false); VersionSubKey.DeleteValue("RuntimeVersion",false); VersionSubKey.DeleteValue("CodeBase",false); // If there are no other values or subkeys then we can delete the VersionSubKey. if ((VersionSubKey.SubKeyCount == 0) && (VersionSubKey.ValueCount == 0)) InProcServerKey.DeleteSubKey(strAsmVersion); } } // If there are sub keys left then there are versions left. if (InProcServerKey.SubKeyCount != 0) bAllVersionsGone = false; // If there are no versions left, then delete the threading model and default value. if (bAllVersionsGone) { InProcServerKey.DeleteValue("",false); InProcServerKey.DeleteValue("ThreadingModel",false); } InProcServerKey.DeleteValue("Assembly",false); InProcServerKey.DeleteValue("Class",false); InProcServerKey.DeleteValue("RuntimeVersion",false); InProcServerKey.DeleteValue("CodeBase",false); // If there are no other values or subkeys then we can delete the InProcServerKey. if ((InProcServerKey.SubKeyCount == 0) && (InProcServerKey.ValueCount == 0)) ClsIdKey.DeleteSubKey("InprocServer32"); } } // remove HKEY_CLASS_ROOT\CLSID\\ProgId // and HKEY_CLASS_ROOT\CLSID\\Implemented Category // only when all versions are removed if (bAllVersionsGone) { // Delete the value we created. ClsIdKey.DeleteValue("",false); if (strProgId != String.Empty) { // // Remove the entries in the HKEY_CLASS_ROOT\CLSID\\ProgId key. // using (RegistryKey ProgIdKey = ClsIdKey.OpenSubKey("ProgId", true)) { if (ProgIdKey != null) { // Delete the value we created. ProgIdKey.DeleteValue("",false); // If there are no other values or subkeys then we can delete the ProgIdSubKey. if ((ProgIdKey.SubKeyCount == 0) && (ProgIdKey.ValueCount == 0)) ClsIdKey.DeleteSubKey("ProgId"); } } } // // Remove entries in the HKEY_CLASS_ROOT\CLSID\\Implemented Categories\ key. // using (RegistryKey CategoryKey = ClsIdKey.OpenSubKey(strImplementedCategoriesSubKey, true)) { if (CategoryKey != null) { using (RegistryKey ManagedCategoryKey = CategoryKey.OpenSubKey(strManagedCategoryGuid, true)) { if (ManagedCategoryKey != null) { // If there are no other values or subkeys then we can delete the ManagedCategoryKey. if ((ManagedCategoryKey.SubKeyCount == 0) && (ManagedCategoryKey.ValueCount == 0)) CategoryKey.DeleteSubKey(strManagedCategoryGuid); } } // If there are no other values or subkeys then we can delete the CategoryKey. if ((CategoryKey.SubKeyCount == 0) && (CategoryKey.ValueCount == 0)) ClsIdKey.DeleteSubKey(strImplementedCategoriesSubKey); } } } // If there are no other values or subkeys then we can delete the ClsIdKey. if ((ClsIdKey.SubKeyCount == 0) && (ClsIdKey.ValueCount == 0)) ClsIdRootKey.DeleteSubKey(strClsId); } } // If there are no other values or subkeys then we can delete the CLSID key. if ((ClsIdRootKey.SubKeyCount == 0) && (ClsIdRootKey.ValueCount == 0)) Registry.ClassesRoot.DeleteSubKey(strClsIdRootName); } // // Remove the entries under HKEY_CLASS_ROOT\ key. // if (bAllVersionsGone) { if (strProgId != String.Empty) { using (RegistryKey TypeNameKey = Registry.ClassesRoot.OpenSubKey(strProgId, true)) { if (TypeNameKey != null) { // Delete the values we created. TypeNameKey.DeleteValue("",false); // // Remove the entries in the HKEY_CLASS_ROOT\\CLSID key. // using (RegistryKey ProgIdClsIdKey = TypeNameKey.OpenSubKey("CLSID", true)) { if (ProgIdClsIdKey != null) { // Delete the values we created. ProgIdClsIdKey.DeleteValue("",false); // If there are no other values or subkeys then we can delete the ProgIdClsIdKey. if ((ProgIdClsIdKey.SubKeyCount == 0) && (ProgIdClsIdKey.ValueCount == 0)) TypeNameKey.DeleteSubKey("CLSID"); } } // If there are no other values or subkeys then we can delete the TypeNameKey. if ((TypeNameKey.SubKeyCount == 0) && (TypeNameKey.ValueCount == 0)) Registry.ClassesRoot.DeleteSubKey(strProgId); } } } } } return bAllVersionsGone; } // UnregisterComImportedType // Return: // true: All version information are gone. // false: There are still some version left in registry [System.Security.SecurityCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] private bool UnregisterComImportedType(Type type, String strAsmVersion) { bool bAllVersionsGone = true; String strClsId = "{" + Marshal.GenerateGuidForType(type).ToString().ToUpper(CultureInfo.InvariantCulture) + "}"; // Try to open the HKEY_CLASS_ROOT\CLSID key. using (RegistryKey ClsIdRootKey = Registry.ClassesRoot.OpenSubKey(strClsIdRootName, true)) { if (ClsIdRootKey != null) { // Try to open the HKEY_CLASS_ROOT\CLSID\ key. using (RegistryKey ClsIdKey = ClsIdRootKey.OpenSubKey(strClsId, true)) { if (ClsIdKey != null) { // Try to open the HKEY_CLASS_ROOT\CLSID\\InProcServer32 key. using (RegistryKey InProcServerKey = ClsIdKey.OpenSubKey("InprocServer32", true)) { if (InProcServerKey != null) { // Delete the values we created. InProcServerKey.DeleteValue("Assembly",false); InProcServerKey.DeleteValue("Class",false); InProcServerKey.DeleteValue("RuntimeVersion",false); InProcServerKey.DeleteValue("CodeBase",false); // Try to open the entries in HKEY_CLASS_ROOT\CLSID\\InProcServer32\ using (RegistryKey VersionSubKey = InProcServerKey.OpenSubKey(strAsmVersion,true)) { if (VersionSubKey != null) { // Delete the value we created VersionSubKey.DeleteValue("Assembly",false); VersionSubKey.DeleteValue("Class",false); VersionSubKey.DeleteValue("RuntimeVersion",false); VersionSubKey.DeleteValue("CodeBase",false); // If there are no other values or subkeys then we can delete the VersionSubKey if ((VersionSubKey.SubKeyCount == 0) && (VersionSubKey.ValueCount == 0)) InProcServerKey.DeleteSubKey(strAsmVersion); } } // If there are sub keys left then there are versions left. if (InProcServerKey.SubKeyCount != 0) bAllVersionsGone = false; // If there are no other values or subkeys then we can delete the InProcServerKey. if ((InProcServerKey.SubKeyCount == 0) && (InProcServerKey.ValueCount == 0)) ClsIdKey.DeleteSubKey("InprocServer32"); } } // If there are no other values or subkeys then we can delete the ClsIdKey. if ((ClsIdKey.SubKeyCount == 0) && (ClsIdKey.ValueCount == 0)) ClsIdRootKey.DeleteSubKey(strClsId); } } // If there are no other values or subkeys then we can delete the CLSID key. if ((ClsIdRootKey.SubKeyCount == 0) && (ClsIdRootKey.ValueCount == 0)) Registry.ClassesRoot.DeleteSubKey(strClsIdRootName); } } return bAllVersionsGone; } [System.Security.SecurityCritical] // auto-generated [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] private void RegisterPrimaryInteropAssembly(RuntimeAssembly assembly, String strAsmCodeBase, PrimaryInteropAssemblyAttribute attr) { // Validate that the PIA has a strong name. if (assembly.GetPublicKey().Length == 0) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_PIAMustBeStrongNamed")); String strTlbId = "{" + Marshal.GetTypeLibGuidForAssembly(assembly).ToString().ToUpper(CultureInfo.InvariantCulture) + "}"; String strVersion = attr.MajorVersion.ToString("x", CultureInfo.InvariantCulture) + "." + attr.MinorVersion.ToString("x", CultureInfo.InvariantCulture); // Create the HKEY_CLASS_ROOT\TypeLib key. using (RegistryKey TypeLibRootKey = Registry.ClassesRoot.CreateSubKey(strTlbRootName)) { // Create the HKEY_CLASS_ROOT\TypeLib\ key. using (RegistryKey TypeLibKey = TypeLibRootKey.CreateSubKey(strTlbId)) { // Create the HKEY_CLASS_ROOT\TypeLib\\ key. using (RegistryKey VersionSubKey = TypeLibKey.CreateSubKey(strVersion)) { // Create the HKEY_CLASS_ROOT\TypeLib\\PrimaryInteropAssembly key. VersionSubKey.SetValue("PrimaryInteropAssemblyName", assembly.FullName); if (strAsmCodeBase != null) VersionSubKey.SetValue("PrimaryInteropAssemblyCodeBase", strAsmCodeBase); } } } } [System.Security.SecurityCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] private void UnregisterPrimaryInteropAssembly(Assembly assembly, PrimaryInteropAssemblyAttribute attr) { String strTlbId = "{" + Marshal.GetTypeLibGuidForAssembly(assembly).ToString().ToUpper(CultureInfo.InvariantCulture) + "}"; String strVersion = attr.MajorVersion.ToString("x", CultureInfo.InvariantCulture) + "." + attr.MinorVersion.ToString("x", CultureInfo.InvariantCulture); // Try to open the HKEY_CLASS_ROOT\TypeLib key. using (RegistryKey TypeLibRootKey = Registry.ClassesRoot.OpenSubKey(strTlbRootName, true)) { if (TypeLibRootKey != null) { // Try to open the HKEY_CLASS_ROOT\TypeLib\ key. using (RegistryKey TypeLibKey = TypeLibRootKey.OpenSubKey(strTlbId, true)) { if (TypeLibKey != null) { // Try to open the HKEY_CLASS_ROOT\TypeLib\ key. using (RegistryKey VersionSubKey = TypeLibKey.OpenSubKey(strVersion, true)) { if (VersionSubKey != null) { // Delete the values we created. VersionSubKey.DeleteValue("PrimaryInteropAssemblyName",false); VersionSubKey.DeleteValue("PrimaryInteropAssemblyCodeBase",false); // If there are no other values or subkeys then we can delete the VersionKey. if ((VersionSubKey.SubKeyCount == 0) && (VersionSubKey.ValueCount == 0)) TypeLibKey.DeleteSubKey(strVersion); } } // If there are no other values or subkeys then we can delete the TypeLibKey. if ((TypeLibKey.SubKeyCount == 0) && (TypeLibKey.ValueCount == 0)) TypeLibRootKey.DeleteSubKey(strTlbId); } } // If there are no other values or subkeys then we can delete the TypeLib key. if ((TypeLibRootKey.SubKeyCount == 0) && (TypeLibRootKey.ValueCount == 0)) Registry.ClassesRoot.DeleteSubKey(strTlbRootName); } } } [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] private void EnsureManagedCategoryExists() { if (!ManagedCategoryExists()) { // Create the HKEY_CLASS_ROOT\Component Category key. using (RegistryKey ComponentCategoryKey = Registry.ClassesRoot.CreateSubKey(strComponentCategorySubKey)) { // Create the HKEY_CLASS_ROOT\Component Category\ key. using (RegistryKey ManagedCategoryKey = ComponentCategoryKey.CreateSubKey(strManagedCategoryGuid)) { ManagedCategoryKey.SetValue("0", strManagedCategoryDescription); } } } } [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] private static bool ManagedCategoryExists() { using (RegistryKey componentCategoryKey = Registry.ClassesRoot.OpenSubKey(strComponentCategorySubKey, #if FEATURE_MACL RegistryKeyPermissionCheck.ReadSubTree)) #else false)) #endif { if (componentCategoryKey == null) return false; using (RegistryKey managedCategoryKey = componentCategoryKey.OpenSubKey(strManagedCategoryGuid, #if FEATURE_MACL RegistryKeyPermissionCheck.ReadSubTree)) #else false)) #endif { if (managedCategoryKey == null) return false; object value = managedCategoryKey.GetValue("0"); if (value == null || value.GetType() != typeof(string)) return false; string stringValue = (string)value; if (stringValue != strManagedCategoryDescription) return false; } } return true; } [System.Security.SecurityCritical] // auto-generated private void CallUserDefinedRegistrationMethod(Type type, bool bRegister) { bool bFunctionCalled = false; // Retrieve the attribute type to use to determine if a function is the requested user defined // registration function. Type RegFuncAttrType = null; if(bRegister) RegFuncAttrType = typeof(ComRegisterFunctionAttribute); else RegFuncAttrType = typeof(ComUnregisterFunctionAttribute); for(Type currType = type; !bFunctionCalled && currType != null; currType = currType.BaseType) { // Retrieve all the methods. MethodInfo[] aMethods = currType.GetMethods(BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static); int NumMethods = aMethods.Length; // Go through all the methods and check for the ComRegisterMethod custom attribute. for(int cMethods = 0;cMethods < NumMethods;cMethods++) { MethodInfo CurrentMethod = aMethods[cMethods]; // Check to see if the method has the custom attribute. if(CurrentMethod.GetCustomAttributes(RegFuncAttrType, true).Length != 0) { // Check to see if the method is static before we call it. if(!CurrentMethod.IsStatic) { if(bRegister) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NonStaticComRegFunction",CurrentMethod.Name,currType.Name)); else throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NonStaticComUnRegFunction",CurrentMethod.Name,currType.Name)); } // Finally check that the signature is string ret void. ParameterInfo[] aParams = CurrentMethod.GetParameters(); if (CurrentMethod.ReturnType != typeof(void) || aParams == null || aParams.Length != 1 || (aParams[0].ParameterType != typeof(String) && aParams[0].ParameterType != typeof(Type))) { if(bRegister) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_InvalidComRegFunctionSig",CurrentMethod.Name,currType.Name)); else throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_InvalidComUnRegFunctionSig",CurrentMethod.Name,currType.Name)); } // There can only be one register and one unregister function per type. if(bFunctionCalled) { if(bRegister) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_MultipleComRegFunctions",currType.Name)); else throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_MultipleComUnRegFunctions",currType.Name)); } // The function is valid so set up the arguments to call it. Object[] objs = new Object[1]; if(aParams[0].ParameterType == typeof(String)) { // We are dealing with the string overload of the function. objs[0] = "HKEY_CLASSES_ROOT\\CLSID\\{" + Marshal.GenerateGuidForType(type).ToString().ToUpper(CultureInfo.InvariantCulture) + "}"; } else { // We are dealing with the type overload of the function. objs[0] = type; } // Invoke the COM register function. CurrentMethod.Invoke(null, objs); // Mark the function as having been called. bFunctionCalled = true; } } } } private Type GetBaseComImportType(Type type) { for (; type != null && !type.IsImport; type = type.BaseType); return type; } private bool IsRegisteredAsValueType(Type type) { if (!type.IsValueType) return false; return true; } #endregion #region FCalls and DllImports #if FEATURE_COMINTEROP_MANAGED_ACTIVATION // GUID versioning can be controlled by using the GuidAttribute or // letting the runtime generate it based on type and assembly strong name. [System.Security.SecurityCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern void RegisterTypeForComClientsNative(Type type,ref Guid g); // GUID versioning can be controlled by using the GuidAttribute or // letting the runtime generate it based on type and assembly strong name. [System.Security.SecurityCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern int RegisterTypeForComClientsExNative(Type t, RegistrationClassContext clsContext, RegistrationConnectionType flags); #endif // FEATURE_COMINTEROP_MANAGED_ACTIVATION [DllImport(Win32Native.OLE32,CharSet=CharSet.Auto,PreserveSig=false)] [ResourceExposure(ResourceScope.None)] private static extern void CoRevokeClassObject(int cookie); #endregion } }