Beispiel #1
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="console">Console to use to log events.
        /// Cannot be <c>null</c>.</param>
        /// <param name="prms"><see cref="Params"/> that determine how
        /// type libraries are exported from assemblies. Cannot be
        /// <c>null</c>. </param>
        /// <exception cref="ArgumentNullException"><paramref name="console"/>
        /// or <paramref name="prms"/> is <c>null</c>.</exception>
        public TypeLibHelper(CLConsole console, Params prms)
        {
            // Validate input.
            if (console == null)
            {
                throw new ArgumentNullException("console");
            }
            if (prms == null)
            {
                throw new ArgumentNullException("prms");
            }

            // Save reference to console.
            this.console = console;

            // Determine exporter flags.
            if (prms.useRegisteredOnly)
            {
                this.flags = TypeLibExporterFlags.OnlyReferenceRegistered;
            }
            else
            {
                this.flags = TypeLibExporterFlags.None;
            }
        }
Beispiel #2
0
        /// <summary>
        /// Displays a header describing the program and displaying copyright
        /// information.
        /// </summary>
        /// <param name="console"><see cref="CLConsole"/> to use to output.
        /// Cannot be <c>null</c>.</param>
        private static void ShowCopyright(CLConsole console)
        {
            Debug.Assert(console != null);

            console.WriteLine("CL's .NET Assembly Registration Tool, version {0} (.NET {1})",
                              GetThisAssemblyVersionAsString(), GetThisAssemblyRutimeVersion());
            console.WriteLine(GetThisAssemblyCopyrightInfo());
            console.WriteLine();
        }
Beispiel #3
0
        /// <summary>
        /// Displays usage information to the console.
        /// </summary>
        /// <param name="console"><see cref="CLConsole"/> to use to output.
        /// Cannot be <c>null</c>.</param>
        private static void ShowUsage(CLConsole console)
        {
            Debug.Assert(console != null);

            // The parser lib doesn't display a sample syntax, so display a little header to include one.
            console.WriteLine("Syntax: {0} <AssemblyName> [Options]",
                              Path.GetFileName(Assembly.GetExecutingAssembly().Location));

            // Now display the usage info returned by the parser.
            console.WriteLine("Options:");
            console.WriteLine(CommandLineArguments.Parser.ArgumentsUsage(typeof(Params)));
        }
Beispiel #4
0
        /// <summary>
        /// Runs the ClpArgAsm registration/unregistration tasks according to the
        /// given program arguments.
        /// </summary>
        /// <param name="args">Program arguments.</param>
        /// <returns>Program exit code. 0 if everything went well.</returns>
        public static int Run(string[] args)
        {
            // Assume everything will work.
            int exitCode = 0;

            // First parse pre-sandbox arguments to have access to parameters
            // needed before anything else.
            PreSandboxParams preSandboxPrms = new PreSandboxParams();

            CommandLineArguments.Parser.ParseArguments(args, preSandboxPrms, msg => { });

            // Create console to use in this method to output according to params.
            CLConsole console = new CLConsole(preSandboxPrms);

            // Show copyright information except if user told us not to.
            if (!preSandboxPrms.nologo)
            {
                ShowCopyright(console);
            }

            try {
                // Now parse all parameters and check if user wants help. If parameter issues
                // are encountered, they will be displayed here.
                Params prms        = new Params();
                bool   wantsHelp   = CommandLineArguments.Parser.ParseHelp(args);
                bool   validParams = CommandLineArguments.Parser.ParseArguments(args, prms);
                if (!wantsHelp && validParams)
                {
                    // Create a new AppDomain to perform registration/unregistration tasks,
                    // so that if something goes horribly wrong in the assembly we'll be loading,
                    // we won't be affected by it. Set the ApplicationBase to the current directory
                    // from where we've been invoked, since it might contain dependencies.
                    AppDomain domain = AppDomain.CreateDomain("CLRegAsm.Core", null,
                                                              new AppDomainSetup {
                        ApplicationBase = Environment.CurrentDirectory
                    });

                    // Create an instance of this class to execute in the new AppDomain.
                    Core sandboxedCore = (Core)domain.CreateInstanceFromAndUnwrap(
                        Assembly.GetExecutingAssembly().CodeBase, typeof(Core).FullName);
                    if (sandboxedCore == null)
                    {
                        throw new CoreException(String.Format("Type \"{0}\" not found when trying to " +
                                                              "create it in sandboxed AppDomain", typeof(Core).FullName));
                    }

                    // Execute in sandboxed AppDomain.
                    exitCode = sandboxedCore.RunSandboxed(args, prms);
                }
                else
                {
                    // Display usage information.
                    if (!validParams)
                    {
                        console.WriteLine();
                    }
                    ShowUsage(console);
                }
            } catch (Exception e) {
                // An error occured. Print it to stderr, then return
                // a non-zero error code to indicate the error.
                console.PrintException(e);
                exitCode = 1;
            }

            return(exitCode);
        }
Beispiel #5
0
        /// <summary>
        /// Runs the CLRegAsm registration/unregistration tasks in a sandboxed
        /// <see cref="AppDomain"/>. Called from <see cref="Core.Run(string[])"/>.
        /// </summary>
        /// <param name="sandboxedArgs">Raw program arguments. Use only to redirect to
        /// other executables; otherwise, use <paramref name="sandboxPrms"/></param>
        /// <param name="sandboxedPrms">Sandboxed <see cref="Params"/> object
        /// determining run parameters.</param>
        /// <returns>Exit code to return from the CLRegAsm tool.</returns>
        /// <exception cref="ArgumentNullException">Either <paramref name="sandboxedArgs"/>
        /// or <paramref name="sandboxedPrms"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException">Could not locate the assembly
        /// specified in <paramref name="sandboxPrms"/>.
        ///
        /// OR
        ///
        /// Registry file specified in <paramref name="sandboxPrms"/>
        /// overwrites the assembly file.
        ///
        /// OR
        ///
        /// Type library file specified in <paramref name="sandboxPrms"/>
        /// but assembly file has an embedded type library.
        ///
        /// OR
        ///
        /// Type library file specified in <paramref name="sandboxPrms"/>
        /// overwrites the assembly file.</exception>
        /// <exception cref="CoreException">The assembly specified in
        /// <paramref name="sandboxPrms"/> has an invalid format.
        /// (InnerException will then be a <see cref="BadImageFormatException"/>)
        ///
        /// OR
        ///
        /// The assembly specified in <paramref name="sandboxPrms"/>
        /// could not be found. (InnerException will then be a
        /// <see cref="FileNotFoundException"/>)
        ///
        /// OR
        ///
        /// Access was denied to the registry keys that need to be updated.
        /// (InnerException will then be a <see cref="UnauthorizedAccessException"/>)
        ///
        /// OR
        ///
        /// An exception was thrown from a user function in the assembly
        /// specified in <paramref name="sandboxPrms"/>. (InnerException will then
        /// be a <see cref="TargetInvocationException"/>)
        ///
        /// OR
        ///
        /// An exception was thrown in a static constructor in the assembly
        /// specified in <paramref name="sandboxPrms"/>. (InnerException will then
        /// be a <see cref="ReflectionTypeLoadException"/>)</exception>
        private int RunSandboxed(string[] sandboxedArgs, Params sandboxedPrms)
        {
            // This will be changed if an error occurs.
            int exitCode = 0;

            // Make sure params are valid and save them in instance variable.
            if (sandboxedArgs == null)
            {
                throw new ArgumentNullException("sandboxedArgs");
            }
            if (sandboxedPrms == null)
            {
                throw new ArgumentNullException("sandboxedPrms");
            }
            sandboxedPrms.Validate();
            prms = sandboxedPrms;

            // Create our console object to use for output.
            console = new CLConsole(prms);

            // Validate assembly path.
            string fullAssemblyPath = Path.GetFullPath(prms.assemblyName);

            if (File.Exists(fullAssemblyPath))
            {
                // Found the assembly easily, take a note of its absolute path.
                prms.assemblyName = fullAssemblyPath;
            }
            else
            {
                // Assembly not found - perhaps user specified a filename only.
                // Let's try to locate this in the current folder or on the PATH.
                StringBuilder buffer = new StringBuilder(MAX_PATH);
                if (SearchPath(null, prms.assemblyName, null, buffer.Capacity + 1, buffer, null) != 0)
                {
                    // Found the assembly by search, update params.
                    prms.assemblyName = buffer.ToString();
                }
                else
                {
                    // We really can't find the assembly; bail out.
                    throw new ArgumentException(String.Format("Could not locate assembly \"{0}\"",
                                                              prms.assemblyName), "assemblyName");
                }
            }
            // Also convert it to its full path.
            prms.assemblyName = new FileInfo(prms.assemblyName).FullName;

            // Compute path of regfile.
            if (prms.registryFile != null)
            {
                if (prms.registryFile.Length == 0)
                {
                    // Use assembly name, replacing extension with .reg.
                    prms.registryFile = Path.ChangeExtension(prms.assemblyName, ".reg");
                    Debug.Assert(Directory.Exists(Path.GetDirectoryName(prms.registryFile)));
                }
                else
                {
                    // Get full path to specified regfile.
                    prms.registryFile = new FileInfo(prms.registryFile).FullName;

                    // Make sure regfile path is different from assembly path.
                    if (String.Compare(prms.registryFile, prms.assemblyName, true) == 0)
                    {
                        throw new ArgumentException(String.Format("Registry file \"{0}\" " +
                                                                  "overwrites assembly file", prms.registryFile));
                    }

                    // Create directory that will contain regfile if it doesn't exist.
                    Directory.CreateDirectory(Path.GetDirectoryName(prms.registryFile));
                }
            }

            // Compute path of TLB according to user-provided value and whether
            // the assembly has an embedded TLB.
            if (prms.typeLibrary != null)
            {
                if (prms.typeLibrary.Length == 0)
                {
                    // TLB name not specified. If assembly has an embedded TLB,
                    // user assembly name as TLB name. Otherwise, compute a TLB
                    // name using the assembly name, ending with .tlb.
                    if (AssemblyHasEmbeddedTypeLibrary(prms.assemblyName))
                    {
                        prms.typeLibrary = prms.assemblyName;
                    }
                    else
                    {
                        prms.typeLibrary = Path.ChangeExtension(prms.assemblyName, ".tlb");
                    }
                    Debug.Assert(Directory.Exists(Path.GetDirectoryName(prms.typeLibrary)));
                }
                else
                {
                    if (AssemblyHasEmbeddedTypeLibrary(prms.assemblyName))
                    {
                        // Specifying a TLB name is invalid if assembly has an embedded TLB.
                        throw new ArgumentException("Assembly \"{0}\" has an embedded type library; " +
                                                    "cannot specify a new type library name.");
                    }

                    // Get full path to TLB file. If user did not specify a full path,
                    // assume file will sit in the same directory as the assembly.
                    if (Path.GetDirectoryName(prms.typeLibrary).Length != 0)
                    {
                        prms.typeLibrary = new FileInfo(prms.typeLibrary).FullName;
                    }
                    else
                    {
                        prms.typeLibrary = Path.Combine(Path.GetDirectoryName(prms.assemblyName), prms.typeLibrary);
                    }

                    // Make sure TLB path is different from assembly path.
                    if (String.Compare(prms.typeLibrary, prms.assemblyName, true) == 0)
                    {
                        throw new ArgumentException(String.Format("Type library \"{0}\" " +
                                                                  "overwrites assembly file", prms.typeLibrary));
                    }

                    // Create TLB directory if it doesn't exist.
                    Directory.CreateDirectory(Path.GetDirectoryName(prms.typeLibrary));
                }
            }

            // Set up context, which will take care of per-user registration/unregistration.
            using (Context context = new Context(prms.perUser && prms.registryFile == null)) {
                try {
                    // Load the assembly we're going to be working with.
                    // If we load it to generate a regfile, load it for reflection only.
                    Debug.Assert(assembly == null);
                    try {
                        if (prms.registryFile == null)
                        {
                            assembly = Assembly.LoadFrom(prms.assemblyName);
                        }
                        else
                        {
                            assembly = Assembly.ReflectionOnlyLoadFrom(prms.assemblyName);
                        }
                    } catch (BadImageFormatException bife) {
                        throw new CoreException(String.Format("Invalid assembly: \"{0}\"", prms.assemblyName), bife);
                    } catch (FileNotFoundException fnfe) {
                        throw new CoreException(String.Format("Could not locate assembly \"{0}\"", prms.assemblyName), fnfe);
                    }

                    // If user asked for the codebase option, check if the assembly has a strong name.
                    // If it doesn't, it's not fatal but we output a warning.
                    if (prms.setCodeBase && assembly.GetName().GetPublicKey().Length == 0)
                    {
                        console.WriteLine("Warning: the /codebase option was meant to be used with strong-named assemblies only.");
                    }

                    // Create registration services helper object. We need it for just about everything.
                    Debug.Assert(regServices == null);
                    regServices = new RegistrationServices();

                    // Here we switch depending on what we need to perform.
                    if (prms.registryFile == null)
                    {
                        // Check if we register or unregister.
                        if (!prms.unregister)
                        {
                            // Need to register assembly.
                            try {
                                AssemblyRegistrationFlags regFlags;
                                if (prms.setCodeBase)
                                {
                                    regFlags = AssemblyRegistrationFlags.SetCodeBase;
                                }
                                else
                                {
                                    regFlags = AssemblyRegistrationFlags.None;
                                }
                                bool registered = regServices.RegisterAssembly(assembly, regFlags);
                                if (registered)
                                {
                                    console.WriteLine("Assembly \"{0}\" registered successfully.", prms.assemblyName);
                                }
                                else
                                {
                                    console.WriteLine("Assembly \"{0}\" contains no registrable types.", prms.assemblyName);
                                }
                            } catch (UnauthorizedAccessException uae) {
                                // User doesn't have access to the needed registry keys.
                                throw new CoreException("Access denied while trying to update registry " +
                                                        "during assembly registration", uae);
                            }

                            // Also export and register type library if needed.
                            if (prms.typeLibrary != null)
                            {
                                ExportAndRegisterTypeLibrary();
                            }
                        }
                        else
                        {
                            // Need to unregister assembly. setCodeBase doesn't matter here.
                            try {
                                bool unregistered = regServices.UnregisterAssembly(assembly);
                                if (unregistered)
                                {
                                    console.WriteLine("Assembly \"{0}\" unregistered successfully.", prms.assemblyName);
                                }
                                else
                                {
                                    console.WriteLine("Assembly \"{0}\" contains no unregistrable types.", prms.assemblyName);
                                }
                            } catch (UnauthorizedAccessException uae) {
                                // User doesn't have access to the needed registry keys.
                                throw new CoreException("Access denied while trying to update registry " +
                                                        "during assembly unregistration", uae);
                            }

                            // Also unregister type library if needed.
                            if (prms.typeLibrary != null)
                            {
                                UnregisterTypeLibrary();
                            }
                        }
                    }
                    else
                    {
                        // User asked us to generate regfile.

                        // Hook our delegate to the ReflectionOnlyAssemblyResolve of the
                        // sandboxed AppDomain. It will be called to load references of our assembly.
                        AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += ResolveReflectionOnlyAssembly;
                        try {
                            // Generate the regfile. Will use instance members to get information.
                            exitCode = GenerateRegistryFile();
                        } finally {
                            // Unhook from the ReflectionOnlyAssemblyResolve now that we no longer need it.
                            AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= ResolveReflectionOnlyAssembly;
                        }
                    }
                } catch (TargetInvocationException tie) {
                    // Error in a user-defined function during assembly registration/unregistration
                    // (for example, in a ComRegisterFunction).
                    throw new CoreException(String.Format("Error in user-defined function from assembly \"{0}\"",
                                                          assembly.GetName().Name), tie);
                } catch (ReflectionTypeLoadException rtle) {
                    // Error while loading a class in the assembly (possibly in a static constructor).
                    StringBuilder builder = new StringBuilder();
                    builder.AppendFormat("Error while loading types in assembly \"{0}\": ", assembly.GetName().Name);
                    foreach (Exception loaderEx in rtle.LoaderExceptions)
                    {
                        builder.AppendLine();
                        builder.AppendFormat("  {0}", loaderEx.Message);
                    }
                    throw new CoreException(builder.ToString(), rtle);
                }
            }

            return(exitCode);
        }