OLD | NEW |
| (Empty) |
1 /// Copyright (c) Microsoft Corporation. All rights reserved. | |
2 | |
3 using System; | |
4 using System.Collections.Generic; | |
5 using System.Diagnostics; | |
6 using System.Diagnostics.CodeAnalysis; | |
7 using System.Runtime.InteropServices; | |
8 using Microsoft.VisualStudio; | |
9 using Microsoft.VisualStudio.Shell.Interop; | |
10 using MSBuild = Microsoft.Build.BuildEngine; | |
11 | |
12 namespace Microsoft.VisualStudio.Project | |
13 { | |
14 /// <summary> | |
15 /// Allows projects to group outputs according to usage. | |
16 /// </summary> | |
17 [CLSCompliant(false), ComVisible(true)] | |
18 public class OutputGroup : IVsOutputGroup2 | |
19 { | |
20 #region fields | |
21 private ProjectConfig projectCfg; | |
22 private ProjectNode project; | |
23 | |
24 private List<Output> outputs = new List<Output>(); | |
25 private Output keyOutput; | |
26 private string name; | |
27 private string targetName; | |
28 #endregion | |
29 | |
30 #region properties | |
31 /// <summary> | |
32 /// Get the project configuration object associated with this ou
tput group | |
33 /// </summary> | |
34 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "Cfg")] | |
35 protected ProjectConfig ProjectCfg | |
36 { | |
37 get { return projectCfg; } | |
38 } | |
39 | |
40 /// <summary> | |
41 /// Get the project object that produces this output group. | |
42 /// </summary> | |
43 protected ProjectNode Project | |
44 { | |
45 get { return project; } | |
46 } | |
47 | |
48 /// <summary> | |
49 /// Gets the msbuild target name which is assciated to the outpu
tgroup. | |
50 /// ProjectNode defines a static collection of output group name
s and their associated MsBuild target | |
51 /// </summary> | |
52 protected string TargetName | |
53 { | |
54 get { return targetName; } | |
55 } | |
56 #endregion | |
57 | |
58 #region ctors | |
59 | |
60 /// <summary> | |
61 /// Constructor for IVSOutputGroup2 implementation | |
62 /// </summary> | |
63 /// <param name="outputName">Name of the output group. See VS_OU
TPUTGROUP_CNAME_Build in vsshell.idl for the list of standard values</param> | |
64 /// <param name="msBuildTargetName">MSBuild target name</param> | |
65 /// <param name="projectManager">Project that produce this outpu
t</param> | |
66 /// <param name="configuration">Configuration that produce this
output</param> | |
67 public OutputGroup(string outputName, string msBuildTargetName,
ProjectNode projectManager, ProjectConfig configuration) | |
68 { | |
69 if(outputName == null) | |
70 throw new ArgumentNullException("outputName"); | |
71 if(msBuildTargetName == null) | |
72 throw new ArgumentNullException("outputName"); | |
73 if(projectManager == null) | |
74 throw new ArgumentNullException("projectManager"
); | |
75 if(configuration == null) | |
76 throw new ArgumentNullException("configuration")
; | |
77 | |
78 name = outputName; | |
79 targetName = msBuildTargetName; | |
80 project = projectManager; | |
81 projectCfg = configuration; | |
82 } | |
83 #endregion | |
84 | |
85 #region virtual methods | |
86 protected virtual void Refresh() | |
87 { | |
88 // Let MSBuild know which configuration we are working w
ith | |
89 project.SetConfiguration(projectCfg.ConfigName); | |
90 | |
91 // Generate dependencies if such a task exist | |
92 const string generateDependencyList = "AllProjectOutputG
roups"; | |
93 if(project.BuildProject.Targets.Exists(generateDependenc
yList)) | |
94 { | |
95 bool succeeded = false; | |
96 project.BuildTarget(generateDependencyList, out
succeeded); | |
97 Debug.Assert(succeeded, "Failed to build target:
" + generateDependencyList); | |
98 } | |
99 | |
100 // Rebuild the content of our list of output | |
101 string outputType = this.targetName + "KeyOutput"; | |
102 this.outputs.Clear(); | |
103 foreach(MSBuild.BuildItem assembly in project.BuildProje
ct.GetEvaluatedItemsByName(outputType)) | |
104 { | |
105 Output output = new Output(project, project.GetP
rojectElement(assembly)); | |
106 this.outputs.Add(output); | |
107 | |
108 // See if it is our key output | |
109 if(String.Compare(assembly.GetEvaluatedMetadata(
"IsKeyOutput"), true.ToString(), StringComparison.OrdinalIgnoreCase) == 0) | |
110 keyOutput = output; | |
111 } | |
112 | |
113 project.SetCurrentConfiguration(); | |
114 | |
115 // Now that the group is built we have to check if it is
invalidated by a property | |
116 // change on the project. | |
117 project.OnProjectPropertyChanged += new EventHandler<Pro
jectPropertyChangedArgs>(OnProjectPropertyChanged); | |
118 } | |
119 | |
120 public virtual void InvalidateGroup() | |
121 { | |
122 // Set keyOutput to null so that a refresh will be perfo
rmed the next time | |
123 // a property getter is called. | |
124 if(null != keyOutput) | |
125 { | |
126 // Once the group is invalidated there is no mor
e reason to listen for events. | |
127 project.OnProjectPropertyChanged -= new EventHan
dler<ProjectPropertyChangedArgs>(OnProjectPropertyChanged); | |
128 } | |
129 keyOutput = null; | |
130 } | |
131 #endregion | |
132 | |
133 #region event handlers | |
134 private void OnProjectPropertyChanged(object sender, ProjectProp
ertyChangedArgs args) | |
135 { | |
136 // In theory here we should decide if we have to invalid
ate the group according with the kind of property | |
137 // that is changed. | |
138 InvalidateGroup(); | |
139 } | |
140 #endregion | |
141 | |
142 #region IVsOutputGroup2 Members | |
143 | |
144 public virtual int get_CanonicalName(out string pbstrCanonicalNa
me) | |
145 { | |
146 pbstrCanonicalName = this.name; | |
147 return VSConstants.S_OK; | |
148 } | |
149 | |
150 public virtual int get_DeployDependencies(uint celt, IVsDeployDe
pendency[] rgpdpd, uint[] pcActual) | |
151 { | |
152 return VSConstants.E_NOTIMPL; | |
153 } | |
154 | |
155 public virtual int get_Description(out string pbstrDescription) | |
156 { | |
157 pbstrDescription = null; | |
158 | |
159 string description; | |
160 int hr = this.get_CanonicalName(out description); | |
161 if(ErrorHandler.Succeeded(hr)) | |
162 pbstrDescription = this.Project.GetOutputGroupDe
scription(description); | |
163 return hr; | |
164 } | |
165 | |
166 public virtual int get_DisplayName(out string pbstrDisplayName) | |
167 { | |
168 pbstrDisplayName = null; | |
169 | |
170 string displayName; | |
171 int hr = this.get_CanonicalName(out displayName); | |
172 if(ErrorHandler.Succeeded(hr)) | |
173 pbstrDisplayName = this.Project.GetOutputGroupDi
splayName(displayName); | |
174 return hr; | |
175 } | |
176 | |
177 public virtual int get_KeyOutput(out string pbstrCanonicalName) | |
178 { | |
179 pbstrCanonicalName = null; | |
180 if(keyOutput == null) | |
181 Refresh(); | |
182 if(keyOutput == null) | |
183 { | |
184 pbstrCanonicalName = String.Empty; | |
185 return VSConstants.S_FALSE; | |
186 } | |
187 return keyOutput.get_CanonicalName(out pbstrCanonicalNam
e); | |
188 } | |
189 | |
190 public virtual int get_KeyOutputObject(out IVsOutput2 ppKeyOutpu
t) | |
191 { | |
192 if(keyOutput == null) | |
193 Refresh(); | |
194 ppKeyOutput = keyOutput; | |
195 if(ppKeyOutput == null) | |
196 return VSConstants.S_FALSE; | |
197 return VSConstants.S_OK; | |
198 } | |
199 | |
200 public virtual int get_Outputs(uint celt, IVsOutput2[] rgpcfg, u
int[] pcActual) | |
201 { | |
202 // Ensure that we are refreshed. This is somewhat of a
hack that enables project to | |
203 // project reference scenarios to work. Normally, outpu
t groups are populated as part | |
204 // of build. However, in the project to project referen
ce case, what ends up happening | |
205 // is that the referencing projects requests the referen
ced project's output group | |
206 // before a build is done on the referenced project. | |
207 // | |
208 // Furthermore, the project auto toolbox manager require
s output groups to be populated | |
209 // on project reopen as well... | |
210 // | |
211 // In the end, this is probably the right thing to do, t
hough -- as it keeps the output | |
212 // groups always up to date. | |
213 Refresh(); | |
214 | |
215 // See if only the caller only wants to know the count | |
216 if(celt == 0 || rgpcfg == null) | |
217 { | |
218 if(pcActual != null && pcActual.Length > 0) | |
219 pcActual[0] = (uint)outputs.Count; | |
220 return VSConstants.S_OK; | |
221 } | |
222 | |
223 // Fill the array with our outputs | |
224 uint count = 0; | |
225 foreach(Output output in outputs) | |
226 { | |
227 if(rgpcfg.Length > count && celt > count && outp
ut != null) | |
228 { | |
229 rgpcfg[count] = output; | |
230 ++count; | |
231 } | |
232 } | |
233 | |
234 if(pcActual != null && pcActual.Length > 0) | |
235 pcActual[0] = count; | |
236 | |
237 // If the number asked for does not match the number ret
urned, return S_FALSE | |
238 return (count == celt) ? VSConstants.S_OK : VSConstants.
S_FALSE; | |
239 } | |
240 | |
241 public virtual int get_ProjectCfg(out IVsProjectCfg2 ppIVsProjec
tCfg2) | |
242 { | |
243 ppIVsProjectCfg2 = (IVsProjectCfg2)this.projectCfg; | |
244 return VSConstants.S_OK; | |
245 } | |
246 | |
247 public virtual int get_Property(string pszProperty, out object p
var) | |
248 { | |
249 pvar = project.GetProjectProperty(pszProperty); | |
250 return VSConstants.S_OK; | |
251 } | |
252 | |
253 #endregion | |
254 } | |
255 } | |
OLD | NEW |