OLD | NEW |
| (Empty) |
1 /// Copyright (c) Microsoft Corporation. All rights reserved. | |
2 | |
3 using System; | |
4 using System.Globalization; | |
5 using System.IO; | |
6 using System.Runtime.InteropServices; | |
7 using EnvDTE; | |
8 using Microsoft.VisualStudio; | |
9 using Microsoft.VisualStudio.Shell.Interop; | |
10 | |
11 namespace Microsoft.VisualStudio.Project.Automation | |
12 { | |
13 [ComVisible(true), CLSCompliant(false)] | |
14 public class OAProject : EnvDTE.Project, EnvDTE.ISupportVSProperties | |
15 { | |
16 #region fields | |
17 private ProjectNode project; | |
18 EnvDTE.ConfigurationManager configurationManager; | |
19 #endregion | |
20 | |
21 #region properties | |
22 public ProjectNode Project | |
23 { | |
24 get { return this.project; } | |
25 } | |
26 #endregion | |
27 | |
28 #region ctor | |
29 public OAProject(ProjectNode project) | |
30 { | |
31 this.project = project; | |
32 } | |
33 #endregion | |
34 | |
35 #region EnvDTE.Project | |
36 /// <summary> | |
37 /// Gets or sets the name of the object. | |
38 /// </summary> | |
39 public virtual string Name | |
40 { | |
41 get | |
42 { | |
43 return project.Caption; | |
44 } | |
45 set | |
46 { | |
47 if(this.project == null || this.project.Site ==
null || this.project.IsClosed) | |
48 { | |
49 throw new InvalidOperationException(); | |
50 } | |
51 | |
52 using(AutomationScope scope = new AutomationScop
e(this.project.Site)) | |
53 { | |
54 project.SetEditLabel(value); | |
55 } | |
56 } | |
57 } | |
58 | |
59 /// <summary> | |
60 /// Microsoft Internal Use Only. Gets the file name of the proj
ect. | |
61 /// </summary> | |
62 public virtual string FileName | |
63 { | |
64 get | |
65 { | |
66 return project.ProjectFile; | |
67 } | |
68 } | |
69 | |
70 /// <summary> | |
71 /// Microsoft Internal Use Only. Specfies if the project is dirt
y. | |
72 /// </summary> | |
73 public virtual bool IsDirty | |
74 { | |
75 get | |
76 { | |
77 int dirty; | |
78 | |
79 ErrorHandler.ThrowOnFailure(project.IsDirty(out
dirty)); | |
80 return dirty != 0; | |
81 } | |
82 set | |
83 { | |
84 if(this.project == null || this.project.Site ==
null || this.project.IsClosed) | |
85 { | |
86 throw new InvalidOperationException(); | |
87 } | |
88 | |
89 using(AutomationScope scope = new AutomationScop
e(this.project.Site)) | |
90 { | |
91 project.SetProjectFileDirty(value); | |
92 } | |
93 } | |
94 } | |
95 | |
96 /// <summary> | |
97 /// Gets the Projects collection containing the Project object s
upporting this property. | |
98 /// </summary> | |
99 public virtual EnvDTE.Projects Collection | |
100 { | |
101 get { return null; } | |
102 } | |
103 | |
104 /// <summary> | |
105 /// Gets the top-level extensibility object. | |
106 /// </summary> | |
107 public virtual EnvDTE.DTE DTE | |
108 { | |
109 get | |
110 { | |
111 return (EnvDTE.DTE)this.project.Site.GetService(
typeof(EnvDTE.DTE)); | |
112 } | |
113 } | |
114 | |
115 /// <summary> | |
116 /// Gets a GUID string indicating the kind or type of the object
. | |
117 /// </summary> | |
118 public virtual string Kind | |
119 { | |
120 get { return project.ProjectGuid.ToString("B"); } | |
121 } | |
122 | |
123 /// <summary> | |
124 /// Gets a ProjectItems collection for the Project object. | |
125 /// </summary> | |
126 public virtual EnvDTE.ProjectItems ProjectItems | |
127 { | |
128 get | |
129 { | |
130 return new OAProjectItems(this, project); | |
131 } | |
132 } | |
133 | |
134 /// <summary> | |
135 /// Gets a collection of all properties that pertain to the Proj
ect object. | |
136 /// </summary> | |
137 public virtual EnvDTE.Properties Properties | |
138 { | |
139 get | |
140 { | |
141 return new OAProperties(this.project.NodePropert
ies); | |
142 } | |
143 } | |
144 | |
145 /// <summary> | |
146 /// Returns the name of project as a relative path from the dire
ctory containing the solution file to the project file | |
147 /// </summary> | |
148 /// <value>Unique name if project is in a valid state. Otherwise
null</value> | |
149 public virtual string UniqueName | |
150 { | |
151 get | |
152 { | |
153 if(this.project == null || this.project.IsClosed
) | |
154 { | |
155 return null; | |
156 } | |
157 else | |
158 { | |
159 // Get Solution service | |
160 IVsSolution solution = this.project.GetS
ervice(typeof(IVsSolution)) as IVsSolution; | |
161 if(solution == null) | |
162 { | |
163 throw new InvalidOperationExcept
ion(); | |
164 } | |
165 | |
166 // Ask solution for unique name of proje
ct | |
167 string uniqueName = string.Empty; | |
168 ErrorHandler.ThrowOnFailure(solution.Get
UniqueNameOfProject(this.project, out uniqueName)); | |
169 return uniqueName; | |
170 } | |
171 } | |
172 } | |
173 | |
174 /// <summary> | |
175 /// Gets an interface or object that can be accessed by name at
run time. | |
176 /// </summary> | |
177 public virtual object Object | |
178 { | |
179 get { return this.project.Object; } | |
180 } | |
181 | |
182 /// <summary> | |
183 /// Gets the requested Extender object if it is available for th
is object. | |
184 /// </summary> | |
185 /// <param name="name">The name of the extender object.</param> | |
186 /// <returns>An Extender object. </returns> | |
187 public virtual object get_Extender(string name) | |
188 { | |
189 return null; | |
190 } | |
191 | |
192 /// <summary> | |
193 /// Gets a list of available Extenders for the object. | |
194 /// </summary> | |
195 public virtual object ExtenderNames | |
196 { | |
197 get { return null; } | |
198 } | |
199 | |
200 /// <summary> | |
201 /// Gets the Extender category ID (CATID) for the object. | |
202 /// </summary> | |
203 public virtual string ExtenderCATID | |
204 { | |
205 get { return String.Empty; } | |
206 } | |
207 | |
208 /// <summary> | |
209 /// Gets the full path and name of the Project object's file. | |
210 /// </summary> | |
211 public virtual string FullName | |
212 { | |
213 get | |
214 { | |
215 string filename; | |
216 uint format; | |
217 ErrorHandler.ThrowOnFailure(project.GetCurFile(o
ut filename, out format)); | |
218 return filename; | |
219 } | |
220 } | |
221 | |
222 /// <summary> | |
223 /// Gets or sets a value indicatingwhether the object has not be
en modified since last being saved or opened. | |
224 /// </summary> | |
225 public virtual bool Saved | |
226 { | |
227 get | |
228 { | |
229 return !this.IsDirty; | |
230 } | |
231 set | |
232 { | |
233 if(this.project == null || this.project.Site ==
null || this.project.IsClosed) | |
234 { | |
235 throw new InvalidOperationException(); | |
236 } | |
237 | |
238 using(AutomationScope scope = new AutomationScop
e(this.project.Site)) | |
239 { | |
240 project.SetProjectFileDirty(!value); | |
241 } | |
242 } | |
243 } | |
244 | |
245 /// <summary> | |
246 /// Gets the ConfigurationManager object for this Project . | |
247 /// </summary> | |
248 public virtual EnvDTE.ConfigurationManager ConfigurationManager | |
249 { | |
250 get | |
251 { | |
252 if(this.configurationManager == null) | |
253 { | |
254 IVsExtensibility3 extensibility = this.p
roject.Site.GetService(typeof(IVsExtensibility)) as IVsExtensibility3; | |
255 | |
256 if(extensibility == null) | |
257 { | |
258 throw new InvalidOperationExcept
ion(); | |
259 } | |
260 | |
261 object configurationManagerAsObject; | |
262 ErrorHandler.ThrowOnFailure(extensibilit
y.GetConfigMgr(this.project, VSConstants.VSITEMID_ROOT, out configurationManager
AsObject)); | |
263 | |
264 if(configurationManagerAsObject == null) | |
265 { | |
266 throw new InvalidOperationExcept
ion(); | |
267 } | |
268 else | |
269 { | |
270 this.configurationManager = (Con
figurationManager)configurationManagerAsObject; | |
271 } | |
272 } | |
273 | |
274 return this.configurationManager; | |
275 } | |
276 } | |
277 | |
278 /// <summary> | |
279 /// Gets the Globals object containing add-in values that may be
saved in the solution (.sln) file, the project file, or in the user's profile d
ata. | |
280 /// </summary> | |
281 public virtual EnvDTE.Globals Globals | |
282 { | |
283 get { return null; } | |
284 } | |
285 | |
286 /// <summary> | |
287 /// Gets a ProjectItem object for the nested project in the host
project. | |
288 /// </summary> | |
289 public virtual EnvDTE.ProjectItem ParentProjectItem | |
290 { | |
291 get { return null; } | |
292 } | |
293 | |
294 /// <summary> | |
295 /// Gets the CodeModel object for the project. | |
296 /// </summary> | |
297 public virtual EnvDTE.CodeModel CodeModel | |
298 { | |
299 get { return null; } | |
300 } | |
301 | |
302 /// <summary> | |
303 /// Saves the project. | |
304 /// </summary> | |
305 /// <param name="fileName">The file name with which to save the
solution, project, or project item. If the file exists, it is overwritten</param
> | |
306 /// <exception cref="InvalidOperationException">Is thrown if the
save operation failes.</exception> | |
307 /// <exception cref="ArgumentNullException">Is thrown if fileNam
e is null.</exception> | |
308 public virtual void SaveAs(string fileName) | |
309 { | |
310 this.DoSave(true, fileName); | |
311 } | |
312 | |
313 /// <summary> | |
314 /// Saves the project | |
315 /// </summary> | |
316 /// <param name="fileName">The file name of the project</param> | |
317 /// <exception cref="InvalidOperationException">Is thrown if the
save operation failes.</exception> | |
318 /// <exception cref="ArgumentNullException">Is thrown if fileNam
e is null.</exception> | |
319 public virtual void Save(string fileName) | |
320 { | |
321 this.DoSave(false, fileName); | |
322 } | |
323 | |
324 /// <summary> | |
325 /// Removes the project from the current solution. | |
326 /// </summary> | |
327 public virtual void Delete() | |
328 { | |
329 if(this.project == null || this.project.Site == null ||
this.project.IsClosed) | |
330 { | |
331 throw new InvalidOperationException(); | |
332 } | |
333 | |
334 using(AutomationScope scope = new AutomationScope(this.p
roject.Site)) | |
335 { | |
336 this.project.Remove(false); | |
337 } | |
338 } | |
339 #endregion | |
340 | |
341 #region ISupportVSProperties methods | |
342 /// <summary> | |
343 /// Microsoft Internal Use Only. | |
344 /// </summary> | |
345 public virtual void NotifyPropertiesDelete() | |
346 { | |
347 } | |
348 #endregion | |
349 | |
350 #region private methods | |
351 /// <summary> | |
352 /// Saves or Save Asthe project. | |
353 /// </summary> | |
354 /// <param name="isCalledFromSaveAs">Flag determining which Save
method called , the SaveAs or the Save.</param> | |
355 /// <param name="fileName">The name of the project file.</param>
| |
356 private void DoSave(bool isCalledFromSaveAs, string fileName) | |
357 { | |
358 if(fileName == null) | |
359 { | |
360 throw new ArgumentNullException("fileName"); | |
361 } | |
362 | |
363 if(this.project == null || this.project.Site == null ||
this.project.IsClosed) | |
364 { | |
365 throw new InvalidOperationException(); | |
366 } | |
367 | |
368 using(AutomationScope scope = new AutomationScope(this.p
roject.Site)) | |
369 { | |
370 // If an empty file name is passed in for Save t
hen make the file name the project name. | |
371 if(!isCalledFromSaveAs && string.IsNullOrEmpty(f
ileName)) | |
372 { | |
373 // Use the solution service to save the
project file. Note that we have to use the service | |
374 // so that all the shell's elements are
aware that we are inside a save operation and | |
375 // all the file change listenters regist
ered by the shell are suspended. | |
376 | |
377 // Get the cookie of the project file fr
om the RTD. | |
378 IVsRunningDocumentTable rdt = this.proje
ct.Site.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; | |
379 if(null == rdt) | |
380 { | |
381 throw new InvalidOperationExcept
ion(); | |
382 } | |
383 | |
384 IVsHierarchy hier; | |
385 uint itemid; | |
386 IntPtr unkData; | |
387 uint cookie; | |
388 ErrorHandler.ThrowOnFailure(rdt.FindAndL
ockDocument((uint)_VSRDTFLAGS.RDT_NoLock, this.project.Url, out hier, | |
389
out itemid, out
unkData, out cookie)); | |
390 if(IntPtr.Zero != unkData) | |
391 { | |
392 Marshal.Release(unkData); | |
393 } | |
394 | |
395 // Verify that we have a cookie. | |
396 if(0 == cookie) | |
397 { | |
398 // This should never happen beca
use if the project is open, then it must be in the RDT. | |
399 throw new InvalidOperationExcept
ion(); | |
400 } | |
401 | |
402 // Get the IVsHierarchy for the project. | |
403 IVsHierarchy prjHierarchy = HierarchyNod
e.GetOuterHierarchy(this.project); | |
404 | |
405 // Now get the soulution. | |
406 IVsSolution solution = this.project.Site
.GetService(typeof(SVsSolution)) as IVsSolution; | |
407 // Verify that we have both solution and
hierarchy. | |
408 if((null == prjHierarchy) || (null == so
lution)) | |
409 { | |
410 throw new InvalidOperationExcept
ion(); | |
411 } | |
412 | |
413 ErrorHandler.ThrowOnFailure(solution.Sav
eSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_SaveIfDirty, prjHierarchy,
cookie)); | |
414 } | |
415 else | |
416 { | |
417 | |
418 // We need to make some checks before we
can call the save method on the project node. | |
419 // This is mainly because it is now us a
nd not the caller like in case of SaveAs or Save that should validate the file
name. | |
420 // The IPersistFileFormat.Save method on
ly does a validation that is necesseray to be performed. Example: in case of Sav
e As the | |
421 // file name itself is not validated onl
y the whole path. (thus a file name like file\file is accepted, since as a path
is valid) | |
422 | |
423 // 1. The file name has to be valid. | |
424 string fullPath = fileName; | |
425 try | |
426 { | |
427 if(!Path.IsPathRooted(fileName)) | |
428 { | |
429 fullPath = Path.Combine(
this.project.ProjectFolder, fileName); | |
430 } | |
431 } | |
432 // We want to be consistent in the error
message and exception we throw. fileName could be for example #¤&%"¤&"% and th
at would trigger an ArgumentException on Path.IsRooted. | |
433 catch(ArgumentException) | |
434 { | |
435 throw new InvalidOperationExcept
ion(SR.GetString(SR.ErrorInvalidFileName, CultureInfo.CurrentUICulture)); | |
436 } | |
437 | |
438 // It might be redundant but we validate
the file and the full path of the file being valid. The SaveAs would also valid
ate the path. | |
439 // If we decide that this is performance
critical then this should be refactored. | |
440 Utilities.ValidateFileName(this.project.
Site, fullPath); | |
441 | |
442 if(!isCalledFromSaveAs) | |
443 { | |
444 // 2. The file name has to be th
e same | |
445 if(!NativeMethods.IsSamePath(ful
lPath, this.project.Url)) | |
446 { | |
447 throw new InvalidOperati
onException(); | |
448 } | |
449 | |
450 ErrorHandler.ThrowOnFailure(this
.project.Save(fullPath, 1, 0)); | |
451 } | |
452 else | |
453 { | |
454 ErrorHandler.ThrowOnFailure(this
.project.Save(fullPath, 0, 0)); | |
455 } | |
456 } | |
457 } | |
458 | |
459 } | |
460 #endregion | |
461 } | |
462 } | |
OLD | NEW |