// NAnt - A .NET build tool // Copyright (C) 2001-2003 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.CodeDom.Compiler; using System.Collections; using System.Collections.Specialized; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.Remoting.Lifetime; using System.Text.RegularExpressions; using System.Xml; using Microsoft.Win32; using NAnt.Core; using NAnt.Core.Util; using NAnt.VSNet.Tasks; namespace NAnt.VSNet { /// /// Represents a reference to a project or assembly. /// public class Reference { #region Public Instance Constructors /// /// Initializes a new instance of the class. /// /// /// is . /// -or- /// is . /// -or- /// is . /// -or- /// is . /// public Reference(Solution solution, ProjectSettings ps, XmlElement elemReference, GacCache gacCache, ReferencesResolver refResolver, ProjectBase parent, DirectoryInfo outputDir) { if (elemReference == null) { throw new ArgumentNullException("elemReference"); } if (gacCache == null) { throw new ArgumentNullException("gacCache"); } if (refResolver == null) { throw new ArgumentNullException("refResolver"); } if (parent == null) { throw new ArgumentNullException("parent"); } _projectSettings = ps; _parent = parent; _referenceTimeStamp = DateTime.MinValue; _isSystem = false; _name = (string) elemReference.GetAttribute("Name"); _isCreated = false; _gacCache = gacCache; _refResolver = refResolver; _deferCopyLocalGacDetermination = false; // Read the private flag _privateSpecified = (elemReference.Attributes["Private"] != null); if (_privateSpecified) { _isPrivate = (elemReference.Attributes["Private"].Value == "True"); } else { _isPrivate = false; } if (elemReference.Attributes["Project"] != null) { if (solution == null) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "External reference '{0}' found, but no solution was specified.", _name), Location.UnknownLocation); } string projectFile = solution.GetProjectFileFromGuid(elemReference.GetAttribute("Project")); TempFileCollection temporaryFiles = solution.TemporaryFiles; if (ps != null) { temporaryFiles = ps.TemporaryFiles; } ProjectBase project = ProjectFactory.LoadProject(solution, parent.SolutionTask, temporaryFiles, _gacCache, _refResolver, outputDir, projectFile); // we don't know what the timestamp of the project is going to be, // because we don't know what configuration we will be building _referenceTimeStamp = DateTime.MinValue; _project = project; _copyLocal = _privateSpecified ? _isPrivate : true; return; } if (elemReference.Attributes["WrapperTool"] != null) { _importTool = elemReference.Attributes["WrapperTool"].Value; } if (_importTool == "tlbimp" || _importTool == "primary" || _importTool == "aximp") { HandleWrapperImport(elemReference); } else { // we're dealing with an assembly reference ResolveAssemblyReference(elemReference); } } #endregion Public Instance Constructors #region Public Instance Properties /// /// Gets a value indicating whether the output file(s) of this reference /// should be copied locally. /// /// /// if the output file(s) of this reference /// should be copied locally; otherwise, . /// public bool CopyLocal { get { // Do we need to check the GAC for copy local information? // This prevents locking of files before they are built if ( _deferCopyLocalGacDetermination ) _copyLocal = !GacCache.IsAssemblyInGac(_referenceFile); return _copyLocal; } } public bool IsCreated { get { return _isCreated; } } public string Filename { get { return _referenceFile; } set { _referenceFile = value; _baseDirectory = new FileInfo(_referenceFile).Directory; _referenceTimeStamp = GetTimestamp(_referenceFile); } } public ConfigurationSettings ConfigurationSettings { get { return _configurationSettings; } set { _configurationSettings = value; } } /// /// Gets the name of the reference. /// /// /// The name of the reference. /// public string Name { get { return _name; } } /// /// Gets a value indicating whether this reference represents a system /// assembly. /// /// /// if this reference represents a system /// assembly; otherwise, . /// public bool IsSystem { get { return _isSystem; } } /// /// Gets the project which is referenced by this . /// /// /// The project which is referenced by this , or /// if this is not a project reference. /// public ProjectBase Project { get { return _project; } } /// /// Gets a value indicating whether this is a reference to another /// project. /// /// /// if this is a reference to another project; /// otherwise, . /// public bool IsProjectReference { get { return _project != null; } } public DateTime Timestamp { get { // if this is a project reference, return timestamp of project // output file (assembly) if (Project != null) { return GetTimestamp(Project.GetOutputPath(ConfigurationSettings.Name)); } // return timestamp of reference file return _referenceTimeStamp; } } public SolutionTask SolutionTask { get { return Parent.SolutionTask; } } #endregion Public Instance Properties #region Protected Instance Properties public GacCache GacCache { get { return _gacCache; } } #endregion Protected Instance Properties #region Private Instance Properties /// /// Gets the project in which the reference is defined. /// private ProjectBase Parent { get { return _parent; } } #endregion Private Instance Properties #region Public Instance Methods public void GetCreationCommand(ConfigurationSettings cs, out string program, out string commandLine) { _referenceFile = new FileInfo(Path.Combine(cs.OutputDir.FullName, _interopFile)).FullName; commandLine = @"""" + _typelibFile + @""" /silent /out:""" + _referenceFile + @""""; if (_importTool == "aximp" && _runtimeCallableWrapper != null) { string rcwFile = Path.Combine(cs.OutputDir.FullName, _runtimeCallableWrapper); if (File.Exists(rcwFile)) { commandLine += " /rcw:\"" + rcwFile + "\""; } } if (_importTool == "tlbimp") { commandLine += " /namespace:" + _namespace; } if (_importTool == "tlbimp" || _importTool == "aximp") { // check if wrapper assembly should be strongly signed if (_projectSettings.AssemblyOriginatorKeyFile != null) { commandLine += @" /keyfile:""" + Path.Combine(Parent.ProjectDirectory.FullName, _projectSettings.AssemblyOriginatorKeyFile) + @""""; } } program = _importTool + ".exe"; } public DirectoryInfo GetBaseDirectory(ConfigurationSettings configurationSettings) { if (Project != null) { return Project.GetConfiguration(configurationSettings.Name).OutputDir; } return _baseDirectory; } public StringCollection GetAssemblyReferences(ConfigurationBase configurationSettings) { StringCollection assemblyReferences = null; if (IsProjectReference) { // if we're dealing with a project reference, then we need to // reference all assembly references of that project assemblyReferences = Project.GetAssemblyReferences(configurationSettings); // and the project output file itself string projectOutputFile = Project.GetConfiguration( configurationSettings.Name).OutputPath; if (!File.Exists(projectOutputFile)) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Output file '{0}' of project '{1}' does not exist.", projectOutputFile, Name), Location.UnknownLocation); } assemblyReferences.Add(projectOutputFile); } else { // if we're dealing with an assembly reference, then we only // need to reference that assembly itself as VS.NET forced users // to add all dependent assemblies to the project itself // ensure referenced assembly actually exists FileInfo fi = new FileInfo(_referenceFile); if (!fi.Exists) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Couldn't find referenced assembly '{0}'.", _referenceFile), Location.UnknownLocation); } // add referenced assembly to list of reference assemblies assemblyReferences = new StringCollection(); assemblyReferences.Add(fi.FullName); } return assemblyReferences; } public StringCollection GetReferenceFiles(ConfigurationSettings configurationSettings) { StringCollection referencedFiles = new StringCollection(); // check if we're dealing with a project reference if (IsProjectReference) { // get output file of project _referenceFile = Project.GetConfiguration( configurationSettings.Name).OutputPath; } FileInfo fi = new FileInfo(_referenceFile); if (!fi.Exists) { if (!IsProjectReference) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Couldn't find referenced assembly '{0}'.", _referenceFile), Location.UnknownLocation); } else { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Couldn't find referenced project '{0}' output file, '{1}'.", Project.Name, _referenceFile), Location.UnknownLocation); } } else { _referenceFile = fi.FullName; } string[] referencedModules = GetAllReferencedModules(_referenceFile); // get a list of the references in the output directory foreach (string referenceFile in referencedModules) { // skip module if module is not the assembly referenced by // the project and is installed in GAC if (string.Compare(referenceFile, _referenceFile, true, CultureInfo.InvariantCulture) != 0) { // skip referenced module if the assembly referenced by // the project is a system reference or the module itself // is installed in the GAC if (IsSystem || GacCache.IsAssemblyInGac(referenceFile)) { continue; } } // now for each reference, get the related files (.xml, .pdf, etc...) string relatedFiles = Path.GetFileName(Path.ChangeExtension(referenceFile, ".*")); foreach (string relatedFile in Directory.GetFiles(fi.DirectoryName, relatedFiles)) { // ignore files that do not have same base filename as reference file // eg. when reference file is MS.Runtime.dll, we do not want files // named MS.Runtime.Interop.dll if (string.Compare(Path.GetFileNameWithoutExtension(relatedFile), Path.GetFileNameWithoutExtension(referenceFile), true, CultureInfo.InvariantCulture) != 0) { continue; } // ignore any other the garbage files created string fileExtension = Path.GetExtension(relatedFile).ToLower(CultureInfo.InvariantCulture); if (fileExtension != ".dll" && fileExtension != ".xml" && fileExtension != ".pdb") { continue; } referencedFiles.Add(new FileInfo(relatedFile).Name); } //ADDED!!!!!! // copy the satellite assembly for each culture name, if it exists foreach (CultureInfo culture in CultureInfo.GetCultures( CultureTypes.AllCultures )) { // determine directory for satellite assembly string satelliteDir = Path.Combine(fi.DirectoryName, culture.Name); // ensure diretory of satellite assembly exists if (!Directory.Exists(satelliteDir)) continue; // determine filename of satellite assembly FileInfo satelliteAssembly = new FileInfo(Path.Combine(satelliteDir, Path.GetFileNameWithoutExtension(referenceFile) + ".resources.dll")); if (satelliteAssembly.Exists) referencedFiles.Add( Path.Combine(culture.Name, satelliteAssembly.Name) ); } //ADDED!!!!!! } return referencedFiles; } #endregion Public Instance Methods #region Private Instance Methods private string[] GetAllReferencedModules(string module) { string fullPathToModule = Path.GetFullPath(module); string moduleDirectory = Path.GetDirectoryName(fullPathToModule); Hashtable allReferences = new Hashtable(); Hashtable unresolvedReferences = new Hashtable(); try { allReferences.Add(fullPathToModule, null); unresolvedReferences.Add(fullPathToModule, null); while (unresolvedReferences.Count > 0) { IDictionaryEnumerator unresolvedEnumerator = unresolvedReferences.GetEnumerator(); unresolvedEnumerator.MoveNext(); string referenceToResolve = (string) unresolvedEnumerator.Key; unresolvedReferences.Remove(referenceToResolve); _refResolver.AppendReferencedModulesLocatedInGivenDirectory(moduleDirectory, referenceToResolve, ref allReferences, ref unresolvedReferences); } } catch (Exception ex) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Error resolving module references of '{0}'.", fullPathToModule), Location.UnknownLocation, ex); } string[] result = new string[allReferences.Keys.Count]; allReferences.Keys.CopyTo(result, 0); return result; } /// /// /// Resolves an assembly reference. /// /// /// The of the assembly reference that should be resolved. /// /// /// Visual Studio .NET uses the following search mechanism : /// /// /// /// /// The project directory. /// /// /// /// /// The directories specified in the "ReferencePath" property, /// which is stored in the .USER file. /// /// /// /// /// The .NET Framework directory (see KB306149) /// /// /// /// /// /// The directories specified under the following registry /// keys: /// /// /// /// /// HKLM\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders /// /// /// /// /// HKCU\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders /// /// /// /// /// HKLM\SOFTWARE\Microsoft\VisualStudio\<major version>.<minor version>\AssemblyFolders /// /// /// /// /// HKCU\SOFTWARE\Microsoft\VisualStudio\<major version>.<minor version>\AssemblyFolders /// /// /// /// /// Future versions of Visual Studio .NET will also check /// in: /// /// /// /// /// HKLM\SOFTWARE\Microsoft\.NETFramework\AssemblyFoldersEx /// /// /// /// /// HKCU\SOFTWARE\Microsoft\.NETFramework\AssemblyFoldersEx /// /// /// /// /// /// /// /// The HintPath. /// /// /// /// private void ResolveAssemblyReference(XmlElement referenceElement) { // check if we're dealing with a Visual C++ assembly reference if (referenceElement.Name == "AssemblyReference") { _referenceFile = referenceElement.GetAttribute("RelativePath"); if (_referenceFile == null) { throw new BuildException("For Visual C++ projects only assembly" + " references using relative paths are supported.", Location.UnknownLocation); } else { // expand macro's in RelativePath _referenceFile = _rxMacro.Replace(_referenceFile, new MatchEvaluator(EvaluateMacro)); // TODO: support locating assemblies in VCConfiguration.ReferencesPath, // but for now just remove it from reference filename _referenceFile = _referenceFile.Replace("{ReferencesPath}\\", ""); } } else { // determine assembly name _referenceFile = referenceElement.Attributes["AssemblyName"].Value + ".dll"; } // 1. The project directory // NOT SURE IF THIS IS CORRECT // 2. The ReferencePath // NOT SURE WE SHOULD DO THIS ONE // 3. The .NET Framework directory if (ResolveFromFramework()) { return; } // 4. AssemblyFolders if (ResolveFromAssemblyFolders(referenceElement)) { return; } // 5. The HintPath / Relative Path if (referenceElement.Name != "AssemblyReference") { // for now we do not support relative paths assembly references // in Visual C++ projects if (ResolveFromRelativePath(referenceElement, referenceElement.GetAttribute("HintPath"))) { return; } throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Reference to assembly '{0}' could not be resolved.", referenceElement.Attributes["AssemblyName"].Value), Location.UnknownLocation); } else { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Reference to assembly '{0}' could not be resolved.", referenceElement.Attributes["RelativePath"].Value), Location.UnknownLocation); } } /// /// Searches for the given file in all paths in . /// /// The folders to search. /// The file to search for. /// /// if was found /// in . /// protected bool ResolveFromFolderList(StringCollection folderList, string fileName) { foreach (string path in folderList) { if (ResolveFromPath(Path.Combine(path, fileName))) { return true; } } return false; } /// /// Resolves an assembly reference in the framework assembly directory /// of the target framework. /// /// /// if the assembly could be located in the /// framework assembly directory; otherwise, see langword="false" />. /// protected bool ResolveFromFramework() { DirectoryInfo frameworkAssemblyDirectory = new DirectoryInfo( SolutionTask.Project.TargetFramework.FrameworkAssemblyDirectory.FullName); string systemAssembly = Path.Combine(frameworkAssemblyDirectory.FullName, _referenceFile); if (File.Exists(systemAssembly)) { // this file is a system assembly _baseDirectory = frameworkAssemblyDirectory; _copyLocal = _privateSpecified ? _isPrivate : false; _referenceFile = systemAssembly; _isSystem = true; _referenceTimeStamp = GetTimestamp(_referenceFile); return true; } return false; } /// /// Resolves an assembly reference using a path relative to the project /// directory. /// /// /// if the assembly could be located using the /// relative path; otherwise, . /// protected bool ResolveFromRelativePath(XmlElement referenceElement, string relativePath) { if (!StringUtils.IsNullOrEmpty(relativePath)) { string referencePath = Path.GetFullPath(Path.Combine( Parent.ProjectDirectory.FullName, relativePath)); if (!ResolveFromPath(referencePath)) { // allow a not-existing file to be a valid reference, // as the reference might point to an output file of // a project that was not referenced as a project FileInfo fileReference = new FileInfo(referencePath); _referenceFile = fileReference.FullName; _baseDirectory = fileReference.Directory; _referenceTimeStamp = GetTimestamp(_referenceFile); _copyLocal = _privateSpecified ? _isPrivate : true; } return true; } return false; } private bool ResolveFromAssemblyFolders(XmlElement referenceElement) { if (referenceElement.Attributes["AssemblyFolderKey"] != null) { string assemblyFolderKey = referenceElement.Attributes["AssemblyFolderKey"].Value; try { RegistryKey registryHive = null; switch (assemblyFolderKey.Substring(0,4)) { case "hklm": registryHive = Registry.LocalMachine; break; case "hkcu": registryHive = Registry.CurrentUser; break; } if (registryHive != null) { foreach (string assemblyFolderRootKey in SolutionTask.AssemblyFolderRootKeys) { RegistryKey assemblyFolderRegistryRoot = registryHive.OpenSubKey(assemblyFolderRootKey); if (assemblyFolderRegistryRoot != null) { RegistryKey assemblyFolderRegistryKey = assemblyFolderRegistryRoot.OpenSubKey(assemblyFolderKey.Substring(5)); if (assemblyFolderRegistryKey != null) { string assemblyFolder = assemblyFolderRegistryKey.GetValue(string.Empty) as string; if (assemblyFolder != null) { if (ResolveFromPath(Path.Combine(assemblyFolder, _referenceFile))) { return true; } } } } } } } catch (Exception ex) { Log(Level.Verbose, "Error resolve reference to '{0}' using" + " AssemblyFolderKey '{1}'.", _referenceFile, assemblyFolderKey); Log(Level.Debug, ex.ToString()); } } if (ResolveFromFolderList(SolutionTask.AssemblyFolders.DirectoryNames, _referenceFile)) { return true; } return ResolveFromFolderList(SolutionTask.DefaultAssemblyFolders.DirectoryNames, _referenceFile); } /// /// Resolves an assembly reference using the specified file path. /// /// /// if the assembly exists at the specified /// location; otherwise, see langword="false" />. /// private bool ResolveFromPath(string path) { FileInfo fileReference = new FileInfo(path); if (fileReference.Exists) { _referenceFile = fileReference.FullName; _baseDirectory = fileReference.Directory; _referenceTimeStamp = GetTimestamp(_referenceFile); if (!_privateSpecified) { // assembly should only be copied locally if its not // installed in the GAC _deferCopyLocalGacDetermination = true; } else { _copyLocal = _isPrivate; } return true; } return false; } /// /// Returns the date and time the specified file was last written to. /// /// The file for which to obtain write date and time information. /// /// A structure set to the date and time that /// the specified file was last written to, or /// if the specified file does not /// exist. /// private DateTime GetTimestamp(string fileName) { if (!File.Exists(fileName)) { return DateTime.MaxValue; } return File.GetLastWriteTime(fileName); } private void HandleWrapperImport(XmlElement elemReference) { string majorVersion = (int.Parse(elemReference.Attributes["VersionMajor"].Value, CultureInfo.InvariantCulture)).ToString("x", CultureInfo.InvariantCulture); string minorVersion = (int.Parse(elemReference.Attributes["VersionMinor"].Value, CultureInfo.InvariantCulture)).ToString("x", CultureInfo.InvariantCulture); string lcid = (int.Parse(elemReference.Attributes["Lcid"].Value, CultureInfo.InvariantCulture)).ToString("x", CultureInfo.InvariantCulture); string referenceName = elemReference.Attributes["Name"].Value; string tlbVersionKey = string.Format(@"TYPELIB\{0}\{1}.{2}", elemReference.Attributes["Guid"].Value, majorVersion, minorVersion); string tlbRegistryKey = string.Format(@"TYPELIB\{0}\{1}.{2}\{3}\win32", elemReference.Attributes["Guid"].Value, majorVersion, minorVersion, lcid); // look for a primary interop assembly using (RegistryKey registryKey = Registry.ClassesRoot.OpenSubKey(tlbVersionKey)) { if (registryKey != null && registryKey.GetValue("PrimaryInteropAssemblyName") != null) { string primaryInteropAssemblyName = (string) registryKey.GetValue("PrimaryInteropAssemblyName"); try { // get filename of primary interop assembly _referenceFile = _refResolver.GetAssemblyFileName( primaryInteropAssemblyName); // determine base directory of primary interop assembly _baseDirectory = new DirectoryInfo(Path.GetDirectoryName(_referenceFile)); // primary interop assembly is located in GAC, so do not // copy it locally unless explicitly specified in project // file _copyLocal = _privateSpecified ? _isPrivate : false; // get timestamp of primary interop assembly _referenceTimeStamp = GetTimestamp(_referenceFile); } catch (Exception ex) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Primary Interop Assembly '{0}' could not be loaded.", primaryInteropAssemblyName), Location.UnknownLocation, ex); } switch (_importTool) { case "aximp": // if the import tool is aximp, we'll use the primary // interop assembly as runtime callable wrapper _runtimeCallableWrapper = _referenceFile; break; case "tlbimp": // if tlbimp is defined as import tool, but a primary // interop assembly is available, then output a // warning Log(Level.Warning, "The reference component" + " '{0}' has an updated custom wrapper available.", referenceName); break; case "primary": // if we found the primary interop assembly, consider // our business here done return; } } // if we were actually looking for a primary interop assembly // and didn't find one, then the build should fail if (_importTool == "primary") { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Couldn't find primary interop assembly '{0}' ({1}).", referenceName, tlbRegistryKey), Location.UnknownLocation); } } using (RegistryKey registryKey = Registry.ClassesRoot.OpenSubKey(tlbRegistryKey)) { if (registryKey == null) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Couldn't find reference to type library '{0}' ({1}).", referenceName, tlbRegistryKey), Location.UnknownLocation); } // check if the typelib actually exists _typelibFile = (string) registryKey.GetValue(null); if (!File.Exists(_typelibFile)) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Couldn't find referenced type library '{0}'.", _typelibFile), Location.UnknownLocation); } _referenceTimeStamp = GetTimestamp(_typelibFile); if (_importTool == "aximp") { if (_runtimeCallableWrapper == null) { // if no primary interop assembly is provided for ActiveX control, // trust the fact that VS.NET uses Interop..dll // for the imported typelibrary _runtimeCallableWrapper = "Interop." + referenceName.Substring(2, referenceName.Length - 2) + ".dll"; } // eg. AxVisOcx will become AxInterop.VisOcx.dll _interopFile = "AxInterop." + referenceName.Substring(2, referenceName.Length - 2) + ".dll"; } else { _interopFile = "Interop." + referenceName + ".dll"; } _referenceFile = _interopFile; _namespace = referenceName; _copyLocal = true; _isCreated = true; } } /// /// Is called each time a regular expression match is found during a /// operation. /// /// The resulting from a single regular expression match during a . /// /// The expanded . /// /// The macro is not supported. /// Expansion of a given macro is not yet implemented. private string EvaluateMacro(Match m) { string macro = m.Groups[1].Value; // expand using solution level macro's string expandedMacro = SolutionTask.ExpandMacro(macro); if (expandedMacro != null) { return expandedMacro; } // expand using project level macro's expandedMacro = Parent.ExpandMacro(macro); if (expandedMacro != null) { return expandedMacro; } throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Macro \"{0}\" is not supported in assembly references.", macro), Location.UnknownLocation); } /// /// Logs a message with the given priority. /// /// The message priority at which the specified message is to be logged. /// The message to be logged. /// /// The actual logging is delegated to the underlying task. /// private void Log(Level messageLevel, string message) { if (SolutionTask != null) { SolutionTask.Log(messageLevel, message); } } /// /// Logs a message with the given priority. /// /// The message priority at which the specified message is to be logged. /// The message to log, containing zero or more format items. /// An array containing zero or more objects to format. /// /// The actual logging is delegated to the underlying task. /// private void Log(Level messageLevel, string message, params object[] args) { if (SolutionTask != null) { SolutionTask.Log(messageLevel, message, args); } } #endregion Private Instance Methods #region Private Instance Fields private ProjectBase _parent; private string _name; private string _referenceFile; private string _runtimeCallableWrapper; private DirectoryInfo _baseDirectory; private string _namespace; private string _interopFile; private string _typelibFile; private bool _deferCopyLocalGacDetermination; private bool _copyLocal; private bool _isCreated; private bool _isSystem; private string _importTool; private DateTime _referenceTimeStamp; private bool _privateSpecified; private bool _isPrivate; private ProjectSettings _projectSettings; private ConfigurationSettings _configurationSettings; private ProjectBase _project; private GacCache _gacCache; private ReferencesResolver _refResolver; private readonly Regex _rxMacro = new Regex(@"\$\((\w+)\)"); #endregion Private Instance Fields } }