summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Runtime/InteropServices/RegistrationServices.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/Runtime/InteropServices/RegistrationServices.cs')
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/RegistrationServices.cs1086
1 files changed, 1086 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/RegistrationServices.cs b/src/mscorlib/src/System/Runtime/InteropServices/RegistrationServices.cs
new file mode 100644
index 0000000000..6b83e92057
--- /dev/null
+++ b/src/mscorlib/src/System/Runtime/InteropServices/RegistrationServices.cs
@@ -0,0 +1,1086 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+/*=============================================================================
+**
+**
+**
+** 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
+ 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
+ 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\<RecordID> key.
+ using (RegistryKey RecordKey = RecordRootKey.CreateSubKey(strRecordId))
+ {
+ // Create the HKEY_CLASS_ROOT\Record\<RecordId>\<version> 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
+ 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\<wzProgId> key.
+ using (RegistryKey TypeNameKey = Registry.ClassesRoot.CreateSubKey(strProgId))
+ {
+ TypeNameKey.SetValue("", strDocString);
+
+ // Create the HKEY_CLASS_ROOT\<wzProgId>\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\<CLSID> key.
+ using (RegistryKey ClsIdKey = ClsIdRootKey.CreateSubKey(strClsId))
+ {
+ ClsIdKey.SetValue("", strDocString);
+
+ // Create the HKEY_CLASS_ROOT\CLSID\<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\<CLSID>\InprocServer32\<Version> 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\<CLSID>\ProdId key.
+ using (RegistryKey ProgIdKey = ClsIdKey.CreateSubKey("ProgId"))
+ {
+ ProgIdKey.SetValue("", strProgId);
+ }
+ }
+ }
+
+ // Create the HKEY_CLASS_ROOT\CLSID\<CLSID>\Implemented Categories\<Managed Category Guid> 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
+ 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\<CLSID> key.
+ using (RegistryKey ClsIdKey = ClsIdRootKey.CreateSubKey(strClsId))
+ {
+ // Create the HKEY_CLASS_ROOT\CLSID\<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\<CLSID>\InprocServer32\<Version> 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
+ 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
+ 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\<CLSID> key.
+ //
+
+ using (RegistryKey ClsIdKey = ClsIdRootKey.OpenSubKey(strClsId, true))
+ {
+ if (ClsIdKey != null)
+ {
+ //
+ // Remove the entries in the HKEY_CLASS_ROOT\CLSID\<CLSID>\InprocServer32 key.
+ //
+
+ using (RegistryKey InProcServerKey = ClsIdKey.OpenSubKey("InprocServer32", true))
+ {
+ if (InProcServerKey != null)
+ {
+ //
+ // Remove the entries in HKEY_CLASS_ROOT\CLSID\<CLSID>\InprocServer32\<Version>
+ //
+
+ 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\<CLSID>\ProgId
+ // and HKEY_CLASS_ROOT\CLSID\<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\<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\<CLSID>\Implemented Categories\<Managed Category Guid> 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\<wzProgId> 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\<wzProgId>\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
+ 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\<CLSID> key.
+ using (RegistryKey ClsIdKey = ClsIdRootKey.OpenSubKey(strClsId, true))
+ {
+ if (ClsIdKey != null)
+ {
+ // Try to open the HKEY_CLASS_ROOT\CLSID\<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\<CLSID>\InProcServer32\<Version>
+ 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
+ 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\<TLBID> key.
+ using (RegistryKey TypeLibKey = TypeLibRootKey.CreateSubKey(strTlbId))
+ {
+ // Create the HKEY_CLASS_ROOT\TypeLib\<TLBID>\<Major.Minor> key.
+ using (RegistryKey VersionSubKey = TypeLibKey.CreateSubKey(strVersion))
+ {
+ // Create the HKEY_CLASS_ROOT\TypeLib\<TLBID>\PrimaryInteropAssembly key.
+ VersionSubKey.SetValue("PrimaryInteropAssemblyName", assembly.FullName);
+ if (strAsmCodeBase != null)
+ VersionSubKey.SetValue("PrimaryInteropAssemblyCodeBase", strAsmCodeBase);
+ }
+ }
+ }
+ }
+
+ [System.Security.SecurityCritical] // auto-generated
+ 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\<TLBID> key.
+ using (RegistryKey TypeLibKey = TypeLibRootKey.OpenSubKey(strTlbId, true))
+ {
+ if (TypeLibKey != null)
+ {
+ // Try to open the HKEY_CLASS_ROOT\TypeLib<TLBID>\<Major.Minor> 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);
+ }
+ }
+ }
+
+ 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\<Managed Category Guid> key.
+ using (RegistryKey ManagedCategoryKey = ComponentCategoryKey.CreateSubKey(strManagedCategoryGuid))
+ {
+ ManagedCategoryKey.SetValue("0", strManagedCategoryDescription);
+ }
+ }
+ }
+ }
+
+ 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
+ [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
+ [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)]
+ private static extern void CoRevokeClassObject(int cookie);
+ #endregion
+ }
+}