RegistrationServices.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / clr / src / BCL / System / Runtime / InteropServices / RegistrationServices.cs / 1 / RegistrationServices.cs

                            // ==++== 
//
//   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;
 
    [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

        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        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"));
 
            // 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 = assembly.nGetCodeBase(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 = assembly.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(assembly, strAsmCodeBase, (PrimaryInteropAssemblyAttribute)aPIAAttrs[cPIAAttrs]);

            // Return value indicating if we actually registered any types.
            if (aTypes.Length > 0 || NumPIAAttrs > 0) 
                return true;
            else 
                return false; 
        }
 
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        public virtual bool UnregisterAssembly(Assembly assembly)
        {
            bool bAllVersionsGone = true; 

            // Validate the arguments. 
            if (assembly == null) 
                throw new ArgumentNullException("assembly");
 
            if (assembly.ReflectionOnly)
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AsmLoadedForReflectionOnly"));

            // 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 = assembly.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;
        } 

        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        public virtual Type[] GetRegistrableTypesInAssembly(Assembly assembly)
        { 
            // Validate the arguments.
            if (assembly == null) 
                throw new ArgumentNullException("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; 
        }

        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        public virtual String GetProgIdForType(Type type) 
        {
            return Marshal.GenerateProgIdForType(type); 
        } 

        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        public virtual void RegisterTypeForComClients(Type type, ref Guid g)
        {
            if(type == null)
                throw new ArgumentNullException("type"); 
            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);
        }
 
        public virtual Guid GetManagedCategoryGuid()
        { 
            return s_ManagedCategoryGuid; 
        }
 
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        public virtual bool TypeRequiresRegistration(Type type)
        {
            return TypeRequiresRegistrationHelper(type); 
        }
 
        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);
            BCLDebug.Assert(baseComImportType != null, "baseComImportType != null");
            if (Marshal.GenerateGuidForType(type) == Marshal.GenerateGuidForType(baseComImportType))
                return true; 

            return false; 
        } 

        #endregion 


        #region Public methods not on IRegistrationServices
        [ComVisible(false)] 
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        public virtual int RegisterTypeForComClients(Type type, RegistrationClassContext classContext, RegistrationConnectionType flags) 
        { 
            if (type == null)
                throw new ArgumentNullException("type"); 
            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); 
        }
 
        [ComVisible(false)]
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        public virtual void UnregisterTypeForComClients(int cookie)
        { 
            // Call the native method to do CoRevokeClassObject.
            CoRevokeClassObject(cookie); 
        } 

        #endregion 


        #region Internal helpers
 
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        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

        [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);
                    } 
                }
            } 
        } 

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

        [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); 
                        } 
                    }
                } 
            }
        }

        [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)
                        {
                            // Delete the values we created. 
                            RecordKey.DeleteValue("Assembly",false);
                            RecordKey.DeleteValue("Class",false); 
                            RecordKey.DeleteValue("CodeBase",false); 

                            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); 

                                    // 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
        [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
        [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;
        } 
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        private void RegisterPrimaryInteropAssembly(Assembly assembly, String strAsmCodeBase, PrimaryInteropAssemblyAttribute attr)
        {
            // Validate that the PIA has a strong name.
            if (assembly.nGetPublicKey().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); 
                    }
                } 
            } 
        }
 
        [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()
        { 
            // 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);
                }
            } 
        }
 
        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(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("InvalidOperation_NonStaticComRegFunction"),CurrentMethod.Name,currType.Name));
                            else
                                throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, 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(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("InvalidOperation_InvalidComRegFunctionSig"),CurrentMethod.Name,currType.Name));
                            else 
                                throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, 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(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("InvalidOperation_MultipleComRegFunctions"),currType.Name));
                            else 
                                throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, 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
 
        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        private static extern void RegisterTypeForComClientsNative(Type type,ref Guid g);
 
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        private static extern int RegisterTypeForComClientsExNative(Type t, RegistrationClassContext clsContext, RegistrationConnectionType flags);

        [DllImport(Win32Native.OLE32,CharSet=CharSet.Auto,PreserveSig=false)] 
        private static extern void CoRevokeClassObject(int cookie);
        #endregion 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++== 
//
//   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;
 
    [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

        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        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"));
 
            // 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 = assembly.nGetCodeBase(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 = assembly.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(assembly, strAsmCodeBase, (PrimaryInteropAssemblyAttribute)aPIAAttrs[cPIAAttrs]);

            // Return value indicating if we actually registered any types.
            if (aTypes.Length > 0 || NumPIAAttrs > 0) 
                return true;
            else 
                return false; 
        }
 
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        public virtual bool UnregisterAssembly(Assembly assembly)
        {
            bool bAllVersionsGone = true; 

            // Validate the arguments. 
            if (assembly == null) 
                throw new ArgumentNullException("assembly");
 
            if (assembly.ReflectionOnly)
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AsmLoadedForReflectionOnly"));

            // 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 = assembly.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;
        } 

        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        public virtual Type[] GetRegistrableTypesInAssembly(Assembly assembly)
        { 
            // Validate the arguments.
            if (assembly == null) 
                throw new ArgumentNullException("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; 
        }

        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        public virtual String GetProgIdForType(Type type) 
        {
            return Marshal.GenerateProgIdForType(type); 
        } 

        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        public virtual void RegisterTypeForComClients(Type type, ref Guid g)
        {
            if(type == null)
                throw new ArgumentNullException("type"); 
            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);
        }
 
        public virtual Guid GetManagedCategoryGuid()
        { 
            return s_ManagedCategoryGuid; 
        }
 
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        public virtual bool TypeRequiresRegistration(Type type)
        {
            return TypeRequiresRegistrationHelper(type); 
        }
 
        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);
            BCLDebug.Assert(baseComImportType != null, "baseComImportType != null");
            if (Marshal.GenerateGuidForType(type) == Marshal.GenerateGuidForType(baseComImportType))
                return true; 

            return false; 
        } 

        #endregion 


        #region Public methods not on IRegistrationServices
        [ComVisible(false)] 
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        public virtual int RegisterTypeForComClients(Type type, RegistrationClassContext classContext, RegistrationConnectionType flags) 
        { 
            if (type == null)
                throw new ArgumentNullException("type"); 
            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); 
        }
 
        [ComVisible(false)]
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        public virtual void UnregisterTypeForComClients(int cookie)
        { 
            // Call the native method to do CoRevokeClassObject.
            CoRevokeClassObject(cookie); 
        } 

        #endregion 


        #region Internal helpers
 
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        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

        [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);
                    } 
                }
            } 
        } 

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

        [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); 
                        } 
                    }
                } 
            }
        }

        [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)
                        {
                            // Delete the values we created. 
                            RecordKey.DeleteValue("Assembly",false);
                            RecordKey.DeleteValue("Class",false); 
                            RecordKey.DeleteValue("CodeBase",false); 

                            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); 

                                    // 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
        [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
        [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;
        } 
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        private void RegisterPrimaryInteropAssembly(Assembly assembly, String strAsmCodeBase, PrimaryInteropAssemblyAttribute attr)
        {
            // Validate that the PIA has a strong name.
            if (assembly.nGetPublicKey().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); 
                    }
                } 
            } 
        }
 
        [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()
        { 
            // 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);
                }
            } 
        }
 
        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(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("InvalidOperation_NonStaticComRegFunction"),CurrentMethod.Name,currType.Name));
                            else
                                throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, 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(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("InvalidOperation_InvalidComRegFunctionSig"),CurrentMethod.Name,currType.Name));
                            else 
                                throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, 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(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("InvalidOperation_MultipleComRegFunctions"),currType.Name));
                            else 
                                throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, 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
 
        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        private static extern void RegisterTypeForComClientsNative(Type type,ref Guid g);
 
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        private static extern int RegisterTypeForComClientsExNative(Type t, RegistrationClassContext clsContext, RegistrationConnectionType flags);

        [DllImport(Win32Native.OLE32,CharSet=CharSet.Auto,PreserveSig=false)] 
        private static extern void CoRevokeClassObject(int cookie);
        #endregion 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK