// NAnt - A .NET build tool // Copyright (C) 2001-2004 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 // // Matthew Mastracci (matt@aclaro.com) // Scott Ford (sford@RJKTECH.com) // Gert Driesen (gert.driesen@ardatis.com) using System; using System.Globalization; using System.IO; using System.Xml; using Microsoft.Win32; using NAnt.Core; using NAnt.Core.Tasks; using NAnt.Core.Util; using NAnt.Core.Types; using NAnt.Win32.Tasks; namespace NAnt.VSNet { public class ManagedWrapperReference : WrapperReferenceBase { #region Public Instance Constructors public ManagedWrapperReference(XmlElement xmlDefinition, ReferencesResolver referencesResolver, ProjectBase parent, GacCache gacCache, ProjectSettings projectSettings) : base(xmlDefinition, referencesResolver, parent, gacCache) { if (projectSettings == null) { throw new ArgumentNullException("projectSettings"); } _projectSettings = projectSettings; // determine name of wrapper reference XmlAttribute wrapperNameAttribute = XmlDefinition.Attributes["Name"]; if (wrapperNameAttribute != null) { _name = wrapperNameAttribute.Value; } // determine wrapper tool XmlAttribute toolAttribute = XmlDefinition.Attributes["WrapperTool"]; if (toolAttribute == null) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Wrapper tool for reference \"{0}\" in project \"{1}\" could" + " not be determined.", Name, Parent.Name), Location.UnknownLocation); } _wrapperTool = toolAttribute.Value; // determine if there's a primary interop assembly for the typelib _primaryInteropAssembly = GetPrimaryInteropAssembly(); // determine filename of wrapper assembly _wrapperAssembly = ResolveWrapperAssembly(); } #endregion Public Instance Constructors #region Override implementation of ReferenceBase /// /// Gets the name of the referenced assembly. /// /// /// The name of the referenced assembly, or if /// the name could not be determined. /// public override string Name { get { return _name; } } #endregion Override implementation of ReferenceBase #region Override implementation of WrapperReferenceBase /// /// Gets the name of the tool that should be used to create the /// . /// /// /// The name of the tool that should be used to create the /// . /// public override string WrapperTool { get { return _wrapperTool; } } /// /// Gets the path of the wrapper assembly. /// /// /// The path of the wrapper assembly. /// /// /// The wrapper assembly is stored in the object directory of the /// project. /// public override string WrapperAssembly { get { return _wrapperAssembly; } } /// /// Gets the path of the Primary Interop Assembly. /// /// /// The path of the Primary Interop Assembly, or /// if not available. /// protected override string PrimaryInteropAssembly { get { return _primaryInteropAssembly; } } /// /// Gets the hex version of the type library as defined in the definition /// of the reference. /// /// /// The hex version of the type library. /// /// /// /// The definition of the reference does not contain a "VersionMajor" attribute. /// /// -or /// /// The definition of the reference does not contain a "VersionMinor" attribute. /// /// protected override string TypeLibVersion { get { XmlAttribute majorAttribute = XmlDefinition.Attributes["VersionMajor"]; if (majorAttribute == null) { throw new BuildException("The definition of the reference" + " does not contain a \"VersionMajor\" attribute."); } XmlAttribute minorAttribute = XmlDefinition.Attributes["VersionMinor"]; if (minorAttribute == null) { throw new BuildException("The definition of the reference" + " does not contain a \"VersionMinor\" attribute."); } string majorVersion = (int.Parse(majorAttribute.Value, CultureInfo.InvariantCulture)).ToString("x", CultureInfo.InvariantCulture); string minorVersion = (int.Parse(minorAttribute.Value, CultureInfo.InvariantCulture)).ToString("x", CultureInfo.InvariantCulture); return majorVersion + "." + minorVersion; } } /// /// Gets the GUID of the type library as defined in the definition /// of the reference. /// /// /// The GUID of the type library. /// protected override string TypeLibGuid { get { XmlAttribute guidAttribute = XmlDefinition.Attributes["Guid"]; if (guidAttribute == null) { throw new BuildException("The definition of the reference" + " does not contain a \"Guid\" attribute."); } return guidAttribute.Value; } } /// /// Gets the locale of the type library in hex notation. /// /// /// The locale of the type library. /// protected override string TypeLibLocale { get { XmlAttribute localeAttribute = XmlDefinition.Attributes["Lcid"]; if (localeAttribute == null) { throw new BuildException("The definition of the reference" + " does not contain a \"Lcid\" attribute."); } return int.Parse(localeAttribute.Value).ToString("x"); } } #endregion Override implementation of WrapperReferenceBase #region Private Instance Properties private ProjectSettings ProjectSettings { get { return _projectSettings; } } #endregion Private Instance Properties #region Private Instance Methods protected override void ImportTypeLibrary() { TlbImpTask tlbImp = new TlbImpTask(); // parent is solution task tlbImp.Parent = SolutionTask; // inherit project from solution task tlbImp.Project = SolutionTask.Project; // inherit namespace manager from solution task tlbImp.NamespaceManager = SolutionTask.NamespaceManager; // inherit verbose setting from solution task tlbImp.Verbose = SolutionTask.Verbose; // make sure framework specific information is set tlbImp.InitializeTaskConfiguration(); tlbImp.TypeLib = new FileInfo(GetTypeLibrary()); tlbImp.OutputFile = new FileInfo(WrapperAssembly); tlbImp.Namespace = TypeLibraryName; // according to "COM Programming with Microsoft .NET" (page 59) // the /sysarray option should always be set in order to // generate wrappers that match those generated by VS.NET tlbImp.SysArray = true; // transform [out, retval] parameters of methods on dispatch-only // interfaces (dispinterfaces) into return values. // // this only affects .NET 1.1 or higher, as tlbimp does not expose // this on .NET 1.0. tlbImp.Transform = "dispret"; // use other imported type libraries to resolve references // // there's one serious limitation in the current implementation: // // if type library A references type library B, then we should // first import type library B and use a reference to that // imported type library when we import type library A. // // however, we have no way to find out in which order the type // libraries should be imported. So only if type library B is // first listed in the project file, it will work fine. // // we should find a way to analyse a type library to determine // dependencies on other type libraries // // according to JR (jrv72@users.sourceforge.net) a possible // solution could be to "use TypeLibConverter.ConvertTypeLibToAssembly. // This has a callback of type ITypeLibImporterNotifySink, which I // speculate allows one to recognize when one type library // depends on another. I believe what you have to do is start // with an arbitrary type library, and if that type library calls // back on the ResolveRef() method, and if that type library is // one you were planning to add later, you compile it // immediately and pass the assembly back out of ResolveRef. I // haven't tested this yet, but it's my best understanding of // how it all works. foreach (ReferenceBase reference in Parent.References) { // we're only interested in imported type libraries WrapperReferenceBase wrapper = reference as WrapperReferenceBase; // avoid stack overflow causes by mutual dependencies if (wrapper == null || !wrapper.IsCreated || wrapper.WrapperTool != "tlbimp") { continue; } tlbImp.References.Includes.Add(wrapper.WrapperAssembly); } if (ProjectSettings.AssemblyOriginatorKeyFile != null) { tlbImp.KeyFile = new FileInfo(FileUtils.CombinePaths(Parent.ProjectDirectory.FullName, ProjectSettings.AssemblyOriginatorKeyFile)); } if (ProjectSettings.AssemblyKeyContainerName != null) { tlbImp.KeyContainer = ProjectSettings.AssemblyKeyContainerName; } // increment indentation level tlbImp.Project.Indent(); try { // execute task tlbImp.Execute(); } finally { // restore indentation level tlbImp.Project.Unindent(); } } protected override void ImportActiveXLibrary() { AxImpTask axImp = new AxImpTask(); // parent is solution task axImp.Parent = SolutionTask; // inherit project from solution task axImp.Project = SolutionTask.Project; // inherit namespace manager from solution task axImp.NamespaceManager = SolutionTask.NamespaceManager; // inherit verbose setting from solution task axImp.Verbose = SolutionTask.Verbose; // make sure framework specific information is set axImp.InitializeTaskConfiguration(); axImp.OcxFile = new FileInfo(GetTypeLibrary()); axImp.OutputFile = new FileInfo(WrapperAssembly); if (ProjectSettings.AssemblyOriginatorKeyFile != null) { axImp.KeyFile = new FileInfo(FileUtils.CombinePaths(Parent.ProjectDirectory.FullName, ProjectSettings.AssemblyOriginatorKeyFile)); } if (ProjectSettings.AssemblyKeyContainerName != null) { axImp.KeyContainer = ProjectSettings.AssemblyKeyContainerName; } string rcw = PrimaryInteropAssembly; if (rcw == null) { // if no primary interop assembly is provided for ActiveX control, // then use the imported type library (if available) rcw = FileUtils.CombinePaths(Parent.ObjectDir.FullName, "Interop." + TypeLibraryName + ".dll"); } if (File.Exists(rcw)) { axImp.RcwFile = new FileInfo(rcw); } // increment indentation level axImp.Project.Indent(); try { // execute task axImp.Execute(); } finally { // restore indentation level axImp.Project.Unindent(); } } #endregion Private Instance Methods #region Private Instance Fields private string _name; private readonly string _wrapperTool; private readonly string _wrapperAssembly; private readonly ProjectSettings _projectSettings; private string _primaryInteropAssembly; #endregion Private Instance Fields } }