// NAnt - A .NET build tool // Copyright (C) 2001-2006 Gerry Shaw // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // Ian MacLean (ian@maclean.ms) // Gert Driesen (gert.driesen@ardatis.com) using System; using System.Collections.Specialized; using System.Diagnostics; using System.Globalization; using System.IO; using System.Text; using NAnt.Core; using NAnt.Core.Attributes; using NAnt.Core.Types; using NAnt.Core.Tasks; using NAnt.Core.Util; using NAnt.DotNet.Types; namespace NAnt.Win32.Tasks { /// /// Registers an assembly, or set of assemblies for use from COM clients. /// /// /// /// Refer to the Regasm /// documentation for more information on the regasm tool. /// /// /// /// /// Register types in a single assembly. /// /// /// /// ]]> /// /// /// /// /// Register types of an assembly and generate a type library containing /// definitions of accessible types defined within the assembly. /// /// /// /// ]]> /// /// /// /// /// Register types of set of assemblies at once, while specifying a set /// of reference assemblies. /// /// /// /// /// /// /// /// /// /// /// /// ]]> /// /// [TaskName("regasm")] [ProgramLocation(LocationType.FrameworkDir)] public class RegAsmTask : ExternalProgramBase { #region Private Instance Fields private StringBuilder _arguments = new StringBuilder(); private string _programFileName; private DirectoryInfo _workingDirectory; private FileInfo _assemblyFile; private FileInfo _regfile; private FileInfo _typelib; private bool _codebase; private bool _unregister; private bool _registered; private AssemblyFileSet _assemblies = new AssemblyFileSet(); private AssemblyFileSet _references = new AssemblyFileSet(); #endregion Private Instance Fields #region Public Instance Properties /// /// The name of the file to register. This is provided as an alternate /// to using the task's . /// [TaskAttribute("assembly")] public FileInfo AssemblyFile { get { return _assemblyFile; } set { _assemblyFile = value; } } /// /// Registry file to export to instead of entering the types directly /// into the registry. /// [TaskAttribute("regfile")] public FileInfo RegistryFile { get { return _regfile; } set { _regfile = value; } } /// /// Set the code base registry setting. /// [TaskAttribute("codebase")] [BooleanValidator()] public bool CodeBase { get { return _codebase; } set { _codebase = value; } } /// /// Only refer to already registered type libraries. /// [TaskAttribute("registered")] [BooleanValidator()] public bool Registered { get { return _registered; } set { _registered = value; } } /// /// Export the assemblies to the specified type library and register it. /// [TaskAttribute("typelib")] public FileInfo TypeLib { get { return _typelib; } set { _typelib = value; } } /// /// Unregister the assembly. The default is . /// [TaskAttribute("unregister")] [BooleanValidator()] public bool Unregister { get { return _unregister; } set { _unregister = value; } } /// /// The set of assemblies to register, or unregister. /// [BuildElement("assemblies")] public AssemblyFileSet Assemblies { get { return _assemblies; } set { _assemblies = value; } } /// /// The set of assembly references. /// [BuildElement("references")] public AssemblyFileSet References { get { return _references; } set { _references = value; } } #endregion Public Instance Properties #region Override implementation of ExternalProgramBase /// /// Gets the working directory for the application. /// /// /// The working directory for the application. /// public override DirectoryInfo BaseDirectory { get { if (_workingDirectory == null) { return base.BaseDirectory; } return _workingDirectory; } set { _workingDirectory = value; } } /// /// Gets the command line arguments for the external program. /// /// /// The command line arguments for the external program. /// public override string ProgramArguments { get { return _arguments.ToString(); } } /// /// Gets the filename of the external program to start. /// /// /// The filename of the external program. /// /// /// Override in derived classes to explicitly set the location of the /// external tool. /// public override string ProgramFileName { get { if (_programFileName == null) { _programFileName = base.ProgramFileName; } return _programFileName; } } /// /// Updates the of the specified /// . /// /// The of which the should be updated. protected override void PrepareProcess(Process process) { // avoid copying the assembly references (and regasm) to a // temporary directory if not necessary if (References.FileNames.Count == 0) { // further delegate preparation to base class base.PrepareProcess(process); // no further processing required return; } // create instance of Copy task CopyTask ct = new CopyTask(); // inherit project from current task ct.Project = Project; // inherit namespace manager from current task ct.NamespaceManager = NamespaceManager; // parent is current task ct.Parent = this; // inherit verbose setting from resgen task ct.Verbose = Verbose; // only output warning messages or higher, unless we're running // in verbose mode if (!ct.Verbose) { ct.Threshold = Level.Warning; } // make sure framework specific information is set ct.InitializeTaskConfiguration(); // set parent of child elements ct.CopyFileSet.Parent = ct; // inherit project from solution task for child elements ct.CopyFileSet.Project = ct.Project; // inherit namespace manager from solution task ct.CopyFileSet.NamespaceManager = ct.NamespaceManager; // set base directory of fileset ct.CopyFileSet.BaseDirectory = Assemblies.BaseDirectory; // copy all files to base directory itself ct.Flatten = true; // copy referenced assemblies foreach (string file in References.FileNames) { ct.CopyFileSet.Includes.Add(file); } // copy assemblies to register foreach (string file in Assemblies.FileNames) { ct.CopyFileSet.Includes.Add(file); } if (AssemblyFile != null) { ct.CopyFileSet.Includes.Add(AssemblyFile.FullName); } // copy command line tool to working directory ct.CopyFileSet.Includes.Add(base.ProgramFileName); // set destination directory ct.ToDirectory = BaseDirectory; // increment indentation level ct.Project.Indent(); try { // execute task ct.Execute(); } finally { // restore indentation level ct.Project.Unindent(); } // change program to execute the tool in working directory as // that will allow this tool to resolve assembly references // using assemblies stored in the same directory _programFileName = Path.Combine(BaseDirectory.FullName, Path.GetFileName(base.ProgramFileName)); // further delegate preparation to base class base.PrepareProcess(process); } #endregion Override implementation of ExternalProgramBase #region Override implementation of Task /// /// Registers or unregisters a single assembly, or a group of assemblies. /// protected override void ExecuteTask() { if (AssemblyFile == null && Assemblies.FileNames.Count == 0) { return; } // when reference assembly are specified, we copy all references // and all assemblies to a temp directory and run regasm from there if (References.FileNames.Count != 0) { // use a newly created temporary directory as working directory BaseDirectory = FileUtils.GetTempDirectory(); } if (Unregister) { _arguments.Append(" /unregister"); } if (TypeLib != null) { _arguments.AppendFormat(CultureInfo.InvariantCulture, " /tlb:\"{0}\"", TypeLib.FullName); } if (CodeBase) { _arguments.Append(" /codebase"); } if (RegistryFile != null) { _arguments.AppendFormat(CultureInfo.InvariantCulture, " /regfile:\"{0}\"", RegistryFile.FullName); } if (Registered) { _arguments.Append(" /registered"); } if (Verbose) { _arguments.Append(" /verbose"); } else { _arguments.Append(" /silent"); } _arguments.Append(" /nologo"); if (AssemblyFile != null) { Log(Level.Info, "{0} '{1}' for COM Interop", Unregister ? "Unregistering" : "Registering", AssemblyFile.FullName); _arguments.AppendFormat(" \"{0}\"", GetAssemblyPath( AssemblyFile.FullName)); } else { // display build log message Log(Level.Info, "{0} {1} files for COM interop", Unregister ? "UnRegistering" : "Registering", Assemblies.FileNames.Count); // add files to command line foreach (string path in Assemblies.FileNames) { Log(Level.Verbose, "{0} '{1}' for COM Interop", Unregister ? "UnRegistering" : "Registering", path); _arguments.AppendFormat(" \"{0}\"", GetAssemblyPath(path)); } } try { // call base class to do the work base.ExecuteTask(); } finally { // we only need to remove temporary directory if it was // actually created if (_workingDirectory != null) { // delete temporary directory and all files in it DeleteTask deleteTask = new DeleteTask(); deleteTask.Project = Project; deleteTask.Parent = this; deleteTask.InitializeTaskConfiguration(); deleteTask.Directory = _workingDirectory; deleteTask.Threshold = Level.None; // no output in build log deleteTask.Execute(); } } } #endregion Override implementation of Task #region Private Instance Methods private string GetAssemblyPath(string assembly) { if (_workingDirectory == null) { return assembly; } return Path.Combine(_workingDirectory.FullName, Path.GetFileName(assembly)); } #endregion Private Instance Methods } }