Datei: NDOPackage/ProjectDescription.cs
Last Commit (90ec57c)
| 1 | // |
| 2 | // Copyright (c) 2002-2024 Mirko Matytschak |
| 3 | // (www.netdataobjects.de) |
| 4 | // |
| 5 | // Author: Mirko Matytschak |
| 6 | // |
| 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated |
| 8 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation |
| 9 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the |
| 10 | // Software, and to permit persons to whom the Software is furnished to do so, subject to the following |
| 11 | // conditions: |
| 12 | |
| 13 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions |
| 14 | // of the Software. |
| 15 | // |
| 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED |
| 17 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF |
| 19 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| 20 | // DEALINGS IN THE SOFTWARE. |
| 21 | |
| 22 | |
| 23 | using SD = System.Diagnostics; |
| 24 | using System.Xml; |
| 25 | using System.Collections.Generic; |
| 26 | using System.IO; |
| 27 | using Microsoft.VisualStudio.Shell.Interop; |
| 28 | using System.Linq; |
| 29 | using EnvDTE; |
| 30 | using Project = Community.VisualStudio.Toolkit.Project; |
| 31 | using Solution = Community.VisualStudio.Toolkit.Solution; |
| 32 | |
| 33 | namespace NDOVsPackage |
| 34 | { |
| 35 | |
| 36 | ····/// <summary> |
| 37 | ····/// ProjectDescription. |
| 38 | ····/// </summary> |
| 39 | ····[SD.CodeAnalysis.SuppressMessage( "Usage", "VSTHRD010:Invoke single-threaded types on Main thread", Justification = "This code always runs on the UI thread" )] |
| 40 | ····internal class ProjectDescription |
| 41 | ····{ |
| 42 | ········Solution solution = null; |
| 43 | ········Project project = null; |
| 44 | ········Dictionary<string, NDOReference> references = null; |
| 45 | ········bool debug; |
| 46 | ········string binFile; |
| 47 | ········string objPath; |
| 48 | ········string projPath; |
| 49 | ········string assemblyName; |
| 50 | ········ConfigurationOptions options; |
| 51 | ········bool isWebProject; |
| 52 | ········string keyFile = string.Empty; |
| 53 | ········string platformTarget; |
| 54 | ········string targetFramework; |
| 55 | ········string version = "4.0"; |
| 56 | |
| 57 | #if DEBUG |
| 58 | ········MessageAdapter messageAdapter; |
| 59 | ········public MessageAdapter MessageAdapter |
| 60 | ········{ |
| 61 | ············get { return messageAdapter; } |
| 62 | ············set { messageAdapter = value; } |
| 63 | ········} |
| 64 | #endif |
| 65 | |
| 66 | ········public string TargetFramework |
| 67 | ········{ |
| 68 | ············get { return this.targetFramework; } |
| 69 | ········} |
| 70 | |
| 71 | ········public string PlatformTarget |
| 72 | ········{ |
| 73 | ············get { return this.platformTarget; } |
| 74 | ········} |
| 75 | |
| 76 | ········public string KeyFile |
| 77 | ········{ |
| 78 | ············get { return keyFile; } |
| 79 | ············set { keyFile = value; } |
| 80 | ········} |
| 81 | |
| 82 | ········public bool IsWebProject |
| 83 | ········{ |
| 84 | ············get { return isWebProject; } |
| 85 | ········} |
| 86 | |
| 87 | ········public ConfigurationOptions ConfigurationOptions |
| 88 | ········{ |
| 89 | ············get { return options; } |
| 90 | ········} |
| 91 | |
| 92 | ········public string AssemblyName |
| 93 | ········{ |
| 94 | ············get { return assemblyName; } |
| 95 | ············set { assemblyName = value; } |
| 96 | ········} |
| 97 | |
| 98 | ········public ConfigurationOptions NewConfigurationOptions() |
| 99 | ········{ |
| 100 | ············return new ConfigurationOptions(project); |
| 101 | ········} |
| 102 | |
| 103 | ········public ProjectDescription() |
| 104 | ········{ |
| 105 | ········} |
| 106 | |
| 107 | ········public ProjectDescription(string fileName) |
| 108 | ········{ |
| 109 | ············this.projPath = Path.GetDirectoryName(fileName) + Path.DirectorySeparatorChar; |
| 110 | ············XmlDocument doc = new XmlDocument(); |
| 111 | ············try |
| 112 | ············{ |
| 113 | ················doc.Load(fileName); |
| 114 | ············} |
| 115 | ············catch(XmlException ex) |
| 116 | ············{ |
| 117 | ················throw new Exception("Parameter file '" + fileName + "' is not a valid Xml file. Line: " + ex.LineNumber.ToString() + " Position: " + ex.LinePosition.ToString()); |
| 118 | ············} |
| 119 | ············XmlHelper.AddNamespace(doc); |
| 120 | ············Load(doc); |
| 121 | ············options = new ConfigurationOptions(doc); |
| 122 | ········} |
| 123 | |
| 124 | ········string AbsolutePath(string path) |
| 125 | ········{ |
| 126 | ············if (Path.IsPathRooted(path)) |
| 127 | ················return path; |
| 128 | ············else |
| 129 | ················return Path.Combine(projPath, path); |
| 130 | ········} |
| 131 | |
| 132 | ········void Load(XmlDocument doc) |
| 133 | ········{ |
| 134 | ············string pns = XmlHelper.Pns(doc); |
| 135 | |
| 136 | ············XmlNode node = doc.SelectSingleNode("//" + pns + "Enhancer/" + pns + "ProjectDescription", XmlHelper.Nsmgr); |
| 137 | ············if (node == null) |
| 138 | ················throw new Exception("Parameters must have at least one //Enhancer/ProjectDescription entry."); |
| 139 | |
| 140 | ············var vattr = ((XmlElement)node).Attributes["version"]; |
| 141 | ············if (vattr != null) |
| 142 | ················this.version = vattr.Value; |
| 143 | |
| 144 | ············binFile = AbsolutePath((string) XmlHelper.GetNode(node, pns + "BinPath")); |
| 145 | ············objPath = AbsolutePath((string) XmlHelper.GetNode(node, pns + "ObjPath")); |
| 146 | ············keyFile = (string)XmlHelper.GetNode(node, pns + "KeyFile", string.Empty); |
| 147 | |
| 148 | ············if (keyFile != string.Empty) |
| 149 | ················keyFile = AbsolutePath(keyFile); |
| 150 | ············ |
| 151 | ············assemblyName = (string)XmlHelper.GetNode(node, pns + "AssemblyName"); |
| 152 | ············debug = (bool) XmlHelper.GetNode(node, pns + "Debug", false); |
| 153 | ············isWebProject = (bool) XmlHelper.GetNode(node, pns + "IsWebProject", false); |
| 154 | ············XmlNodeList refList = doc.SelectNodes("//" + pns + "Enhancer/" + pns + "ProjectDescription/" + pns + "References/" + pns + "Reference", XmlHelper.Nsmgr); |
| 155 | ············references = new Dictionary<string, NDOReference>(); |
| 156 | ············foreach ( XmlNode rnode in refList ) |
| 157 | ············{ |
| 158 | ················string assName = (string) XmlHelper.GetAttribute(rnode, "AssemblyName"); |
| 159 | ················string assPath = AbsolutePath((string) XmlHelper.GetAttribute(rnode, "AssemblyPath")); |
| 160 | ················bool processDLL = true; |
| 161 | ················XmlAttribute attr = rnode.Attributes["CheckThisDLL"]; |
| 162 | ················if ( attr != null && string.Compare( attr.Value, "True", true ) != 0 ) |
| 163 | ····················processDLL = false; |
| 164 | |
| 165 | ················AddReference( assName, assPath, processDLL ); |
| 166 | ············} |
| 167 | ········} |
| 168 | |
| 169 | |
| 170 | ········private XmlNode MakeNode(string name, object value, XmlNode parentNode, XmlDocument doc) |
| 171 | ········{ |
| 172 | ············XmlElement el = doc.CreateElement(name); |
| 173 | ············parentNode.AppendChild(el); |
| 174 | ············if (value != null) |
| 175 | ················el.InnerText = value.ToString(); |
| 176 | ············return el; |
| 177 | ········} |
| 178 | |
| 179 | ········public async Task ToXmlAsync(XmlNode parent) |
| 180 | ········{ |
| 181 | ············XmlDocument doc = (XmlDocument) parent.ParentNode; |
| 182 | ············XmlNode node = doc.CreateElement("ProjectDescription"); |
| 183 | ············this.version = await NDOPackage.Instance.GetNdoVersionAsync( this.project ); |
| 184 | |
| 185 | ············( (XmlElement) node ).SetAttribute( "version", this.version ); |
| 186 | |
| 187 | ············parent.AppendChild(node); |
| 188 | ············string reference = this.projPath; |
| 189 | ············if (reference.EndsWith("\\")) |
| 190 | ················reference = reference.Substring(0, reference.Length - 1); |
| 191 | |
| 192 | ············MakeNode("BinPath", ExtendedPath.GetRelativePath(reference, binFile), node, doc); |
| 193 | ············MakeNode("ObjPath", ExtendedPath.GetRelativePath(reference, objPath), node, doc); |
| 194 | ············MakeNode("AssemblyName", assemblyName, node, doc); |
| 195 | ············MakeNode("Debug", debug, node, doc); |
| 196 | ············MakeNode("IsWebProject", isWebProject, node, doc); |
| 197 | ············MakeNode("KeyFile", keyFile, node, doc); |
| 198 | ············XmlNode refsNode = MakeNode("References", string.Empty, node, doc); |
| 199 | ············foreach ( string key in References.Keys ) |
| 200 | ············{ |
| 201 | ················NDOReference ndoreference = References[key]; |
| 202 | ················if ( ndoreference.Path == binFile ) |
| 203 | ····················continue; |
| 204 | ················XmlElement refNode = (XmlElement) MakeNode( "Reference", "", refsNode, doc ); |
| 205 | ················refNode.SetAttribute( "AssemblyName", ndoreference.Name ); |
| 206 | ················refNode.SetAttribute( "AssemblyPath", ExtendedPath.GetRelativePath( reference, ndoreference.Path ) ); |
| 207 | ················if ( !ndoreference.CheckThisDLL ) |
| 208 | ················{ |
| 209 | ····················refNode.SetAttribute( "CheckThisDLL", "False" ); |
| 210 | ················} |
| 211 | ············} |
| 212 | ········} |
| 213 | |
| 214 | ········string GetBuildProperty(IVsBuildPropertyStorage propertyStorage, string key, string configuration = "") |
| 215 | ········{ |
| 216 | ············string result = null; |
| 217 | ············if (propertyStorage != null) |
| 218 | ················propertyStorage.GetPropertyValue( key, configuration, (uint)_PersistStorageType.PST_PROJECT_FILE, out result ); |
| 219 | ············return result; |
| 220 | ········} |
| 221 | |
| 222 | ········public ProjectDescription( Project project ) |
| 223 | ········{ |
| 224 | ············this.solution = (Solution) project.Parent; |
| 225 | ············this.project = project; |
| 226 | |
| 227 | ············ThreadHelper.ThrowIfNotOnUIThread(); |
| 228 | ············var dteProj = project.DteProject(); |
| 229 | ············EnvDTE.Configuration conf = dteProj.ConfigurationManager.ActiveConfiguration; |
| 230 | ············//foreach (Property item in conf.Properties) |
| 231 | ············//{ |
| 232 | // SD. Debug. WriteLine( $"{ item. Name} = { item. Value} " ) ; |
| 233 | ············//} |
| 234 | |
| 235 | |
| 236 | ············// Get the MSBuild property storage |
| 237 | ············IVsBuildPropertyStorage propertyStorage = GetPropertyStorage( project ); |
| 238 | |
| 239 | ············try |
| 240 | ············{ |
| 241 | ················this.platformTarget = (string) conf.Properties.Item( "PlatformTarget" ).Value; |
| 242 | ············} |
| 243 | ············catch { } |
| 244 | ············try |
| 245 | ············{ |
| 246 | ················this.targetFramework = (string) dteProj.Properties.Item( "TargetFrameworkMoniker" ).Value; |
| 247 | ············} |
| 248 | ············catch { } |
| 249 | |
| 250 | |
| 251 | ············string outputPath = (string) conf.Properties.Item( "OutputPath" ).Value; |
| 252 | ············string fullPath = dteProj.Properties.Item( "FullPath" ).Value as string; |
| 253 | ············string outputFileName = GetBuildProperty( propertyStorage, "TargetFileName" ); |
| 254 | |
| 255 | ············if (String.IsNullOrEmpty( outputFileName )) |
| 256 | ············{ |
| 257 | ················int outputType = (int) dteProj.Properties.Item( "OutputType" ).Value; |
| 258 | ················// .NET Core Executables are dlls. |
| 259 | ················if (this.targetFramework.StartsWith( ".NETCoreApp" )) |
| 260 | ····················outputType = 2; |
| 261 | ················outputFileName = (string) dteProj.Properties.Item( "AssemblyName" ).Value + ( outputType == 2 ? ".dll" : ".exe" ); |
| 262 | ············} |
| 263 | |
| 264 | ············if (project.GetVsHierarchy().IsCapabilityMatch( "CPS" )) |
| 265 | ············{ |
| 266 | ················// new .csproj format |
| 267 | objPath = GetBuildProperty( propertyStorage, "IntermediateOutputPath" ) ; |
| 268 | ················string configuration = GetBuildProperty( propertyStorage, "Configuration" ); |
| 269 | ················debug = configuration == "Debug"; |
| 270 | ············} |
| 271 | ············else |
| 272 | ············{ |
| 273 | ················// old .csproj format |
| 274 | ················string debugInfo = (string) conf.Properties.Item( "DebugInfo" ).Value; |
| 275 | ················debug = debugInfo == "full"; |
| 276 | objPath = ( string) conf. Properties. Item( "IntermediatePath" ) . Value; |
| 277 | ············} |
| 278 | binFile = Path. Combine( fullPath, outputPath ) ; |
| 279 | ············binFile = Path.Combine( binFile, outputFileName ); |
| 280 | ············projPath = Path.GetDirectoryName( dteProj.FileName ) + "\\"; |
| 281 | ············string sign = GetBuildProperty( propertyStorage, "SignAssembly" ); |
| 282 | ············if (!String.IsNullOrEmpty( sign ) && String.Compare( sign, "true", true ) == 0) |
| 283 | ················keyFile = GetBuildProperty( propertyStorage, "AssemblyOriginatorKeyFile" ); |
| 284 | ············else |
| 285 | ················keyFile = null; |
| 286 | |
| 287 | ········} |
| 288 | |
| 289 | |
| 290 | ········private static IVsBuildPropertyStorage GetPropertyStorage( Project project ) |
| 291 | ········{ |
| 292 | ············ThreadHelper.ThrowIfNotOnUIThread(); |
| 293 | ············IVsHierarchy projectHierarchy = project.GetVsHierarchy(); |
| 294 | |
| 295 | ············return GetPropertyStorage( projectHierarchy ); |
| 296 | ········} |
| 297 | |
| 298 | ········private static IVsBuildPropertyStorage GetPropertyStorage( EnvDTE.Project project ) |
| 299 | ········{ |
| 300 | ············ThreadHelper.ThrowIfNotOnUIThread(); |
| 301 | ············IVsHierarchy projectHierarchy = project.GetVsHierarchy(); |
| 302 | |
| 303 | ············return GetPropertyStorage( projectHierarchy ); |
| 304 | ········} |
| 305 | |
| 306 | ········private static IVsBuildPropertyStorage GetPropertyStorage( IVsHierarchy projectHierarchy ) |
| 307 | ········{ |
| 308 | ············IVsBuildPropertyStorage propertyStorage = null; |
| 309 | |
| 310 | ············if (projectHierarchy != null) |
| 311 | ············{ |
| 312 | ················propertyStorage = (IVsBuildPropertyStorage) projectHierarchy; |
| 313 | ············} |
| 314 | |
| 315 | ············return propertyStorage; |
| 316 | ········} |
| 317 | |
| 318 | ········public string ObjPath |
| 319 | ········{ |
| 320 | ············get { return objPath; } |
| 321 | ············set { objPath = value; } |
| 322 | ········} |
| 323 | |
| 324 | ········public string BinFile |
| 325 | ········{ |
| 326 | ············get { return binFile; } |
| 327 | ············set { binFile = value; } |
| 328 | ········} |
| 329 | |
| 330 | ········public bool Debug |
| 331 | ········{ |
| 332 | ············get { return debug; } |
| 333 | ············set { debug = value; } |
| 334 | ········} |
| 335 | |
| 336 | ········public string ProjPath |
| 337 | ········{ |
| 338 | ············get { return projPath; } |
| 339 | ············set { projPath = value; } |
| 340 | ········} |
| 341 | |
| 342 | ········private void AddReference( string name, string path, bool checkThisDLL ) |
| 343 | ········{ |
| 344 | ············if ( !references.ContainsKey( name ) ) |
| 345 | ················references.Add( name, new NDOReference( name, path, checkThisDLL ) ); |
| 346 | ········} |
| 347 | |
| 348 | |
| 349 | ········public void BuildReferences() |
| 350 | ········{ |
| 351 | ············if (this.references != null) |
| 352 | ················return; |
| 353 | |
| 354 | ············this.references = new Dictionary<string,NDOReference>(); |
| 355 | ············var allProjects = new Dictionary<string, string>(); |
| 356 | ············var solution = ApplicationObject.VisualStudioApplication.Solution; |
| 357 | ············ |
| 358 | ············foreach(var p in new ProjectIterator(solution).Projects) |
| 359 | ············{ |
| 360 | ················if (p.Name == project.Name) continue; |
| 361 | ················EnvDTE.ConfigurationManager cman = p.ConfigurationManager; |
| 362 | ················if (cman == null) |
| 363 | ····················continue; |
| 364 | ················var········ conf = cman.ActiveConfiguration; |
| 365 | ················if (conf.Properties == null) |
| 366 | ····················continue; |
| 367 | ················try // Skip the project, if a property is not present |
| 368 | ················{ |
| 369 | ····················string outputPath = (string)conf.Properties.Item("OutputPath").Value; |
| 370 | ····················string fullPath = (string)p.Properties.Item("FullPath").Value; |
| 371 | ····················string outputFileName = GetBuildProperty( GetPropertyStorage(p), "TargetFileName" ); |
| 372 | ····················//messages.Output(fullPath + outputPath + outputFileName); |
| 373 | ····················if (!allProjects.ContainsKey(p.Name)) |
| 374 | ························allProjects.Add(p.Name, fullPath + outputPath + outputFileName); |
| 375 | ················} |
| 376 | ················catch { } |
| 377 | ············} |
| 378 | ············ |
| 379 | |
| 380 | ············foreach ( var r in this.project.References ) |
| 381 | ············{ |
| 382 | ················string rname = ""; |
| 383 | ················//if (r.SourceProject != null) |
| 384 | ················//····rname = r.SourceProject.Name; |
| 385 | ················//else |
| 386 | ················rname = r.Name; |
| 387 | ················if (rname == project.Name) continue; |
| 388 | |
| 389 | ················if (allProjects.ContainsKey( rname )) |
| 390 | ················{ |
| 391 | ····················AddReference( r.Name, (string) allProjects[rname], false ); |
| 392 | ················} |
| 393 | ················else |
| 394 | ················{ |
| 395 | ····················var vsRef = r.VsReference; |
| 396 | ····················var path = vsRef.FullPath; |
| 397 | ····················// Referenzen, die auf keine gültige DLL verweisen... |
| 398 | ····················if (!String.IsNullOrEmpty( path ) && NDOAssemblyChecker.IsEnhanced( path )) |
| 399 | ························AddReference( rname, path, false ); |
| 400 | ················} |
| 401 | ············} |
| 402 | //············AddReference(project.Name, this.binFile); |
| 403 | |
| 404 | ········} |
| 405 | |
| 406 | ········ProjectItems GetItemCollection(string fileName) |
| 407 | ········{ |
| 408 | ············string relPath = ExtendedPath.GetRelativePath(this.projPath, fileName); |
| 409 | ············var dteProj = project.DteProject(); |
| 410 | ············ProjectItems result = dteProj.ProjectItems; |
| 411 | ············if (relPath.IndexOf(":\\") > -1) |
| 412 | ················return result; |
| 413 | ············string[] splittedName = relPath.Split(new char[] { '\\' }); |
| 414 | ············for (int i = 0; i < splittedName.Length - 1; i++) |
| 415 | ············{ |
| 416 | ················string name = splittedName[i]; |
| 417 | ················ProjectItem pi = result.Item(name); |
| 418 | ················if (pi != null) |
| 419 | ····················result = pi.ProjectItems; |
| 420 | ················else |
| 421 | ····················break; |
| 422 | ············} |
| 423 | ············return result; |
| 424 | ········} |
| 425 | |
| 426 | ········public void FixDllState() |
| 427 | ········{ |
| 428 | ············// The package works with a transient version of the ProjectDescription, which will be saved |
| 429 | ············// after a successful Build. But we need the CheckThisDLL state from the saved version for the UI. |
| 430 | |
| 431 | ············var fileName = ConfigurationOptions.GetNdoProjFileName( project.FullPath ); |
| 432 | |
| 433 | ············if (!String.IsNullOrEmpty( fileName ) && File.Exists( fileName )) |
| 434 | ············{ |
| 435 | ················ProjectDescription storedDescription = new ProjectDescription( fileName ); |
| 436 | ················var storedReferences = storedDescription.references.Values.ToArray(); |
| 437 | ················foreach (var reference in this.references.Values) |
| 438 | ················{ |
| 439 | ····················var storedReference = storedReferences.FirstOrDefault( r => r.Name == reference.Name ); |
| 440 | ····················if (storedReference != null) |
| 441 | ····················{ |
| 442 | ························reference.CheckThisDLL = storedReference.CheckThisDLL; |
| 443 | ····················} |
| 444 | ················} |
| 445 | ············} |
| 446 | ········} |
| 447 | |
| 448 | ········public void AddFileToProject(string fileName) |
| 449 | ········{ |
| 450 | ············//TODO: Make the search hierarchical |
| 451 | ············if (project == null) |
| 452 | ················return; |
| 453 | ············if (!File.Exists(fileName)) |
| 454 | ················return; |
| 455 | ············bool found = false; |
| 456 | |
| 457 | ············ProjectItems itemCollection = GetItemCollection(fileName); |
| 458 | |
| 459 | ············foreach (ProjectItem pi in itemCollection) |
| 460 | ············{ |
| 461 | ················if (string.Compare(Path.GetFileName(pi.Name), Path.GetFileName(fileName), true) == 0) |
| 462 | ················{ |
| 463 | ····················found = true; |
| 464 | ····················break; |
| 465 | ················} |
| 466 | ············} |
| 467 | ············if (!found) |
| 468 | ············{ |
| 469 | #if DEBUG |
| 470 | ················messageAdapter.WriteLine("··Adding file to project: " + fileName); |
| 471 | #endif |
| 472 | ················this.project.DteProject().ProjectItems.AddFromFile(fileName); |
| 473 | ············} |
| 474 | ········} |
| 475 | |
| 476 | |
| 477 | ········public Dictionary<string, NDOReference> References |
| 478 | ········{ |
| 479 | ············get |
| 480 | ············{ |
| 481 | ················BuildReferences(); |
| 482 | ················return references; |
| 483 | ············} |
| 484 | ········} |
| 485 | |
| 486 | ····} |
| 487 | } |
| 488 |
New Commit (ecca4b4)
| 1 | // |
| 2 | // Copyright (c) 2002-2024 Mirko Matytschak |
| 3 | // (www.netdataobjects.de) |
| 4 | // |
| 5 | // Author: Mirko Matytschak |
| 6 | // |
| 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated |
| 8 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation |
| 9 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the |
| 10 | // Software, and to permit persons to whom the Software is furnished to do so, subject to the following |
| 11 | // conditions: |
| 12 | |
| 13 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions |
| 14 | // of the Software. |
| 15 | // |
| 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED |
| 17 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF |
| 19 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| 20 | // DEALINGS IN THE SOFTWARE. |
| 21 | |
| 22 | |
| 23 | using SD = System.Diagnostics; |
| 24 | using System.Xml; |
| 25 | using System.Collections.Generic; |
| 26 | using System.IO; |
| 27 | using Microsoft.VisualStudio.Shell.Interop; |
| 28 | using System.Linq; |
| 29 | using EnvDTE; |
| 30 | using Project = Community.VisualStudio.Toolkit.Project; |
| 31 | using Solution = Community.VisualStudio.Toolkit.Solution; |
| 32 | |
| 33 | namespace NDOVsPackage |
| 34 | { |
| 35 | |
| 36 | ····/// <summary> |
| 37 | ····/// ProjectDescription. |
| 38 | ····/// </summary> |
| 39 | ····[SD.CodeAnalysis.SuppressMessage( "Usage", "VSTHRD010:Invoke single-threaded types on Main thread", Justification = "This code always runs on the UI thread" )] |
| 40 | ····internal class ProjectDescription |
| 41 | ····{ |
| 42 | ········Solution solution = null; |
| 43 | ········Project project = null; |
| 44 | ········Dictionary<string, NDOReference> references = null; |
| 45 | ········bool debug; |
| 46 | ········string binFile; |
| 47 | ········string objPath; |
| 48 | ········string projPath; |
| 49 | ········string assemblyName; |
| 50 | ········ConfigurationOptions options; |
| 51 | ········bool isWebProject; |
| 52 | ········string keyFile = string.Empty; |
| 53 | ········string platformTarget; |
| 54 | ········string targetFramework; |
| 55 | ········string version = "4.0"; |
| 56 | |
| 57 | #if DEBUG |
| 58 | ········MessageAdapter messageAdapter; |
| 59 | ········public MessageAdapter MessageAdapter |
| 60 | ········{ |
| 61 | ············get { return messageAdapter; } |
| 62 | ············set { messageAdapter = value; } |
| 63 | ········} |
| 64 | #endif |
| 65 | |
| 66 | ········public string TargetFramework |
| 67 | ········{ |
| 68 | ············get { return this.targetFramework; } |
| 69 | ········} |
| 70 | |
| 71 | ········public string PlatformTarget |
| 72 | ········{ |
| 73 | ············get { return this.platformTarget; } |
| 74 | ········} |
| 75 | |
| 76 | ········public string KeyFile |
| 77 | ········{ |
| 78 | ············get { return keyFile; } |
| 79 | ············set { keyFile = value; } |
| 80 | ········} |
| 81 | |
| 82 | ········public bool IsWebProject |
| 83 | ········{ |
| 84 | ············get { return isWebProject; } |
| 85 | ········} |
| 86 | |
| 87 | ········public ConfigurationOptions ConfigurationOptions |
| 88 | ········{ |
| 89 | ············get { return options; } |
| 90 | ········} |
| 91 | |
| 92 | ········public string AssemblyName |
| 93 | ········{ |
| 94 | ············get { return assemblyName; } |
| 95 | ············set { assemblyName = value; } |
| 96 | ········} |
| 97 | |
| 98 | ········public ConfigurationOptions NewConfigurationOptions() |
| 99 | ········{ |
| 100 | ············return new ConfigurationOptions(project); |
| 101 | ········} |
| 102 | |
| 103 | ········public ProjectDescription() |
| 104 | ········{ |
| 105 | ········} |
| 106 | |
| 107 | ········public ProjectDescription(string fileName) |
| 108 | ········{ |
| 109 | ············this.projPath = Path.GetDirectoryName(fileName) + Path.DirectorySeparatorChar; |
| 110 | ············XmlDocument doc = new XmlDocument(); |
| 111 | ············try |
| 112 | ············{ |
| 113 | ················doc.Load(fileName); |
| 114 | ············} |
| 115 | ············catch(XmlException ex) |
| 116 | ············{ |
| 117 | ················throw new Exception("Parameter file '" + fileName + "' is not a valid Xml file. Line: " + ex.LineNumber.ToString() + " Position: " + ex.LinePosition.ToString()); |
| 118 | ············} |
| 119 | ············XmlHelper.AddNamespace(doc); |
| 120 | ············Load(doc); |
| 121 | ············options = new ConfigurationOptions(doc); |
| 122 | ········} |
| 123 | |
| 124 | ········string AbsolutePath(string path) |
| 125 | ········{ |
| 126 | ············if (Path.IsPathRooted(path)) |
| 127 | ················return path; |
| 128 | ············else |
| 129 | ················return Path.Combine(projPath, path); |
| 130 | ········} |
| 131 | |
| 132 | ········void Load(XmlDocument doc) |
| 133 | ········{ |
| 134 | ············string pns = XmlHelper.Pns(doc); |
| 135 | |
| 136 | ············XmlNode node = doc.SelectSingleNode("//" + pns + "Enhancer/" + pns + "ProjectDescription", XmlHelper.Nsmgr); |
| 137 | ············if (node == null) |
| 138 | ················throw new Exception("Parameters must have at least one //Enhancer/ProjectDescription entry."); |
| 139 | |
| 140 | ············var vattr = ((XmlElement)node).Attributes["version"]; |
| 141 | ············if (vattr != null) |
| 142 | ················this.version = vattr.Value; |
| 143 | |
| 144 | ············binFile = AbsolutePath((string) XmlHelper.GetNode(node, pns + "BinPath")); |
| 145 | ············objPath = AbsolutePath((string) XmlHelper.GetNode(node, pns + "ObjPath")); |
| 146 | ············keyFile = (string)XmlHelper.GetNode(node, pns + "KeyFile", string.Empty); |
| 147 | |
| 148 | ············if (keyFile != string.Empty) |
| 149 | ················keyFile = AbsolutePath(keyFile); |
| 150 | ············ |
| 151 | ············assemblyName = (string)XmlHelper.GetNode(node, pns + "AssemblyName"); |
| 152 | ············debug = (bool) XmlHelper.GetNode(node, pns + "Debug", false); |
| 153 | ············isWebProject = (bool) XmlHelper.GetNode(node, pns + "IsWebProject", false); |
| 154 | ············XmlNodeList refList = doc.SelectNodes("//" + pns + "Enhancer/" + pns + "ProjectDescription/" + pns + "References/" + pns + "Reference", XmlHelper.Nsmgr); |
| 155 | ············references = new Dictionary<string, NDOReference>(); |
| 156 | ············foreach ( XmlNode rnode in refList ) |
| 157 | ············{ |
| 158 | ················string assName = (string) XmlHelper.GetAttribute(rnode, "AssemblyName"); |
| 159 | ················string assPath = AbsolutePath((string) XmlHelper.GetAttribute(rnode, "AssemblyPath")); |
| 160 | ················bool processDLL = true; |
| 161 | ················XmlAttribute attr = rnode.Attributes["CheckThisDLL"]; |
| 162 | ················if ( attr != null && string.Compare( attr.Value, "True", true ) != 0 ) |
| 163 | ····················processDLL = false; |
| 164 | |
| 165 | ················AddReference( assName, assPath, processDLL ); |
| 166 | ············} |
| 167 | ········} |
| 168 | |
| 169 | |
| 170 | ········private XmlNode MakeNode(string name, object value, XmlNode parentNode, XmlDocument doc) |
| 171 | ········{ |
| 172 | ············XmlElement el = doc.CreateElement(name); |
| 173 | ············parentNode.AppendChild(el); |
| 174 | ············if (value != null) |
| 175 | ················el.InnerText = value.ToString(); |
| 176 | ············return el; |
| 177 | ········} |
| 178 | |
| 179 | ········public async Task ToXmlAsync(XmlNode parent) |
| 180 | ········{ |
| 181 | ············XmlDocument doc = (XmlDocument) parent.ParentNode; |
| 182 | ············XmlNode node = doc.CreateElement("ProjectDescription"); |
| 183 | ············this.version = await NDOPackage.Instance.GetNdoVersionAsync( this.project ); |
| 184 | |
| 185 | ············( (XmlElement) node ).SetAttribute( "version", this.version ); |
| 186 | |
| 187 | ············parent.AppendChild(node); |
| 188 | ············string reference = this.projPath; |
| 189 | ············if (reference.EndsWith("\\")) |
| 190 | ················reference = reference.Substring(0, reference.Length - 1); |
| 191 | |
| 192 | ············MakeNode("BinPath", ExtendedPath.GetRelativePath(reference, binFile), node, doc); |
| 193 | ············MakeNode("ObjPath", ExtendedPath.GetRelativePath(reference, objPath), node, doc); |
| 194 | ············MakeNode("AssemblyName", assemblyName, node, doc); |
| 195 | ············MakeNode("Debug", debug, node, doc); |
| 196 | ············MakeNode("IsWebProject", isWebProject, node, doc); |
| 197 | ············MakeNode("KeyFile", keyFile, node, doc); |
| 198 | ············XmlNode refsNode = MakeNode("References", string.Empty, node, doc); |
| 199 | ············foreach ( string key in References.Keys ) |
| 200 | ············{ |
| 201 | ················NDOReference ndoreference = References[key]; |
| 202 | ················if ( ndoreference.Path == binFile ) |
| 203 | ····················continue; |
| 204 | ················XmlElement refNode = (XmlElement) MakeNode( "Reference", "", refsNode, doc ); |
| 205 | ················refNode.SetAttribute( "AssemblyName", ndoreference.Name ); |
| 206 | ················refNode.SetAttribute( "AssemblyPath", ExtendedPath.GetRelativePath( reference, ndoreference.Path ) ); |
| 207 | ················if ( !ndoreference.CheckThisDLL ) |
| 208 | ················{ |
| 209 | ····················refNode.SetAttribute( "CheckThisDLL", "False" ); |
| 210 | ················} |
| 211 | ············} |
| 212 | ········} |
| 213 | |
| 214 | ········string GetBuildProperty(IVsBuildPropertyStorage propertyStorage, string key, string configuration = "") |
| 215 | ········{ |
| 216 | ············string result = null; |
| 217 | ············if (propertyStorage != null) |
| 218 | ················propertyStorage.GetPropertyValue( key, configuration, (uint)_PersistStorageType.PST_PROJECT_FILE, out result ); |
| 219 | ············return result; |
| 220 | ········} |
| 221 | |
| 222 | ········public ProjectDescription( Project project ) |
| 223 | ········{ |
| 224 | ············this.solution = (Solution) project.Parent; |
| 225 | ············this.project = project; |
| 226 | |
| 227 | ············ThreadHelper.ThrowIfNotOnUIThread(); |
| 228 | ············var dteProj = project.DteProject(); |
| 229 | ············EnvDTE.Configuration conf = dteProj.ConfigurationManager.ActiveConfiguration; |
| 230 | ············//var props = new Dictionary<string,object>(); |
| 231 | ············//foreach (Property item in conf.Properties) |
| 232 | ············//{ |
| 233 | ············//····object value = "-"; |
| 234 | ············//····try |
| 235 | ············//····{ |
| 236 | ············//········value = item.Value; |
| 237 | ············//········props.Add( item.Name, value ); |
| 238 | ············//····} |
| 239 | ············//····catch(Exception ex) |
| 240 | ············//····{ } |
| 241 | ············//} |
| 242 | |
| 243 | ············//foreach (Property item in dteProj.Properties) |
| 244 | ············//{ |
| 245 | // object value = "-"; |
| 246 | ············//····try |
| 247 | ············//····{ |
| 248 | ············//········value = item.Value; |
| 249 | ············//········props.Add( item.Name, value ); |
| 250 | ············//····} |
| 251 | ············//····catch (Exception ex) |
| 252 | ············//····{ } |
| 253 | ············//} |
| 254 | |
| 255 | ············//foreach (var item in props) |
| 256 | ············//{ |
| 257 | ············//····SD.Debug.WriteLine( $"{item.Key} = {item.Value}" ); |
| 258 | ············//} |
| 259 | |
| 260 | ············// Get the MSBuild property storage |
| 261 | ············ThreadHelper.JoinableTaskFactory.Run( async () => this.version = await NDOPackage.Instance.GetNdoVersionAsync( this.project ) ); |
| 262 | ············Version.TryParse( this.version, out var ndoprojVersion ); |
| 263 | ············var friendlyTargetFramework = (string)dteProj.Properties.Item("FriendlyTargetFramework").Value; |
| 264 | |
| 265 | ············IVsBuildPropertyStorage propertyStorage = GetPropertyStorage( project ); |
| 266 | |
| 267 | ············try |
| 268 | ············{ |
| 269 | ················this.platformTarget = (string) conf.Properties.Item( "PlatformTarget" ).Value; |
| 270 | ············} |
| 271 | ············catch { } |
| 272 | ············try |
| 273 | ············{ |
| 274 | ················this.targetFramework = (string) dteProj.Properties.Item( "TargetFrameworkMoniker" ).Value; |
| 275 | ············} |
| 276 | ············catch { } |
| 277 | |
| 278 | ············string outputPath = (string) conf.Properties.Item( "OutputPath" ).Value; |
| 279 | ············string fullPath = dteProj.Properties.Item( "FullPath" ).Value as string; |
| 280 | ············string outputFileName = GetBuildProperty( propertyStorage, "TargetFileName" ); |
| 281 | |
| 282 | ············if (String.IsNullOrEmpty( outputFileName )) |
| 283 | ············{ |
| 284 | ················int outputType = (int) dteProj.Properties.Item( "OutputType" ).Value; |
| 285 | ················// .NET Core Executables are dlls. |
| 286 | ················if (this.targetFramework.StartsWith( ".NETCoreApp" )) |
| 287 | ····················outputType = 2; |
| 288 | ················outputFileName = (string) dteProj.Properties.Item( "AssemblyName" ).Value + ( outputType == 2 ? ".dll" : ".exe" ); |
| 289 | ············} |
| 290 | |
| 291 | ············if (project.GetVsHierarchy().IsCapabilityMatch( "CPS" )) |
| 292 | ············{ |
| 293 | ················// new .csproj format |
| 294 | this. objPath = GetBuildProperty( propertyStorage, "IntermediateOutputPath" ) ; |
| 295 | ················string configuration = GetBuildProperty( propertyStorage, "Configuration" ); |
| 296 | ················debug = configuration == "Debug"; |
| 297 | ············} |
| 298 | ············else |
| 299 | ············{ |
| 300 | ················// old .csproj format |
| 301 | ················string debugInfo = (string) conf.Properties.Item( "DebugInfo" ).Value; |
| 302 | ················debug = debugInfo == "full"; |
| 303 | this. objPath = ( string) conf. Properties. Item( "IntermediatePath" ) . Value; |
| 304 | ············} |
| 305 | ············this.binFile = Path.Combine( fullPath, outputPath ); |
| 306 | ············this.binFile = Path.Combine( binFile, outputFileName ); |
| 307 | ············this.projPath = Path.GetDirectoryName( dteProj.FileName ) + "\\"; |
| 308 | |
| 309 | ············if (ndoprojVersion.Major >= 5) |
| 310 | ············{ |
| 311 | ················this.binFile = this.binFile.Replace( friendlyTargetFramework, "$(TargetFramework)" ); |
| 312 | ················this.objPath = this.objPath.Replace(friendlyTargetFramework, "$(TargetFramework)" ); |
| 313 | ············} |
| 314 | |
| 315 | ············string sign = GetBuildProperty( propertyStorage, "SignAssembly" ); |
| 316 | ············if (!String.IsNullOrEmpty( sign ) && String.Compare( sign, "true", true ) == 0) |
| 317 | ················keyFile = GetBuildProperty( propertyStorage, "AssemblyOriginatorKeyFile" ); |
| 318 | ············else |
| 319 | ················keyFile = null; |
| 320 | |
| 321 | ········} |
| 322 | |
| 323 | |
| 324 | ········private static IVsBuildPropertyStorage GetPropertyStorage( Project project ) |
| 325 | ········{ |
| 326 | ············ThreadHelper.ThrowIfNotOnUIThread(); |
| 327 | ············IVsHierarchy projectHierarchy = project.GetVsHierarchy(); |
| 328 | |
| 329 | ············return GetPropertyStorage( projectHierarchy ); |
| 330 | ········} |
| 331 | |
| 332 | ········private static IVsBuildPropertyStorage GetPropertyStorage( EnvDTE.Project project ) |
| 333 | ········{ |
| 334 | ············ThreadHelper.ThrowIfNotOnUIThread(); |
| 335 | ············IVsHierarchy projectHierarchy = project.GetVsHierarchy(); |
| 336 | |
| 337 | ············return GetPropertyStorage( projectHierarchy ); |
| 338 | ········} |
| 339 | |
| 340 | ········private static IVsBuildPropertyStorage GetPropertyStorage( IVsHierarchy projectHierarchy ) |
| 341 | ········{ |
| 342 | ············IVsBuildPropertyStorage propertyStorage = null; |
| 343 | |
| 344 | ············if (projectHierarchy != null) |
| 345 | ············{ |
| 346 | ················propertyStorage = (IVsBuildPropertyStorage) projectHierarchy; |
| 347 | ············} |
| 348 | |
| 349 | ············return propertyStorage; |
| 350 | ········} |
| 351 | |
| 352 | ········public string ObjPath |
| 353 | ········{ |
| 354 | ············get { return objPath; } |
| 355 | ············set { objPath = value; } |
| 356 | ········} |
| 357 | |
| 358 | ········public string BinFile |
| 359 | ········{ |
| 360 | ············get { return binFile; } |
| 361 | ············set { binFile = value; } |
| 362 | ········} |
| 363 | |
| 364 | ········public bool Debug |
| 365 | ········{ |
| 366 | ············get { return debug; } |
| 367 | ············set { debug = value; } |
| 368 | ········} |
| 369 | |
| 370 | ········public string ProjPath |
| 371 | ········{ |
| 372 | ············get { return projPath; } |
| 373 | ············set { projPath = value; } |
| 374 | ········} |
| 375 | |
| 376 | ········private void AddReference( string name, string path, bool checkThisDLL ) |
| 377 | ········{ |
| 378 | ············if ( !references.ContainsKey( name ) ) |
| 379 | ················references.Add( name, new NDOReference( name, path, checkThisDLL ) ); |
| 380 | ········} |
| 381 | |
| 382 | |
| 383 | ········public void BuildReferences() |
| 384 | ········{ |
| 385 | ············if (this.references != null) |
| 386 | ················return; |
| 387 | |
| 388 | ············this.references = new Dictionary<string,NDOReference>(); |
| 389 | ············var allProjects = new Dictionary<string, string>(); |
| 390 | ············var solution = ApplicationObject.VisualStudioApplication.Solution; |
| 391 | ············ |
| 392 | ············foreach(var p in new ProjectIterator(solution).Projects) |
| 393 | ············{ |
| 394 | ················if (p.Name == project.Name) continue; |
| 395 | ················EnvDTE.ConfigurationManager cman = p.ConfigurationManager; |
| 396 | ················if (cman == null) |
| 397 | ····················continue; |
| 398 | ················var········ conf = cman.ActiveConfiguration; |
| 399 | ················if (conf.Properties == null) |
| 400 | ····················continue; |
| 401 | ················try // Skip the project, if a property is not present |
| 402 | ················{ |
| 403 | ····················string outputPath = (string)conf.Properties.Item("OutputPath").Value; |
| 404 | ····················string fullPath = (string)p.Properties.Item("FullPath").Value; |
| 405 | ····················string outputFileName = GetBuildProperty( GetPropertyStorage(p), "TargetFileName" ); |
| 406 | ····················//messages.Output(fullPath + outputPath + outputFileName); |
| 407 | ····················if (!allProjects.ContainsKey(p.Name)) |
| 408 | ························allProjects.Add(p.Name, fullPath + outputPath + outputFileName); |
| 409 | ················} |
| 410 | ················catch { } |
| 411 | ············} |
| 412 | ············ |
| 413 | |
| 414 | ············foreach ( var r in this.project.References ) |
| 415 | ············{ |
| 416 | ················string rname = ""; |
| 417 | ················//if (r.SourceProject != null) |
| 418 | ················//····rname = r.SourceProject.Name; |
| 419 | ················//else |
| 420 | ················rname = r.Name; |
| 421 | ················if (rname == project.Name) continue; |
| 422 | |
| 423 | ················if (allProjects.ContainsKey( rname )) |
| 424 | ················{ |
| 425 | ····················AddReference( r.Name, (string) allProjects[rname], false ); |
| 426 | ················} |
| 427 | ················else |
| 428 | ················{ |
| 429 | ····················var vsRef = r.VsReference; |
| 430 | ····················var path = vsRef.FullPath; |
| 431 | ····················// Referenzen, die auf keine gültige DLL verweisen... |
| 432 | ····················if (!String.IsNullOrEmpty( path ) && NDOAssemblyChecker.IsEnhanced( path )) |
| 433 | ························AddReference( rname, path, false ); |
| 434 | ················} |
| 435 | ············} |
| 436 | //············AddReference(project.Name, this.binFile); |
| 437 | |
| 438 | ········} |
| 439 | |
| 440 | ········ProjectItems GetItemCollection(string fileName) |
| 441 | ········{ |
| 442 | ············string relPath = ExtendedPath.GetRelativePath(this.projPath, fileName); |
| 443 | ············var dteProj = project.DteProject(); |
| 444 | ············ProjectItems result = dteProj.ProjectItems; |
| 445 | ············if (relPath.IndexOf(":\\") > -1) |
| 446 | ················return result; |
| 447 | ············string[] splittedName = relPath.Split(new char[] { '\\' }); |
| 448 | ············for (int i = 0; i < splittedName.Length - 1; i++) |
| 449 | ············{ |
| 450 | ················string name = splittedName[i]; |
| 451 | ················ProjectItem pi = result.Item(name); |
| 452 | ················if (pi != null) |
| 453 | ····················result = pi.ProjectItems; |
| 454 | ················else |
| 455 | ····················break; |
| 456 | ············} |
| 457 | ············return result; |
| 458 | ········} |
| 459 | |
| 460 | ········public void FixDllState() |
| 461 | ········{ |
| 462 | ············// The package works with a transient version of the ProjectDescription, which will be saved |
| 463 | ············// after a successful Build. But we need the CheckThisDLL state from the saved version for the UI. |
| 464 | |
| 465 | ············var fileName = ConfigurationOptions.GetNdoProjFileName( project.FullPath ); |
| 466 | |
| 467 | ············if (!String.IsNullOrEmpty( fileName ) && File.Exists( fileName )) |
| 468 | ············{ |
| 469 | ················ProjectDescription storedDescription = new ProjectDescription( fileName ); |
| 470 | ················var storedReferences = storedDescription.references.Values.ToArray(); |
| 471 | ················foreach (var reference in this.references.Values) |
| 472 | ················{ |
| 473 | ····················var storedReference = storedReferences.FirstOrDefault( r => r.Name == reference.Name ); |
| 474 | ····················if (storedReference != null) |
| 475 | ····················{ |
| 476 | ························reference.CheckThisDLL = storedReference.CheckThisDLL; |
| 477 | ····················} |
| 478 | ················} |
| 479 | ············} |
| 480 | ········} |
| 481 | |
| 482 | ········public void AddFileToProject(string fileName) |
| 483 | ········{ |
| 484 | ············//TODO: Make the search hierarchical |
| 485 | ············if (project == null) |
| 486 | ················return; |
| 487 | ············if (!File.Exists(fileName)) |
| 488 | ················return; |
| 489 | ············bool found = false; |
| 490 | |
| 491 | ············ProjectItems itemCollection = GetItemCollection(fileName); |
| 492 | |
| 493 | ············foreach (ProjectItem pi in itemCollection) |
| 494 | ············{ |
| 495 | ················if (string.Compare(Path.GetFileName(pi.Name), Path.GetFileName(fileName), true) == 0) |
| 496 | ················{ |
| 497 | ····················found = true; |
| 498 | ····················break; |
| 499 | ················} |
| 500 | ············} |
| 501 | ············if (!found) |
| 502 | ············{ |
| 503 | #if DEBUG |
| 504 | ················messageAdapter.WriteLine("··Adding file to project: " + fileName); |
| 505 | #endif |
| 506 | ················this.project.DteProject().ProjectItems.AddFromFile(fileName); |
| 507 | ············} |
| 508 | ········} |
| 509 | |
| 510 | |
| 511 | ········public Dictionary<string, NDOReference> References |
| 512 | ········{ |
| 513 | ············get |
| 514 | ············{ |
| 515 | ················BuildReferences(); |
| 516 | ················return references; |
| 517 | ············} |
| 518 | ········} |
| 519 | |
| 520 | ····} |
| 521 | } |
| 522 |