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