Beispiel #1
0
        /// <summary>
        /// Writes the entries needed to register a COM-imported type (e.g. a type
        /// with the <see cref="System.Runtime.InteropServices.ComImportAttribute"/>)
        /// to the registry file.
        /// </summary>
        /// <param name="type">Type to write.</param>
        /// <param name="codebase">Optional codebase, if it needs to be written.</param>
        /// <param name="rootKeyName">Name of root key where to add types.</param>
        /// <param name="writer"><see cref="RegistryFileWriter"/> used to write to the
        /// registry file.</param>
        private void WriteComImportInRegistryFile(Type type, string codebase,
                                                  string rootKeyName, RegistryFileWriter writer)
        {
            Debug.Assert(type != null);
            Debug.Assert(!String.IsNullOrEmpty(rootKeyName));
            Debug.Assert(writer != null);

            // For COM imports, we write the CLSID, but no ProgID.
            string keyPath = String.Format(@"{0}\CLSID\{1}\InprocServer32", rootKeyName,
                                           type.GUID.ToString("B").ToUpper(CultureInfo.InvariantCulture));

            using (RegistryKeyWriter keyWriter = writer.AddKey(keyPath)) {
                keyWriter.AddValue("Class", type.FullName);
                keyWriter.AddValue("Assembly", assembly.FullName);
                keyWriter.AddValue("RuntimeVersion", assembly.ImageRuntimeVersion);
                if (!String.IsNullOrEmpty(codebase))
                {
                    keyWriter.AddValue("CodeBase", codebase);
                }
            }
            // Also write versioned key.
            keyPath += String.Format(@"\{0}", assembly.GetName().Version);
            using (RegistryKeyWriter keyWriter = writer.AddKey(keyPath)) {
                keyWriter.AddValue("Class", type.FullName);
                keyWriter.AddValue("Assembly", assembly.FullName);
                keyWriter.AddValue("RuntimeVersion", assembly.ImageRuntimeVersion);
                if (!String.IsNullOrEmpty(codebase))
                {
                    keyWriter.AddValue("CodeBase", codebase);
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Writes the entries needed to register a value type (e.g. structs) to
        /// the registry file.
        /// </summary>
        /// <param name="type">Type to write.</param>
        /// <param name="codebase">Optional codebase, if it needs to be written.</param>
        /// <param name="rootKeyName">Name of root key where to add types.</param>
        /// <param name="writer"><see cref="RegistryKeyWriter"/> used to write
        /// to the registry file.</param>
        private void WriteValueTypeInRegistryFile(Type type, string codebase,
                                                  string rootKeyName, RegistryFileWriter writer)
        {
            Debug.Assert(type != null);
            Debug.Assert(!String.IsNullOrEmpty(rootKeyName));
            Debug.Assert(writer != null);

            // Value types are written to the Classes\Record key, using the type's GUID and its version.
            string keyPath = String.Format(@"{0}\Record\{1}\{2}", rootKeyName,
                                           type.GUID.ToString("B").ToUpper(CultureInfo.InvariantCulture), assembly.GetName().Version);

            using (RegistryKeyWriter keyWriter = writer.AddKey(keyPath)) {
                keyWriter.AddValue("Class", type.FullName);
                keyWriter.AddValue("Assembly", assembly.FullName);
                keyWriter.AddValue("RuntimeVersion", assembly.ImageRuntimeVersion);
                if (!String.IsNullOrEmpty(codebase))
                {
                    keyWriter.AddValue("CodeBase", codebase);
                }
            }
        }
Beispiel #3
0
        /// <summary>
        /// Writes the entries needed to register our assembly as a primary
        /// interop assembly to the registry file.
        /// </summary>
        /// <param name="attrib"><see cref="System.Reflection.CustomAttributeData"/>
        /// for the assembly's <see cref="System.Runtime.InteropServices.PrimaryInteropAssemblyAttribute"/>.</param>
        /// <param name="codebase">Optional codebase, if it needs to be written.</param>
        /// <param name="rootKeyName">Name of root key where to add types.</param>
        /// <param name="writer"><see cref="RegistryFileWriter"/> used to write to the
        /// registry file.</param>
        /// <seealso cref="System.Runtime.InteropServices.PrimaryInteropAssemblyAttribute"/>
        private void WritePrimaryInteropAssemblyInRegistryFile(CustomAttributeData attrib,
                                                               string codebase, string rootKeyName, RegistryFileWriter writer)
        {
            Debug.Assert(attrib != null);
            Debug.Assert(!String.IsNullOrEmpty(rootKeyName));
            Debug.Assert(writer != null);

            // For this, we add data to the Classes\TypeLib key, using TypeLib ID and version,
            // pulled from the PrimaryInteropAssemblyAttribute (and inexplicably expressed as hexadecimal values).
            string keyPath = String.Format(@"{0}\TypeLib\{1}\{2}.{3}", rootKeyName,
                                           Marshal.GetTypeLibGuidForAssembly(assembly).ToString("B").ToUpper(CultureInfo.InvariantCulture),
                                           ((int)attrib.ConstructorArguments[0].Value).ToString("x", CultureInfo.InvariantCulture),
                                           ((int)attrib.ConstructorArguments[1].Value).ToString("x", CultureInfo.InvariantCulture));

            using (RegistryKeyWriter keyWriter = writer.AddKey(keyPath)) {
                keyWriter.AddValue("PrimaryInteropAssemblyName", assembly.FullName);
                if (!String.IsNullOrEmpty(codebase))
                {
                    keyWriter.AddValue("PrimaryInteropAssemblyCodeBase", codebase);
                }
            }
        }
Beispiel #4
0
        /// <summary>
        /// Writes the entries needed to register a class type to the registry file.
        /// </summary>
        /// <param name="type">Type to write.</param>
        /// <param name="codebase">Optional codebase, if it needs to be written.</param>
        /// <param name="rootKeyName">Name of root key where to add types.</param>
        /// <param name="writer"><see cref="RegistryFileWriter"/> used to write to the
        /// registry file.</param>
        private void WriteClassInRegistryFile(Type type, string codebase,
                                              string rootKeyName, RegistryFileWriter writer)
        {
            Debug.Assert(type != null);
            Debug.Assert(!String.IsNullOrEmpty(rootKeyName));
            Debug.Assert(writer != null);

            // For class types, we add ProgID entries AND CLSID entries.
            string clsid  = type.GUID.ToString("B").ToUpper(CultureInfo.InvariantCulture);
            string progId = regServices.GetProgIdForType(type);
            string keyPath;

            // First ProgID if class has one. Link it to CLSID.
            if (!String.IsNullOrEmpty(progId))
            {
                keyPath = String.Format(@"{0}\{1}", rootKeyName, progId);
                using (RegistryKeyWriter keyWriter = writer.AddKey(keyPath)) {
                    keyWriter.AddDefaultValue(type.FullName);
                }
                keyPath += @"\CLSID";
                using (RegistryKeyWriter keyWriter = writer.AddKey(keyPath)) {
                    keyWriter.AddDefaultValue(clsid);
                }
            }

            // Now CLSID. First write class name in root CLSID key.
            keyPath = String.Format(@"{0}\CLSID\{1}", rootKeyName, clsid);
            using (RegistryKeyWriter keyWriter = writer.AddKey(keyPath)) {
                keyWriter.AddDefaultValue(type.FullName);
            }

            // Now write all infos in InprocServer32.
            keyPath += @"\InprocServer32";
            using (RegistryKeyWriter keyWriter = writer.AddKey(keyPath)) {
                keyWriter.AddDefaultValue("mscoree.dll");
                keyWriter.AddValue("ThreadingModel", "Both");
                keyWriter.AddValue("Class", type.FullName);
                keyWriter.AddValue("Assembly", assembly.FullName);
                keyWriter.AddValue("RuntimeVersion", assembly.ImageRuntimeVersion);
                if (codebase != null)
                {
                    keyWriter.AddValue("CodeBase", codebase);
                }
            }

            // Also write versioned key.
            keyPath += String.Format(@"\{0}", assembly.GetName().Version);
            using (RegistryKeyWriter keyWriter = writer.AddKey(keyPath)) {
                keyWriter.AddValue("Class", type.FullName);
                keyWriter.AddValue("Assembly", assembly.FullName);
                keyWriter.AddValue("RuntimeVersion", assembly.ImageRuntimeVersion);
                if (codebase != null)
                {
                    keyWriter.AddValue("CodeBase", codebase);
                }
            }

            // If class has a ProgID, link the CLSID to it.
            if (!String.IsNullOrEmpty(progId))
            {
                keyPath = String.Format(@"{0}\CLSID\{1}\ProgId", rootKeyName, clsid);
                using (RegistryKeyWriter keyWriter = writer.AddKey(keyPath)) {
                    keyWriter.AddDefaultValue(progId);
                }
            }

            // Finally, add implemented categories.
            keyPath = String.Format(@"{0}\CLSID\{1}\Implemented Categories\{2}", rootKeyName, clsid,
                                    regServices.GetManagedCategoryGuid().ToString("B").ToUpper(CultureInfo.InvariantCulture));
            writer.AddEmptyKey(keyPath);
        }
Beispiel #5
0
        /// <summary>
        /// Generates the registry file (.reg) asked for by the user via the
        /// <c>/regfile</c> command-line option.
        /// </summary>
        /// <returns>Exit code to return from the CLRegAsm tool.</returns>
        /// <exception cref="CoreException">User asked for codebase but provided assembly
        /// has no codebase.</exception>
        private int GenerateRegistryFile()
        {
            // This will be changed if an error occurs
            int exitCode = 0;

            // Get list of registrable types in the assembly.
            Type[] registrableTypes = regServices.GetRegistrableTypesInAssembly(assembly);

            // Check if assembly is a primary interop assembly.
            IList <CustomAttributeData> attribs = CustomAttributeData.GetCustomAttributes(assembly);
            bool assemblyIsPrimaryInterop       = false;

            foreach (CustomAttributeData attrib in attribs)
            {
                if (attrib.Constructor.DeclaringType == typeof(PrimaryInteropAssemblyAttribute))
                {
                    assemblyIsPrimaryInterop = true;
                    break;
                }
            }

            if (registrableTypes.Length != 0 || assemblyIsPrimaryInterop)
            {
                // Get codebase if needed.
                string codebase = null;
                if (prms.setCodeBase)
                {
                    codebase = assembly.CodeBase;
                    if (String.IsNullOrEmpty(codebase))
                    {
                        throw new CoreException(String.Format("Assembly \"{0}\" has no codebase; " +
                                                              "cannot include codebase in registry file.", prms.assemblyName));
                    }
                }

                // Get root key name depending on whether this is per-user or per-machine.
                string rootKeyName;
                if (prms.perUser)
                {
                    rootKeyName = String.Format(@"{0}\Software\Classes", Registry.CurrentUser.Name);
                }
                else
                {
                    rootKeyName = Registry.ClassesRoot.Name;
                }

                // Create regfile writer.
                Debug.Assert(!String.IsNullOrEmpty(prms.registryFile));
                using (RegistryFileWriter writer = new RegistryFileWriter(prms.registryFile)) {
                    // Write each registrable type to the file.
                    foreach (Type type in registrableTypes)
                    {
                        if (type.IsValueType)
                        {
                            // Value type, like struct.
                            WriteValueTypeInRegistryFile(type, codebase, rootKeyName, writer);
                        }
                        else if (regServices.TypeRepresentsComType(type))
                        {
                            // Com-imported type.
                            WriteComImportInRegistryFile(type, codebase, rootKeyName, writer);
                        }
                        else
                        {
                            // Class type.
                            WriteClassInRegistryFile(type, codebase, rootKeyName, writer);
                        }
                    }

                    // Write primary interop assembly info.
                    foreach (CustomAttributeData attrib in attribs)
                    {
                        if (attrib.Constructor.DeclaringType == typeof(PrimaryInteropAssemblyAttribute))
                        {
                            WritePrimaryInteropAssemblyInRegistryFile(attrib, codebase, rootKeyName, writer);
                            break;
                        }
                    }
                }

                // We're done, tell the user.
                console.WriteLine("Registry file \"{0}\" generated successfully.", prms.registryFile);
            }
            else if (!prms.silent)
            {
                // No registrable types and assembly isn't a primary interop assembly; can't continue.
                console.Error.WriteLine("Assembly \"{0}\" has no registrable types and is not a " +
                                        "primary interop assembly: cannot generate registry file.", prms.assemblyName);
                exitCode = 500;
            }

            return(exitCode);
        }