OLD | NEW |
| (Empty) |
1 /// Copyright (c) Microsoft Corporation. All rights reserved. | |
2 | |
3 using System; | |
4 using System.Collections.Generic; | |
5 using System.ComponentModel; | |
6 using System.Diagnostics; | |
7 using System.Diagnostics.CodeAnalysis; | |
8 using System.Drawing; | |
9 using System.Globalization; | |
10 using System.IO; | |
11 using System.Runtime.InteropServices; | |
12 using System.Security.Permissions; | |
13 using System.Security.Policy; | |
14 using System.Text; | |
15 using System.Text.RegularExpressions; | |
16 using System.Windows.Forms; | |
17 using Microsoft.VisualStudio; | |
18 using Microsoft.VisualStudio.OLE.Interop; | |
19 using Microsoft.VisualStudio.Shell; | |
20 using Microsoft.VisualStudio.Shell.Interop; | |
21 using Microsoft.Win32; | |
22 using IServiceProvider = System.IServiceProvider; | |
23 using MSBuild = Microsoft.Build.BuildEngine; | |
24 using VSRegistry = Microsoft.VisualStudio.Shell.VSRegistry; | |
25 | |
26 namespace Microsoft.VisualStudio.Project | |
27 { | |
28 public static class Utilities | |
29 { | |
30 private const string defaultMSBuildVersion = "2.0"; | |
31 | |
32 /// <summary> | |
33 /// Look in the registry under the current hive for the path | |
34 /// of MSBuild | |
35 /// </summary> | |
36 /// <returns></returns> | |
37 [CLSCompliant(false)] | |
38 [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBe
CasedCorrectly", MessageId = "Ms")] | |
39 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "msbuild")] | |
40 public static string GetMsBuildPath(IServiceProvider serviceProv
ider) | |
41 { | |
42 return GetMsBuildPath(serviceProvider, defaultMSBuildVer
sion); | |
43 } | |
44 | |
45 /// <summary> | |
46 /// Search the registry for the tools path for MSBuild. | |
47 /// </summary> | |
48 /// <param name="serviceProvider">The service provider.</param> | |
49 /// <param name="version">Msbuild version.</param> | |
50 /// <returns>The msbuild tools path</returns> | |
51 [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBe
CasedCorrectly", MessageId = "Ms")] | |
52 public static string GetMsBuildPath(IServiceProvider serviceProv
ider, string version) | |
53 { | |
54 string msBuildPath = null; | |
55 using(RegistryKey root = VSRegistry.RegistryRoot(service
Provider, __VsLocalRegistryType.RegType_Configuration, false)) | |
56 { | |
57 // Get the value from the registry | |
58 using(RegistryKey vsKey = root.OpenSubKey("MSBui
ld", false)) | |
59 { | |
60 msBuildPath = (string)vsKey.GetValue("MS
BuildBinPath", null); | |
61 } | |
62 } | |
63 if(!string.IsNullOrEmpty(msBuildPath)) | |
64 { | |
65 return msBuildPath; | |
66 } | |
67 | |
68 // The path to MSBuild was not found in the VisualStudio
's registry hive, so try to | |
69 // find it in the new MSBuild hive. | |
70 string registryPath = string.Format(CultureInfo.Invarian
tCulture, "Software\\Microsoft\\MSBuild\\ToolsVersions\\{0}", version); | |
71 using(Microsoft.Win32.RegistryKey msbuildKey = Microsoft
.Win32.Registry.LocalMachine.OpenSubKey(registryPath, false)) | |
72 { | |
73 msBuildPath = (string)msbuildKey.GetValue("MSBui
ldToolsPath", null); | |
74 } | |
75 if(string.IsNullOrEmpty(msBuildPath)) | |
76 { | |
77 string error = SR.GetString(SR.ErrorMsBuildRegis
tration, CultureInfo.CurrentUICulture); | |
78 throw new FileLoadException(error); | |
79 } | |
80 return msBuildPath; | |
81 } | |
82 | |
83 /// <summary> | |
84 /// Is Visual Studio in design mode. | |
85 /// </summary> | |
86 /// <param name="serviceProvider">The service provider.</param> | |
87 /// <returns>true if visual studio is in design mode</returns> | |
88 public static bool IsVisualStudioInDesignMode(IServiceProvider s
ite) | |
89 { | |
90 IVsMonitorSelection selectionMonitor = site.GetService(t
ypeof(IVsMonitorSelection)) as IVsMonitorSelection; | |
91 uint cookie = 0; | |
92 int active = 0; | |
93 Guid designContext = VSConstants.UICONTEXT_DesignMode; | |
94 ErrorHandler.ThrowOnFailure(selectionMonitor.GetCmdUICon
textCookie(ref designContext, out cookie)); | |
95 ErrorHandler.ThrowOnFailure(selectionMonitor.IsCmdUICont
extActive(cookie, out active)); | |
96 return active != 0; | |
97 } | |
98 | |
99 /// <include file='doc\VsShellUtilities.uex' path='docs/doc[@for
="Utilities.IsInAutomationFunction"]/*' /> | |
100 /// <devdoc> | |
101 /// Is an extensibility object executing an automation function. | |
102 /// </devdoc> | |
103 /// <param name="serviceProvider">The service provider.</param> | |
104 /// <returns>true if the extensiblity object is executing an aut
omation function.</returns> | |
105 public static bool IsInAutomationFunction(IServiceProvider servi
ceProvider) | |
106 { | |
107 if(serviceProvider == null) | |
108 { | |
109 throw new ArgumentNullException("serviceProvider
"); | |
110 } | |
111 | |
112 IVsExtensibility3 extensibility = serviceProvider.GetSer
vice(typeof(EnvDTE.IVsExtensibility)) as IVsExtensibility3; | |
113 | |
114 if(extensibility == null) | |
115 { | |
116 throw new InvalidOperationException(); | |
117 } | |
118 int inAutomation = 0; | |
119 ErrorHandler.ThrowOnFailure(extensibility.IsInAutomation
Function(out inAutomation)); | |
120 return inAutomation != 0; | |
121 } | |
122 | |
123 /// <summary> | |
124 /// Creates a semicolon delinited list of strings. This can be u
sed to provide the properties for VSHPROPID_CfgPropertyPagesCLSIDList, VSHPROPID
_PropertyPagesCLSIDList, VSHPROPID_PriorityPropertyPagesCLSIDList | |
125 /// </summary> | |
126 /// <param name="guids">An array of Guids.</param> | |
127 /// <returns>A semicolon delimited string, or null</returns> | |
128 [CLSCompliant(false)] | |
129 public static string CreateSemicolonDelimitedListOfStringFromGui
ds(Guid[] guids) | |
130 { | |
131 if(guids == null || guids.Length == 0) | |
132 { | |
133 return null; | |
134 } | |
135 | |
136 // Create a StringBuilder with a pre-allocated buffer bi
g enough for the | |
137 // final string. 39 is the length of a GUID in the "B" f
orm plus the final ';' | |
138 StringBuilder stringList = new StringBuilder(39 * guids.
Length); | |
139 for(int i = 0; i < guids.Length; i++) | |
140 { | |
141 stringList.Append(guids[i].ToString("B")); | |
142 stringList.Append(";"); | |
143 } | |
144 | |
145 return stringList.ToString().TrimEnd(';'); | |
146 } | |
147 | |
148 private static char[] curlyBraces = new char[] { '{', '}' }; | |
149 /// <summary> | |
150 /// Take list of guids as a single string and generate an array
of Guids from it | |
151 /// </summary> | |
152 /// <param name="guidList">Semi-colon separated list of Guids</p
aram> | |
153 /// <returns>Array of Guids</returns> | |
154 [CLSCompliant(false)] | |
155 public static Guid[] GuidsArrayFromSemicolonDelimitedStringOfGui
ds(string guidList) | |
156 { | |
157 if(guidList == null) | |
158 { | |
159 return null; | |
160 } | |
161 | |
162 List<Guid> guids = new List<Guid>(); | |
163 string[] guidsStrings = guidList.Split(';'); | |
164 foreach(string guid in guidsStrings) | |
165 { | |
166 if(!String.IsNullOrEmpty(guid)) | |
167 guids.Add(new Guid(guid.Trim(curlyBraces
))); | |
168 } | |
169 | |
170 return guids.ToArray(); | |
171 } | |
172 | |
173 /// <summary> | |
174 /// Validates a file path by validating all file parts. If the | |
175 /// the file name is invalid it throws an exception if the proje
ct is in automation. Otherwise it shows a dialog box with the error message. | |
176 /// </summary> | |
177 /// <param name="serviceProvider">The service provider</param> | |
178 /// <param name="filePath">A full path to a file name</param> | |
179 /// <exception cref="InvalidOperationException">In case of failu
re an InvalidOperationException is thrown.</exception> | |
180 public static void ValidateFileName(IServiceProvider serviceProv
ider, string filePath) | |
181 { | |
182 string errorMessage = String.Empty; | |
183 if(String.IsNullOrEmpty(filePath)) | |
184 { | |
185 errorMessage = SR.GetString(SR.ErrorInvalidFileN
ame, CultureInfo.CurrentUICulture); | |
186 } | |
187 else if(filePath.Length > NativeMethods.MAX_PATH) | |
188 { | |
189 errorMessage = String.Format(CultureInfo.Current
Culture, SR.GetString(SR.PathTooLong, CultureInfo.CurrentUICulture), filePath); | |
190 } | |
191 else if(ContainsInvalidFileNameChars(filePath)) | |
192 { | |
193 errorMessage = SR.GetString(SR.ErrorInvalidFileN
ame, CultureInfo.CurrentUICulture); | |
194 } | |
195 | |
196 if(errorMessage.Length == 0) | |
197 { | |
198 string fileName = Path.GetFileName(filePath); | |
199 if(String.IsNullOrEmpty(fileName) || IsFileNameI
nvalid(fileName)) | |
200 { | |
201 errorMessage = SR.GetString(SR.ErrorInva
lidFileName, CultureInfo.CurrentUICulture); | |
202 } | |
203 else | |
204 { | |
205 string fileNameWithoutExtension = Path.G
etFileNameWithoutExtension(fileName); | |
206 | |
207 // If there is no filename or it starts
with a leading dot issue an error message and quit. | |
208 if(String.IsNullOrEmpty(fileNameWithoutE
xtension) || fileNameWithoutExtension[0] == '.') | |
209 { | |
210 errorMessage = SR.GetString(SR.F
ileNameCannotContainALeadingPeriod, CultureInfo.CurrentUICulture); | |
211 } | |
212 } | |
213 } | |
214 | |
215 if(errorMessage.Length > 0) | |
216 { | |
217 // If it is not called from an automation method
show a dialog box. | |
218 if(!Utilities.IsInAutomationFunction(serviceProv
ider)) | |
219 { | |
220 string title = null; | |
221 OLEMSGICON icon = OLEMSGICON.OLEMSGICON_
CRITICAL; | |
222 OLEMSGBUTTON buttons = OLEMSGBUTTON.OLEM
SGBUTTON_OK; | |
223 OLEMSGDEFBUTTON defaultButton = OLEMSGDE
FBUTTON.OLEMSGDEFBUTTON_FIRST; | |
224 VsShellUtilities.ShowMessageBox(serviceP
rovider, title, errorMessage, icon, buttons, defaultButton); | |
225 } | |
226 else | |
227 { | |
228 throw new InvalidOperationException(erro
rMessage); | |
229 } | |
230 } | |
231 | |
232 } | |
233 | |
234 /// <summary> | |
235 /// Creates a CALPOLESTR from a list of strings | |
236 /// It is the responsability of the caller to release this memor
y. | |
237 /// </summary> | |
238 /// <param name="guids"></param> | |
239 /// <returns>A CALPOLESTR that was created from the the list of
strings.</returns> | |
240 [CLSCompliant(false)] | |
241 [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBe
CasedCorrectly", MessageId = "CALPOLESTR")] | |
242 public static CALPOLESTR CreateCALPOLESTR(IList<string> strings) | |
243 { | |
244 CALPOLESTR calpolStr = new CALPOLESTR(); | |
245 | |
246 if(strings != null) | |
247 { | |
248 // Demand unmanaged permissions in order to acce
ss unmanaged memory. | |
249 new SecurityPermission(SecurityPermissionFlag.Un
managedCode).Demand(); | |
250 | |
251 calpolStr.cElems = (uint)strings.Count; | |
252 | |
253 int size = Marshal.SizeOf(typeof(IntPtr)); | |
254 | |
255 calpolStr.pElems = Marshal.AllocCoTaskMem(string
s.Count * size); | |
256 | |
257 IntPtr ptr = calpolStr.pElems; | |
258 | |
259 foreach(string aString in strings) | |
260 { | |
261 IntPtr tempPtr = Marshal.StringToCoTaskM
emUni(aString); | |
262 Marshal.WriteIntPtr(ptr, tempPtr); | |
263 ptr = new IntPtr(ptr.ToInt64() + size); | |
264 } | |
265 } | |
266 | |
267 return calpolStr; | |
268 } | |
269 | |
270 /// <summary> | |
271 /// Creates a CADWORD from a list of tagVsSccFilesFlags. Memory
is allocated for the elems. | |
272 /// It is the responsability of the caller to release this memor
y. | |
273 /// </summary> | |
274 /// <param name="guids"></param> | |
275 /// <returns>A CADWORD created from the list of tagVsSccFilesFla
gs.</returns> | |
276 [CLSCompliant(false)] | |
277 [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBe
CasedCorrectly", MessageId = "CADWORD")] | |
278 public static CADWORD CreateCADWORD(IList<tagVsSccFilesFlags> fl
ags) | |
279 { | |
280 CADWORD cadWord = new CADWORD(); | |
281 | |
282 if(flags != null) | |
283 { | |
284 // Demand unmanaged permissions in order to acce
ss unmanaged memory. | |
285 new SecurityPermission(SecurityPermissionFlag.Un
managedCode).Demand(); | |
286 | |
287 cadWord.cElems = (uint)flags.Count; | |
288 | |
289 int size = Marshal.SizeOf(typeof(UInt32)); | |
290 | |
291 cadWord.pElems = Marshal.AllocCoTaskMem(flags.Co
unt * size); | |
292 | |
293 IntPtr ptr = cadWord.pElems; | |
294 | |
295 foreach(tagVsSccFilesFlags flag in flags) | |
296 { | |
297 Marshal.WriteInt32(ptr, (int)flag); | |
298 ptr = new IntPtr(ptr.ToInt64() + size); | |
299 } | |
300 } | |
301 | |
302 return cadWord; | |
303 } | |
304 | |
305 /// <summary> | |
306 /// Splits a bitmap from a Stream into an ImageList | |
307 /// </summary> | |
308 /// <param name="imageStream">A Stream representing a Bitmap</pa
ram> | |
309 /// <returns>An ImageList object representing the images from th
e given stream</returns> | |
310 public static ImageList GetImageList(Stream imageStream) | |
311 { | |
312 ImageList ilist = new ImageList(); | |
313 | |
314 if(imageStream == null) | |
315 { | |
316 return ilist; | |
317 } | |
318 ilist.ColorDepth = ColorDepth.Depth24Bit; | |
319 ilist.ImageSize = new Size(16, 16); | |
320 Bitmap bitmap = new Bitmap(imageStream); | |
321 ilist.Images.AddStrip(bitmap); | |
322 ilist.TransparentColor = Color.Magenta; | |
323 return ilist; | |
324 } | |
325 | |
326 /// <summary> | |
327 /// Splits a bitmap from a pointer to an ImageList | |
328 /// </summary> | |
329 /// <param name="imageListAsPointer">A pointer to a bitmap of im
ages to split</param> | |
330 /// <returns>An ImageList object representing the images from th
e given stream</returns> | |
331 public static ImageList GetImageList(object imageListAsPointer) | |
332 { | |
333 ImageList images = null; | |
334 | |
335 IntPtr intPtr = new IntPtr((int)imageListAsPointer); | |
336 HandleRef hImageList = new HandleRef(null, intPtr); | |
337 int count = UnsafeNativeMethods.ImageList_GetImageCount(
hImageList); | |
338 | |
339 if(count > 0) | |
340 { | |
341 // Create a bitmap big enough to hold all the im
ages | |
342 Bitmap b = new Bitmap(16 * count, 16); | |
343 Graphics g = Graphics.FromImage(b); | |
344 | |
345 // Loop through and extract each image from the
imagelist into our own bitmap | |
346 IntPtr hDC = IntPtr.Zero; | |
347 try | |
348 { | |
349 hDC = g.GetHdc(); | |
350 HandleRef handleRefDC = new HandleRef(nu
ll, hDC); | |
351 for(int i = 0; i < count; i++) | |
352 { | |
353 UnsafeNativeMethods.ImageList_Dr
aw(hImageList, i, handleRefDC, i * 16, 0, NativeMethods.ILD_NORMAL); | |
354 } | |
355 } | |
356 finally | |
357 { | |
358 if(g != null && hDC != IntPtr.Zero) | |
359 { | |
360 g.ReleaseHdc(hDC); | |
361 } | |
362 } | |
363 | |
364 // Create a new imagelist based on our stolen im
ages | |
365 images = new ImageList(); | |
366 images.ColorDepth = ColorDepth.Depth24Bit; | |
367 images.ImageSize = new Size(16, 16); | |
368 images.Images.AddStrip(b); | |
369 } | |
370 return images; | |
371 } | |
372 | |
373 /// <summary> | |
374 /// Gets the active configuration name. | |
375 /// </summary> | |
376 /// <param name="automationObject">The automation object.</param
> | |
377 /// <returns>The name of the active configuartion.</returns>
| |
378 internal static string GetActiveConfigurationName(EnvDTE.Project
automationObject) | |
379 { | |
380 if(automationObject == null) | |
381 { | |
382 throw new ArgumentNullException("automationObjec
t"); | |
383 } | |
384 | |
385 string currentConfigName = string.Empty; | |
386 if(automationObject.ConfigurationManager != null) | |
387 { | |
388 EnvDTE.Configuration activeConfig = automationOb
ject.ConfigurationManager.ActiveConfiguration; | |
389 if(activeConfig != null) | |
390 { | |
391 currentConfigName = activeConfig.Configu
rationName; | |
392 } | |
393 } | |
394 return currentConfigName; | |
395 | |
396 } | |
397 | |
398 | |
399 /// <summary> | |
400 /// Verifies that two objects represent the same instance of a C
OM object. | |
401 /// This essentially compares the IUnkown pointers of the 2 obje
cts. | |
402 /// This is needed in scenario where aggregation is involved. | |
403 /// </summary> | |
404 /// <param name="obj1">Can be an object, interface or IntPtr</pa
ram> | |
405 /// <param name="obj2">Can be an object, interface or IntPtr</pa
ram> | |
406 /// <returns>True if the 2 items represent the same thing</retur
ns> | |
407 [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNo
tContainTypeNames", MessageId = "obj")] | |
408 public static bool IsSameComObject(object obj1, object obj2) | |
409 { | |
410 bool isSame = false; | |
411 IntPtr unknown1 = IntPtr.Zero; | |
412 IntPtr unknown2 = IntPtr.Zero; | |
413 try | |
414 { | |
415 // If we have 2 null, then they are not COM obje
cts and as such "it's not the same COM object" | |
416 if(obj1 != null && obj2 != null) | |
417 { | |
418 unknown1 = QueryInterfaceIUnknown(obj1); | |
419 unknown2 = QueryInterfaceIUnknown(obj2); | |
420 | |
421 isSame = IntPtr.Equals(unknown1, unknown
2); | |
422 } | |
423 } | |
424 finally | |
425 { | |
426 if(unknown1 != IntPtr.Zero) | |
427 { | |
428 Marshal.Release(unknown1); | |
429 } | |
430 | |
431 if(unknown2 != IntPtr.Zero) | |
432 { | |
433 Marshal.Release(unknown2); | |
434 } | |
435 | |
436 } | |
437 | |
438 return isSame; | |
439 } | |
440 | |
441 /// <summary> | |
442 /// Retrieve the IUnknown for the managed or COM object passed i
n. | |
443 /// </summary> | |
444 /// <param name="objToQuery">Managed or COM object.</param> | |
445 /// <returns>Pointer to the IUnknown interface of the object.</r
eturns> | |
446 internal static IntPtr QueryInterfaceIUnknown(object objToQuery) | |
447 { | |
448 bool releaseIt = false; | |
449 IntPtr unknown = IntPtr.Zero; | |
450 IntPtr result; | |
451 try | |
452 { | |
453 if(objToQuery is IntPtr) | |
454 { | |
455 unknown = (IntPtr)objToQuery; | |
456 } | |
457 else | |
458 { | |
459 // This is a managed object (or RCW) | |
460 unknown = Marshal.GetIUnknownForObject(o
bjToQuery); | |
461 releaseIt = true; | |
462 } | |
463 | |
464 // We might already have an IUnknown, but if thi
s is an aggregated | |
465 // object, it may not be THE IUnknown until we Q
I for it. | |
466 Guid IID_IUnknown = VSConstants.IID_IUnknown; | |
467 ErrorHandler.ThrowOnFailure(Marshal.QueryInterfa
ce(unknown, ref IID_IUnknown, out result)); | |
468 } | |
469 finally | |
470 { | |
471 if(releaseIt && unknown != IntPtr.Zero) | |
472 { | |
473 Marshal.Release(unknown); | |
474 } | |
475 | |
476 } | |
477 | |
478 return result; | |
479 } | |
480 | |
481 /// <summary> | |
482 /// Returns true if thename that can represent a path, absolut o
r relative, or a file name contains invalid filename characters. | |
483 /// </summary> | |
484 /// <param name="name">File name</param> | |
485 /// <returns>true if file name is invalid</returns> | |
486 public static bool ContainsInvalidFileNameChars(string name) | |
487 { | |
488 if(String.IsNullOrEmpty(name)) | |
489 { | |
490 return true; | |
491 } | |
492 | |
493 try | |
494 { | |
495 if(Path.IsPathRooted(name) && !name.StartsWith(@
"\\", StringComparison.Ordinal)) | |
496 { | |
497 string root = Path.GetPathRoot(name); | |
498 name = name.Substring(root.Length); | |
499 } | |
500 } | |
501 // The Path methods used by ContainsInvalidFileNameChars
return argument exception if the filePath contains invalid characters. | |
502 catch(ArgumentException) | |
503 { | |
504 return true; | |
505 } | |
506 | |
507 Microsoft.VisualStudio.Shell.Url uri = new Microsoft.Vis
ualStudio.Shell.Url(name); | |
508 | |
509 // This might be confusing bur Url.IsFile means that the
uri represented by the name is either absolut or relative. | |
510 if(uri.IsFile) | |
511 { | |
512 string[] segments = uri.Segments; | |
513 if(segments != null && segments.Length > 0) | |
514 { | |
515 foreach(string segment in segments) | |
516 { | |
517 if(IsFilePartInValid(segment)) | |
518 { | |
519 return true; | |
520 } | |
521 } | |
522 | |
523 // Now the last segment should be specia
lly taken care, since that cannot be all dots or spaces. | |
524 string lastSegment = segments[segments.L
ength - 1]; | |
525 string filePart = Path.GetFileNameWithou
tExtension(lastSegment); | |
526 if(IsFileNameAllGivenCharacter('.', file
Part) || IsFileNameAllGivenCharacter(' ', filePart)) | |
527 { | |
528 return true; | |
529 } | |
530 } | |
531 } | |
532 else | |
533 { | |
534 // The assumption here is that we got a file nam
e. | |
535 string filePart = Path.GetFileNameWithoutExtensi
on(name); | |
536 if(IsFileNameAllGivenCharacter('.', filePart) ||
IsFileNameAllGivenCharacter(' ', filePart)) | |
537 { | |
538 return true; | |
539 } | |
540 | |
541 | |
542 return IsFilePartInValid(name); | |
543 } | |
544 | |
545 return false; | |
546 } | |
547 | |
548 /// Cehcks if a file name is valid. | |
549 /// </devdoc> | |
550 /// <param name="fileName">The name of the file</param> | |
551 /// <returns>True if the file is valid.</returns> | |
552 public static bool IsFileNameInvalid(string fileName) | |
553 { | |
554 if(String.IsNullOrEmpty(fileName)) | |
555 { | |
556 return true; | |
557 } | |
558 | |
559 if(IsFileNameAllGivenCharacter('.', fileName) || IsFileN
ameAllGivenCharacter(' ', fileName)) | |
560 { | |
561 return true; | |
562 } | |
563 | |
564 | |
565 return IsFilePartInValid(fileName); | |
566 | |
567 } | |
568 | |
569 /// <summary> | |
570 /// Helper method to call a converter explicitely to convert to
an enum type | |
571 /// </summary> | |
572 /// <typeparam name="T">THe enum to convert to</typeparam> | |
573 /// <typeparam name="V">The converter that will be created</type
param> | |
574 /// <param name="value">The enum value to be converted to</param
> | |
575 /// <param name="typeToConvert">The type to convert</param> | |
576 /// <param name="culture">The culture to use to read the localiz
ed strings</param> | |
577 /// <returns></returns> | |
578 [CLSCompliant(false)] | |
579 public static object ConvertToType<T>(T value, Type typeToConver
t, CultureInfo culture) | |
580 where T : struct | |
581 { | |
582 EnumConverter converter = GetEnumConverter<T>(); | |
583 if(converter == null) | |
584 { | |
585 return null; | |
586 } | |
587 if(converter.CanConvertTo(typeToConvert)) | |
588 { | |
589 return converter.ConvertTo(null, culture, value,
typeToConvert); | |
590 } | |
591 | |
592 return null; | |
593 } | |
594 | |
595 /// <summary> | |
596 /// Helper method for converting from a string to an enum using
a converter. | |
597 /// </summary> | |
598 /// <typeparam name="T"></typeparam> | |
599 /// <param name="value"></param> | |
600 /// <param name="culture">The culture to use to read the localiz
ed strings</param> | |
601 /// <returns></returns> | |
602 [CLSCompliant(false)] | |
603 public static Nullable<T> ConvertFromType<T>(string value, Cultu
reInfo culture) | |
604 where T : struct | |
605 { | |
606 Nullable<T> returnValue = new Nullable<T>(); | |
607 | |
608 returnValue = returnValue.GetValueOrDefault(); | |
609 | |
610 if(value == null) | |
611 { | |
612 return returnValue; | |
613 } | |
614 | |
615 EnumConverter converter = GetEnumConverter<T>(); | |
616 if(converter == null) | |
617 { | |
618 return returnValue; | |
619 } | |
620 | |
621 if(converter.CanConvertFrom(value.GetType())) | |
622 { | |
623 object converted = converter.ConvertFrom(null, c
ulture, value); | |
624 | |
625 if(converted != null && (converted is T)) | |
626 { | |
627 returnValue = (T)converted; | |
628 } | |
629 } | |
630 | |
631 return returnValue; | |
632 } | |
633 | |
634 | |
635 /// <summary> | |
636 /// Sets a string value from an enum | |
637 /// </summary> | |
638 /// <typeparam name="T">The enum type</typeparam> | |
639 /// <param name="enumValue">The value of teh enum.</param> | |
640 /// <returns></returns> | |
641 [CLSCompliant(false)] | |
642 public static string SetStringValueFromConvertedEnum<T>(T enumVa
lue, CultureInfo culture) | |
643 where T : struct | |
644 { | |
645 string convertToType = ConvertToType<T>(enumValue, typeo
f(string), culture) as string; | |
646 | |
647 if(convertToType == null) | |
648 { | |
649 return String.Empty; | |
650 } | |
651 | |
652 return convertToType; | |
653 } | |
654 | |
655 | |
656 /// <summary> | |
657 /// Initializes the in memory project. Sets BuildEnabled on the
project to true. | |
658 /// </summary> | |
659 /// <param name="engine">The build engine to use to create a bui
ld project.</param> | |
660 /// <param name="fullProjectPath">The full path of the project.<
/param> | |
661 /// <returns>A loaded msbuild project.</returns> | |
662 internal static MSBuild.Project InitializeMsBuildProject(MSBuild
.Engine buildEngine, string fullProjectPath) | |
663 { | |
664 if(buildEngine == null) | |
665 { | |
666 throw new ArgumentNullException("buildEngine"); | |
667 } | |
668 | |
669 if(String.IsNullOrEmpty(fullProjectPath)) | |
670 { | |
671 throw new ArgumentException(SR.GetString(SR.Inva
lidParameter, CultureInfo.CurrentUICulture), "fullProjectPath"); | |
672 } | |
673 | |
674 // Check if the project already has been loaded with the
fullProjectPath. If yes return the build project associated to it. | |
675 MSBuild.Project buildProject = buildEngine.GetLoadedProj
ect(fullProjectPath); | |
676 | |
677 if(buildProject == null) | |
678 { | |
679 buildProject = buildEngine.CreateNewProject(); | |
680 buildProject.BuildEnabled = true; | |
681 buildProject.Load(fullProjectPath); | |
682 } | |
683 | |
684 return buildProject; | |
685 } | |
686 | |
687 /// <summary> | |
688 /// Loads a project file for the file. If the build project exis
ts and it was loaded with a different file then it is unloaded first. | |
689 /// </summary> | |
690 /// <param name="engine">The build engine to use to create a bui
ld project.</param> | |
691 /// <param name="fullProjectPath">The full path of the project.<
/param> | |
692 /// <param name="exitingBuildProject">An Existing build project
that will be reloaded.</param> | |
693 /// <returns>A loaded msbuild project.</returns> | |
694 internal static MSBuild.Project ReinitializeMsBuildProject(MSBui
ld.Engine buildEngine, string fullProjectPath, MSBuild.Project exitingBuildProje
ct) | |
695 { | |
696 // If we have a build project that has been loaded with
another file unload it. | |
697 try | |
698 { | |
699 if(exitingBuildProject != null && exitingBuildPr
oject.ParentEngine != null && !NativeMethods.IsSamePath(exitingBuildProject.Full
FileName, fullProjectPath)) | |
700 { | |
701 exitingBuildProject.ParentEngine.UnloadP
roject(exitingBuildProject); | |
702 } | |
703 } | |
704 // We catch Invalid operation exception because if the
project was unloaded while we touch the ParentEngine the msbuild API throws. | |
705 // Is there a way to figure out that a project was unloa
ded? | |
706 catch(InvalidOperationException) | |
707 { | |
708 } | |
709 | |
710 return Utilities.InitializeMsBuildProject(buildEngine, f
ullProjectPath); | |
711 } | |
712 | |
713 /// <summary> | |
714 /// Initialize the build engine. Sets the build enabled property
to true. The engine is initialzed if the passed in engine is null or does not h
ave its bin path set. | |
715 /// </summary> | |
716 /// <param name="engine">An instance of MSBuild.Engine build eng
ine, that will be checked if initialized.</param> | |
717 /// <param name="engine">The service provider.</param> | |
718 /// <returns>The buildengine to use.</returns> | |
719 internal static MSBuild.Engine InitializeMsBuildEngine(MSBuild.E
ngine existingEngine, IServiceProvider serviceProvider) | |
720 { | |
721 if(serviceProvider == null) | |
722 { | |
723 throw new ArgumentNullException("serviceProvider
"); | |
724 } | |
725 | |
726 if(existingEngine == null) | |
727 { | |
728 MSBuild.Engine buildEngine = MSBuild.Engine.Glob
alEngine; | |
729 return buildEngine; | |
730 } | |
731 | |
732 return existingEngine; | |
733 } | |
734 | |
735 /// <summary> | |
736 /// Gets an instance of an EnumConverter for enums that have Pro
pertyPageTypeConverter attribute | |
737 /// </summary> | |
738 /// <typeparam name="T">The type to search for the PropertyPageT
ypeConverter attribute.</typeparam> | |
739 /// <returns>An instance of an enum converter, or null if none f
ound.</returns> | |
740 private static EnumConverter GetEnumConverter<T>() | |
741 where T : struct | |
742 { | |
743 object[] attributes = typeof(T).GetCustomAttributes(type
of(PropertyPageTypeConverterAttribute), true); | |
744 | |
745 // There should be only one PropertyPageTypeConverterAtt
ribute defined on T | |
746 if(attributes != null && attributes.Length == 1) | |
747 { | |
748 | |
749 Debug.Assert(attributes[0] is PropertyPageTypeCo
nverterAttribute, "The returned attribute must be an attribute is PropertyPageTy
peConverterAttribute"); | |
750 PropertyPageTypeConverterAttribute converterAttr
ibute = (PropertyPageTypeConverterAttribute)attributes[0]; | |
751 | |
752 if(converterAttribute.ConverterType.IsSubclassOf
(typeof(EnumConverter))) | |
753 { | |
754 return Activator.CreateInstance(converte
rAttribute.ConverterType) as EnumConverter; | |
755 } | |
756 } | |
757 | |
758 return null; | |
759 } | |
760 | |
761 /// <summary>> | |
762 /// Checks if the file name is all the given character. | |
763 /// </summary> | |
764 private static bool IsFileNameAllGivenCharacter(char c, string f
ileName) | |
765 { | |
766 // A valid file name cannot be all "c" . | |
767 int charFound = 0; | |
768 for(charFound = 0; charFound < fileName.Length && fileNa
me[charFound] == c; ++charFound) ; | |
769 if(charFound >= fileName.Length) | |
770 { | |
771 return true; | |
772 } | |
773 | |
774 return false; | |
775 } | |
776 | |
777 /// <summary> | |
778 /// Checks whether a file part contains valid characters. The fi
le part can be any part of a non rooted path. | |
779 /// </summary> | |
780 /// <param name="filePart"></param> | |
781 /// <returns></returns> | |
782 private static bool IsFilePartInValid(string filePart) | |
783 { | |
784 if(String.IsNullOrEmpty(filePart)) | |
785 { | |
786 return true; | |
787 } | |
788 String reservedName = "(\\b(nul|con|aux|prn)\\b)|(\\b((c
om|lpt)[0-9])\\b)"; | |
789 String invalidChars = @"([/?:&\\*<>|#%" + '\"' + "])"; | |
790 String regexToUseForFileName = reservedName + "|" + inva
lidChars; | |
791 String fileNameToVerify = filePart; | |
792 | |
793 // Define a regular expression that covers all character
s that are not in the safe character sets. | |
794 // It is compiled for performance. | |
795 | |
796 // The filePart might still be a file and extension. If
it is like that then we must check them separately, since different rules apply | |
797 string extension = String.Empty; | |
798 try | |
799 { | |
800 extension = Path.GetExtension(filePart); | |
801 } | |
802 // We catch the ArgumentException because we want this m
ethod to return true if the filename is not valid. FilePart could be for example
#¤&%"¤&"% and that would throw ArgumentException on GetExtension | |
803 catch(ArgumentException) | |
804 { | |
805 return true; | |
806 } | |
807 | |
808 if(!String.IsNullOrEmpty(extension)) | |
809 { | |
810 // Check the extension first | |
811 String regexToUseForExtension = invalidChars; | |
812 Regex unsafeCharactersRegex = new Regex(regexToU
seForExtension, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.C
ultureInvariant); | |
813 bool isMatch = unsafeCharactersRegex.IsMatch(ext
ension); | |
814 if(isMatch) | |
815 { | |
816 return isMatch; | |
817 } | |
818 | |
819 // We want to verify here everything but the ext
ension. | |
820 // We cannot use GetFileNameWithoutExtension bec
ause it might be that for example (..\\filename.txt) is passed in asnd that shou
ld fail, since that is not a valid filename. | |
821 fileNameToVerify = filePart.Substring(0, filePar
t.Length - extension.Length); | |
822 | |
823 if(String.IsNullOrEmpty(fileNameToVerify)) | |
824 { | |
825 return true; | |
826 } | |
827 } | |
828 | |
829 // We verify CLOCK$ outside the regex since for some rea
son the regex is not matching the clock\\$ added. | |
830 if(String.Compare(fileNameToVerify, "CLOCK$", StringComp
arison.OrdinalIgnoreCase) == 0) | |
831 { | |
832 return true; | |
833 } | |
834 | |
835 Regex unsafeFileNameCharactersRegex = new Regex(regexToU
seForFileName, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Cu
ltureInvariant); | |
836 return unsafeFileNameCharactersRegex.IsMatch(fileNameToV
erify); | |
837 } | |
838 | |
839 /// <summary> | |
840 /// Copy a directory recursively to the specified non-existing d
irectory | |
841 /// </summary> | |
842 /// <param name="source">Directory to copy from</param> | |
843 /// <param name="target">Directory to copy to</param> | |
844 public static void RecursivelyCopyDirectory(string source, strin
g target) | |
845 { | |
846 // Make sure it doesn't already exist | |
847 if(Directory.Exists(target)) | |
848 throw new ArgumentException(String.Format(Cultur
eInfo.CurrentCulture, SR.GetString(SR.FileOrFolderAlreadyExists, CultureInfo.Cur
rentUICulture), target)); | |
849 | |
850 Directory.CreateDirectory(target); | |
851 DirectoryInfo directory = new DirectoryInfo(source); | |
852 | |
853 // Copy files | |
854 foreach(FileInfo file in directory.GetFiles()) | |
855 { | |
856 file.CopyTo(Path.Combine(target, file.Name)); | |
857 } | |
858 | |
859 // Now recurse to child directories | |
860 foreach(DirectoryInfo child in directory.GetDirectories(
)) | |
861 { | |
862 RecursivelyCopyDirectory(child.FullName, Path.Co
mbine(target, child.Name)); | |
863 } | |
864 } | |
865 | |
866 /// <summary> | |
867 /// Canonicalizes a file name, including: | |
868 /// - determines the full path to the file | |
869 /// - casts to upper case | |
870 /// Canonicalizing a file name makes it possible to compare file
names using simple simple string comparison. | |
871 /// | |
872 /// Note: this method does not handle shared drives and UNC driv
es. | |
873 /// </summary> | |
874 /// <param name="anyFileName">A file name, which can be relative
/absolute and contain lower-case/upper-case characters.</param> | |
875 /// <returns>Canonicalized file name.</returns> | |
876 internal static string CanonicalizeFileName(string anyFileName) | |
877 { | |
878 // Get absolute path | |
879 // Note: this will not handle UNC paths | |
880 FileInfo fileInfo = new FileInfo(anyFileName); | |
881 string fullPath = fileInfo.FullName; | |
882 | |
883 // Cast to upper-case | |
884 fullPath = fullPath.ToUpper(CultureInfo.CurrentCulture); | |
885 | |
886 return fullPath; | |
887 } | |
888 | |
889 | |
890 /// <summary> | |
891 /// Determines if a file is a template. | |
892 /// </summary> | |
893 /// <param name="fileName">The file to check whether it is a tem
plate file</param> | |
894 /// <returns>true if the file is a template file</returns> | |
895 internal static bool IsTemplateFile(string fileName) | |
896 { | |
897 if(String.IsNullOrEmpty(fileName)) | |
898 { | |
899 return false; | |
900 } | |
901 | |
902 string extension = Path.GetExtension(fileName); | |
903 return (String.Compare(extension, ".vstemplate", StringC
omparison.OrdinalIgnoreCase) == 0 || string.Compare(extension, ".vsz", StringCom
parison.OrdinalIgnoreCase) == 0); | |
904 } | |
905 | |
906 /// <summary> | |
907 /// Retrives the configuration and the platform using the IVsSol
utionBuildManager2 interface. | |
908 /// </summary> | |
909 /// <param name="serviceProvider">A service provider.</param> | |
910 /// <param name="hierarchy">The hierrachy whose configuration is
requested.</param> | |
911 /// <param name="configuration">The name of the active configura
tion.</param> | |
912 /// <param name="platform">The name of the platform.</param> | |
913 /// <returns>true if successfull.</returns> | |
914 internal static bool TryGetActiveConfigurationAndPlatform(System
.IServiceProvider serviceProvider, IVsHierarchy hierarchy, out string configurat
ion, out string platform) | |
915 { | |
916 if(serviceProvider == null) | |
917 { | |
918 throw new ArgumentNullException("serviceProvider
"); | |
919 } | |
920 | |
921 if(hierarchy == null) | |
922 { | |
923 throw new ArgumentNullException("hierarchy"); | |
924 } | |
925 | |
926 configuration = String.Empty; | |
927 platform = String.Empty; | |
928 | |
929 IVsSolutionBuildManager2 solutionBuildManager = serviceP
rovider.GetService(typeof(SVsSolutionBuildManager)) as IVsSolutionBuildManager2; | |
930 | |
931 if(solutionBuildManager == null) | |
932 { | |
933 return false; | |
934 } | |
935 | |
936 IVsProjectCfg[] activeConfigs = new IVsProjectCfg[1]; | |
937 ErrorHandler.ThrowOnFailure(solutionBuildManager.FindAct
iveProjectCfg(IntPtr.Zero, IntPtr.Zero, hierarchy, activeConfigs)); | |
938 | |
939 IVsProjectCfg activeCfg = activeConfigs[0]; | |
940 | |
941 // Can it be that the activeCfg is null? | |
942 System.Diagnostics.Debug.Assert(activeCfg != null, "Cann
ot find the active configuration"); | |
943 | |
944 string canonicalName; | |
945 ErrorHandler.ThrowOnFailure(activeCfg.get_CanonicalName(
out canonicalName)); | |
946 | |
947 return ProjectConfig.TrySplitConfigurationCanonicalName(
canonicalName, out configuration, out platform); | |
948 } | |
949 | |
950 /// <summary> | |
951 /// Determines whether the shell is in command line mode. | |
952 /// </summary> | |
953 /// <param name="serviceProvider">A reference to a Service Provi
der.</param> | |
954 /// <returns>true if the shell is in command line mode. false ot
herwise.</returns> | |
955 internal static bool IsShellInCommandLineMode(System.IServicePro
vider serviceProvider) | |
956 { | |
957 if(serviceProvider == null) | |
958 { | |
959 throw new ArgumentNullException("serviceProvider
"); | |
960 } | |
961 | |
962 IVsShell shell = serviceProvider.GetService(typeof(SVsSh
ell)) as IVsShell; | |
963 if(shell == null) | |
964 { | |
965 throw new InvalidOperationException(); | |
966 } | |
967 | |
968 object isInCommandLineModeAsObject; | |
969 ErrorHandler.ThrowOnFailure(shell.GetProperty((int)__VSS
PROPID.VSSPROPID_IsInCommandLineMode, out isInCommandLineModeAsObject)); | |
970 | |
971 return ((bool)isInCommandLineModeAsObject); | |
972 } | |
973 | |
974 /// <summary> | |
975 /// Saves the dialog state in the solution | |
976 /// </summary> | |
977 /// <param name="serviceProvider">A reference to a Service Provi
der.</param> | |
978 /// <param name="projectLoadSecurityDialogState">The dialog stat
e</param> | |
979 internal static void SaveDialogStateInSolution(IServiceProvider
serviceProvider, _ProjectLoadSecurityDialogState projectLoadSecurityDialogState) | |
980 { | |
981 if(serviceProvider == null) | |
982 { | |
983 throw new ArgumentNullException("serviceProvider
"); | |
984 } | |
985 | |
986 IVsSolution solution = serviceProvider.GetService(typeof
(SVsSolution)) as IVsSolution; | |
987 | |
988 if(solution == null) | |
989 { | |
990 throw new InvalidOperationException(); | |
991 } | |
992 | |
993 ErrorHandler.ThrowOnFailure(solution.SetProperty((int)__
VSPROPID2.VSPROPID_ProjectLoadSecurityDialogState, projectLoadSecurityDialogStat
e)); | |
994 } | |
995 | |
996 /// <summary> | |
997 /// Checks if the project location is secure. | |
998 /// </summary> | |
999 /// <param name="location">The project folder.</param> | |
1000 /// <returns>True if the project location is secure.</returns> | |
1001 internal static bool IsProjectLocationSecure(string location) | |
1002 { | |
1003 if(String.IsNullOrEmpty(location) || location.Length > N
ativeMethods.MAX_PATH) | |
1004 { | |
1005 return false; | |
1006 } | |
1007 | |
1008 Zone zone = Zone.CreateFromUrl(location); | |
1009 if(zone == null) | |
1010 { | |
1011 return false; | |
1012 } | |
1013 | |
1014 // Now use the utilities from the msbuild api to check u
s the path. | |
1015 Microsoft.VisualStudio.Build.ComInteropWrapper.Utilities
utilities = new Microsoft.VisualStudio.Build.ComInteropWrapper.Utilities(); | |
1016 | |
1017 return utilities.CheckPath(location, (int)zone.SecurityZ
one); | |
1018 } | |
1019 } | |
1020 } | |
OLD | NEW |