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 |