/// Copyright (c) Microsoft Corporation. All rights reserved. using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Globalization; using System.IO; using System.Runtime.InteropServices; using System.Security.Permissions; using System.Security.Policy; using System.Text; using System.Text.RegularExpressions; using System.Windows.Forms; using Microsoft.VisualStudio; using Microsoft.VisualStudio.OLE.Interop; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.Win32; using IServiceProvider = System.IServiceProvider; using MSBuild = Microsoft.Build.BuildEngine; using VSRegistry = Microsoft.VisualStudio.Shell.VSRegistry; namespace Microsoft.VisualStudio.Project { public static class Utilities { private const string defaultMSBuildVersion = "2.0"; /// /// Look in the registry under the current hive for the path /// of MSBuild /// /// [CLSCompliant(false)] [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Ms")] [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "msbuild")] public static string GetMsBuildPath(IServiceProvider serviceProvider) { return GetMsBuildPath(serviceProvider, defaultMSBuildVersion); } /// /// Search the registry for the tools path for MSBuild. /// /// The service provider. /// Msbuild version. /// The msbuild tools path [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Ms")] public static string GetMsBuildPath(IServiceProvider serviceProvider, string version) { string msBuildPath = null; using(RegistryKey root = VSRegistry.RegistryRoot(serviceProvider, __VsLocalRegistryType.RegType_Configuration, false)) { // Get the value from the registry using(RegistryKey vsKey = root.OpenSubKey("MSBuild", false)) { msBuildPath = (string)vsKey.GetValue("MSBuildBinPath", null); } } if(!string.IsNullOrEmpty(msBuildPath)) { return msBuildPath; } // The path to MSBuild was not found in the VisualStudio's registry hive, so try to // find it in the new MSBuild hive. string registryPath = string.Format(CultureInfo.InvariantCulture, "Software\\Microsoft\\MSBuild\\ToolsVersions\\{0}", version); using(Microsoft.Win32.RegistryKey msbuildKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(registryPath, false)) { msBuildPath = (string)msbuildKey.GetValue("MSBuildToolsPath", null); } if(string.IsNullOrEmpty(msBuildPath)) { string error = SR.GetString(SR.ErrorMsBuildRegistration, CultureInfo.CurrentUICulture); throw new FileLoadException(error); } return msBuildPath; } /// /// Is Visual Studio in design mode. /// /// The service provider. /// true if visual studio is in design mode public static bool IsVisualStudioInDesignMode(IServiceProvider site) { IVsMonitorSelection selectionMonitor = site.GetService(typeof(IVsMonitorSelection)) as IVsMonitorSelection; uint cookie = 0; int active = 0; Guid designContext = VSConstants.UICONTEXT_DesignMode; ErrorHandler.ThrowOnFailure(selectionMonitor.GetCmdUIContextCookie(ref designContext, out cookie)); ErrorHandler.ThrowOnFailure(selectionMonitor.IsCmdUIContextActive(cookie, out active)); return active != 0; } /// /// /// Is an extensibility object executing an automation function. /// /// The service provider. /// true if the extensiblity object is executing an automation function. public static bool IsInAutomationFunction(IServiceProvider serviceProvider) { if(serviceProvider == null) { throw new ArgumentNullException("serviceProvider"); } IVsExtensibility3 extensibility = serviceProvider.GetService(typeof(EnvDTE.IVsExtensibility)) as IVsExtensibility3; if(extensibility == null) { throw new InvalidOperationException(); } int inAutomation = 0; ErrorHandler.ThrowOnFailure(extensibility.IsInAutomationFunction(out inAutomation)); return inAutomation != 0; } /// /// Creates a semicolon delinited list of strings. This can be used to provide the properties for VSHPROPID_CfgPropertyPagesCLSIDList, VSHPROPID_PropertyPagesCLSIDList, VSHPROPID_PriorityPropertyPagesCLSIDList /// /// An array of Guids. /// A semicolon delimited string, or null [CLSCompliant(false)] public static string CreateSemicolonDelimitedListOfStringFromGuids(Guid[] guids) { if(guids == null || guids.Length == 0) { return null; } // Create a StringBuilder with a pre-allocated buffer big enough for the // final string. 39 is the length of a GUID in the "B" form plus the final ';' StringBuilder stringList = new StringBuilder(39 * guids.Length); for(int i = 0; i < guids.Length; i++) { stringList.Append(guids[i].ToString("B")); stringList.Append(";"); } return stringList.ToString().TrimEnd(';'); } private static char[] curlyBraces = new char[] { '{', '}' }; /// /// Take list of guids as a single string and generate an array of Guids from it /// /// Semi-colon separated list of Guids /// Array of Guids [CLSCompliant(false)] public static Guid[] GuidsArrayFromSemicolonDelimitedStringOfGuids(string guidList) { if(guidList == null) { return null; } List guids = new List(); string[] guidsStrings = guidList.Split(';'); foreach(string guid in guidsStrings) { if(!String.IsNullOrEmpty(guid)) guids.Add(new Guid(guid.Trim(curlyBraces))); } return guids.ToArray(); } /// /// Validates a file path by validating all file parts. If the /// the file name is invalid it throws an exception if the project is in automation. Otherwise it shows a dialog box with the error message. /// /// The service provider /// A full path to a file name /// In case of failure an InvalidOperationException is thrown. public static void ValidateFileName(IServiceProvider serviceProvider, string filePath) { string errorMessage = String.Empty; if(String.IsNullOrEmpty(filePath)) { errorMessage = SR.GetString(SR.ErrorInvalidFileName, CultureInfo.CurrentUICulture); } else if(filePath.Length > NativeMethods.MAX_PATH) { errorMessage = String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.PathTooLong, CultureInfo.CurrentUICulture), filePath); } else if(ContainsInvalidFileNameChars(filePath)) { errorMessage = SR.GetString(SR.ErrorInvalidFileName, CultureInfo.CurrentUICulture); } if(errorMessage.Length == 0) { string fileName = Path.GetFileName(filePath); if(String.IsNullOrEmpty(fileName) || IsFileNameInvalid(fileName)) { errorMessage = SR.GetString(SR.ErrorInvalidFileName, CultureInfo.CurrentUICulture); } else { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName); // If there is no filename or it starts with a leading dot issue an error message and quit. if(String.IsNullOrEmpty(fileNameWithoutExtension) || fileNameWithoutExtension[0] == '.') { errorMessage = SR.GetString(SR.FileNameCannotContainALeadingPeriod, CultureInfo.CurrentUICulture); } } } if(errorMessage.Length > 0) { // If it is not called from an automation method show a dialog box. if(!Utilities.IsInAutomationFunction(serviceProvider)) { string title = null; OLEMSGICON icon = OLEMSGICON.OLEMSGICON_CRITICAL; OLEMSGBUTTON buttons = OLEMSGBUTTON.OLEMSGBUTTON_OK; OLEMSGDEFBUTTON defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST; VsShellUtilities.ShowMessageBox(serviceProvider, title, errorMessage, icon, buttons, defaultButton); } else { throw new InvalidOperationException(errorMessage); } } } /// /// Creates a CALPOLESTR from a list of strings /// It is the responsability of the caller to release this memory. /// /// /// A CALPOLESTR that was created from the the list of strings. [CLSCompliant(false)] [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "CALPOLESTR")] public static CALPOLESTR CreateCALPOLESTR(IList strings) { CALPOLESTR calpolStr = new CALPOLESTR(); if(strings != null) { // Demand unmanaged permissions in order to access unmanaged memory. new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand(); calpolStr.cElems = (uint)strings.Count; int size = Marshal.SizeOf(typeof(IntPtr)); calpolStr.pElems = Marshal.AllocCoTaskMem(strings.Count * size); IntPtr ptr = calpolStr.pElems; foreach(string aString in strings) { IntPtr tempPtr = Marshal.StringToCoTaskMemUni(aString); Marshal.WriteIntPtr(ptr, tempPtr); ptr = new IntPtr(ptr.ToInt64() + size); } } return calpolStr; } /// /// Creates a CADWORD from a list of tagVsSccFilesFlags. Memory is allocated for the elems. /// It is the responsability of the caller to release this memory. /// /// /// A CADWORD created from the list of tagVsSccFilesFlags. [CLSCompliant(false)] [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "CADWORD")] public static CADWORD CreateCADWORD(IList flags) { CADWORD cadWord = new CADWORD(); if(flags != null) { // Demand unmanaged permissions in order to access unmanaged memory. new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand(); cadWord.cElems = (uint)flags.Count; int size = Marshal.SizeOf(typeof(UInt32)); cadWord.pElems = Marshal.AllocCoTaskMem(flags.Count * size); IntPtr ptr = cadWord.pElems; foreach(tagVsSccFilesFlags flag in flags) { Marshal.WriteInt32(ptr, (int)flag); ptr = new IntPtr(ptr.ToInt64() + size); } } return cadWord; } /// /// Splits a bitmap from a Stream into an ImageList /// /// A Stream representing a Bitmap /// An ImageList object representing the images from the given stream public static ImageList GetImageList(Stream imageStream) { ImageList ilist = new ImageList(); if(imageStream == null) { return ilist; } ilist.ColorDepth = ColorDepth.Depth24Bit; ilist.ImageSize = new Size(16, 16); Bitmap bitmap = new Bitmap(imageStream); ilist.Images.AddStrip(bitmap); ilist.TransparentColor = Color.Magenta; return ilist; } /// /// Splits a bitmap from a pointer to an ImageList /// /// A pointer to a bitmap of images to split /// An ImageList object representing the images from the given stream public static ImageList GetImageList(object imageListAsPointer) { ImageList images = null; IntPtr intPtr = new IntPtr((int)imageListAsPointer); HandleRef hImageList = new HandleRef(null, intPtr); int count = UnsafeNativeMethods.ImageList_GetImageCount(hImageList); if(count > 0) { // Create a bitmap big enough to hold all the images Bitmap b = new Bitmap(16 * count, 16); Graphics g = Graphics.FromImage(b); // Loop through and extract each image from the imagelist into our own bitmap IntPtr hDC = IntPtr.Zero; try { hDC = g.GetHdc(); HandleRef handleRefDC = new HandleRef(null, hDC); for(int i = 0; i < count; i++) { UnsafeNativeMethods.ImageList_Draw(hImageList, i, handleRefDC, i * 16, 0, NativeMethods.ILD_NORMAL); } } finally { if(g != null && hDC != IntPtr.Zero) { g.ReleaseHdc(hDC); } } // Create a new imagelist based on our stolen images images = new ImageList(); images.ColorDepth = ColorDepth.Depth24Bit; images.ImageSize = new Size(16, 16); images.Images.AddStrip(b); } return images; } /// /// Gets the active configuration name. /// /// The automation object. /// The name of the active configuartion. internal static string GetActiveConfigurationName(EnvDTE.Project automationObject) { if(automationObject == null) { throw new ArgumentNullException("automationObject"); } string currentConfigName = string.Empty; if(automationObject.ConfigurationManager != null) { EnvDTE.Configuration activeConfig = automationObject.ConfigurationManager.ActiveConfiguration; if(activeConfig != null) { currentConfigName = activeConfig.ConfigurationName; } } return currentConfigName; } /// /// Verifies that two objects represent the same instance of a COM object. /// This essentially compares the IUnkown pointers of the 2 objects. /// This is needed in scenario where aggregation is involved. /// /// Can be an object, interface or IntPtr /// Can be an object, interface or IntPtr /// True if the 2 items represent the same thing [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj")] public static bool IsSameComObject(object obj1, object obj2) { bool isSame = false; IntPtr unknown1 = IntPtr.Zero; IntPtr unknown2 = IntPtr.Zero; try { // If we have 2 null, then they are not COM objects and as such "it's not the same COM object" if(obj1 != null && obj2 != null) { unknown1 = QueryInterfaceIUnknown(obj1); unknown2 = QueryInterfaceIUnknown(obj2); isSame = IntPtr.Equals(unknown1, unknown2); } } finally { if(unknown1 != IntPtr.Zero) { Marshal.Release(unknown1); } if(unknown2 != IntPtr.Zero) { Marshal.Release(unknown2); } } return isSame; } /// /// Retrieve the IUnknown for the managed or COM object passed in. /// /// Managed or COM object. /// Pointer to the IUnknown interface of the object. internal static IntPtr QueryInterfaceIUnknown(object objToQuery) { bool releaseIt = false; IntPtr unknown = IntPtr.Zero; IntPtr result; try { if(objToQuery is IntPtr) { unknown = (IntPtr)objToQuery; } else { // This is a managed object (or RCW) unknown = Marshal.GetIUnknownForObject(objToQuery); releaseIt = true; } // We might already have an IUnknown, but if this is an aggregated // object, it may not be THE IUnknown until we QI for it. Guid IID_IUnknown = VSConstants.IID_IUnknown; ErrorHandler.ThrowOnFailure(Marshal.QueryInterface(unknown, ref IID_IUnknown, out result)); } finally { if(releaseIt && unknown != IntPtr.Zero) { Marshal.Release(unknown); } } return result; } /// /// Returns true if thename that can represent a path, absolut or relative, or a file name contains invalid filename characters. /// /// File name /// true if file name is invalid public static bool ContainsInvalidFileNameChars(string name) { if(String.IsNullOrEmpty(name)) { return true; } try { if(Path.IsPathRooted(name) && !name.StartsWith(@"\\", StringComparison.Ordinal)) { string root = Path.GetPathRoot(name); name = name.Substring(root.Length); } } // The Path methods used by ContainsInvalidFileNameChars return argument exception if the filePath contains invalid characters. catch(ArgumentException) { return true; } Microsoft.VisualStudio.Shell.Url uri = new Microsoft.VisualStudio.Shell.Url(name); // This might be confusing bur Url.IsFile means that the uri represented by the name is either absolut or relative. if(uri.IsFile) { string[] segments = uri.Segments; if(segments != null && segments.Length > 0) { foreach(string segment in segments) { if(IsFilePartInValid(segment)) { return true; } } // Now the last segment should be specially taken care, since that cannot be all dots or spaces. string lastSegment = segments[segments.Length - 1]; string filePart = Path.GetFileNameWithoutExtension(lastSegment); if(IsFileNameAllGivenCharacter('.', filePart) || IsFileNameAllGivenCharacter(' ', filePart)) { return true; } } } else { // The assumption here is that we got a file name. string filePart = Path.GetFileNameWithoutExtension(name); if(IsFileNameAllGivenCharacter('.', filePart) || IsFileNameAllGivenCharacter(' ', filePart)) { return true; } return IsFilePartInValid(name); } return false; } /// Cehcks if a file name is valid. /// /// The name of the file /// True if the file is valid. public static bool IsFileNameInvalid(string fileName) { if(String.IsNullOrEmpty(fileName)) { return true; } if(IsFileNameAllGivenCharacter('.', fileName) || IsFileNameAllGivenCharacter(' ', fileName)) { return true; } return IsFilePartInValid(fileName); } /// /// Helper method to call a converter explicitely to convert to an enum type /// /// THe enum to convert to /// The converter that will be created /// The enum value to be converted to /// The type to convert /// The culture to use to read the localized strings /// [CLSCompliant(false)] public static object ConvertToType(T value, Type typeToConvert, CultureInfo culture) where T : struct { EnumConverter converter = GetEnumConverter(); if(converter == null) { return null; } if(converter.CanConvertTo(typeToConvert)) { return converter.ConvertTo(null, culture, value, typeToConvert); } return null; } /// /// Helper method for converting from a string to an enum using a converter. /// /// /// /// The culture to use to read the localized strings /// [CLSCompliant(false)] public static Nullable ConvertFromType(string value, CultureInfo culture) where T : struct { Nullable returnValue = new Nullable(); returnValue = returnValue.GetValueOrDefault(); if(value == null) { return returnValue; } EnumConverter converter = GetEnumConverter(); if(converter == null) { return returnValue; } if(converter.CanConvertFrom(value.GetType())) { object converted = converter.ConvertFrom(null, culture, value); if(converted != null && (converted is T)) { returnValue = (T)converted; } } return returnValue; } /// /// Sets a string value from an enum /// /// The enum type /// The value of teh enum. /// [CLSCompliant(false)] public static string SetStringValueFromConvertedEnum(T enumValue, CultureInfo culture) where T : struct { string convertToType = ConvertToType(enumValue, typeof(string), culture) as string; if(convertToType == null) { return String.Empty; } return convertToType; } /// /// Initializes the in memory project. Sets BuildEnabled on the project to true. /// /// The build engine to use to create a build project. /// The full path of the project. /// A loaded msbuild project. internal static MSBuild.Project InitializeMsBuildProject(MSBuild.Engine buildEngine, string fullProjectPath) { if(buildEngine == null) { throw new ArgumentNullException("buildEngine"); } if(String.IsNullOrEmpty(fullProjectPath)) { throw new ArgumentException(SR.GetString(SR.InvalidParameter, CultureInfo.CurrentUICulture), "fullProjectPath"); } // Check if the project already has been loaded with the fullProjectPath. If yes return the build project associated to it. MSBuild.Project buildProject = buildEngine.GetLoadedProject(fullProjectPath); if(buildProject == null) { buildProject = buildEngine.CreateNewProject(); buildProject.BuildEnabled = true; buildProject.Load(fullProjectPath); } return buildProject; } /// /// Loads a project file for the file. If the build project exists and it was loaded with a different file then it is unloaded first. /// /// The build engine to use to create a build project. /// The full path of the project. /// An Existing build project that will be reloaded. /// A loaded msbuild project. internal static MSBuild.Project ReinitializeMsBuildProject(MSBuild.Engine buildEngine, string fullProjectPath, MSBuild.Project exitingBuildProject) { // If we have a build project that has been loaded with another file unload it. try { if(exitingBuildProject != null && exitingBuildProject.ParentEngine != null && !NativeMethods.IsSamePath(exitingBuildProject.FullFileName, fullProjectPath)) { exitingBuildProject.ParentEngine.UnloadProject(exitingBuildProject); } } // We catch Invalid operation exception because if the project was unloaded while we touch the ParentEngine the msbuild API throws. // Is there a way to figure out that a project was unloaded? catch(InvalidOperationException) { } return Utilities.InitializeMsBuildProject(buildEngine, fullProjectPath); } /// /// 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 have its bin path set. /// /// An instance of MSBuild.Engine build engine, that will be checked if initialized. /// The service provider. /// The buildengine to use. internal static MSBuild.Engine InitializeMsBuildEngine(MSBuild.Engine existingEngine, IServiceProvider serviceProvider) { if(serviceProvider == null) { throw new ArgumentNullException("serviceProvider"); } if(existingEngine == null) { MSBuild.Engine buildEngine = MSBuild.Engine.GlobalEngine; return buildEngine; } return existingEngine; } /// /// Gets an instance of an EnumConverter for enums that have PropertyPageTypeConverter attribute /// /// The type to search for the PropertyPageTypeConverter attribute. /// An instance of an enum converter, or null if none found. private static EnumConverter GetEnumConverter() where T : struct { object[] attributes = typeof(T).GetCustomAttributes(typeof(PropertyPageTypeConverterAttribute), true); // There should be only one PropertyPageTypeConverterAttribute defined on T if(attributes != null && attributes.Length == 1) { Debug.Assert(attributes[0] is PropertyPageTypeConverterAttribute, "The returned attribute must be an attribute is PropertyPageTypeConverterAttribute"); PropertyPageTypeConverterAttribute converterAttribute = (PropertyPageTypeConverterAttribute)attributes[0]; if(converterAttribute.ConverterType.IsSubclassOf(typeof(EnumConverter))) { return Activator.CreateInstance(converterAttribute.ConverterType) as EnumConverter; } } return null; } /// > /// Checks if the file name is all the given character. /// private static bool IsFileNameAllGivenCharacter(char c, string fileName) { // A valid file name cannot be all "c" . int charFound = 0; for(charFound = 0; charFound < fileName.Length && fileName[charFound] == c; ++charFound) ; if(charFound >= fileName.Length) { return true; } return false; } /// /// Checks whether a file part contains valid characters. The file part can be any part of a non rooted path. /// /// /// private static bool IsFilePartInValid(string filePart) { if(String.IsNullOrEmpty(filePart)) { return true; } String reservedName = "(\\b(nul|con|aux|prn)\\b)|(\\b((com|lpt)[0-9])\\b)"; String invalidChars = @"([/?:&\\*<>|#%" + '\"' + "])"; String regexToUseForFileName = reservedName + "|" + invalidChars; String fileNameToVerify = filePart; // Define a regular expression that covers all characters that are not in the safe character sets. // It is compiled for performance. // The filePart might still be a file and extension. If it is like that then we must check them separately, since different rules apply string extension = String.Empty; try { extension = Path.GetExtension(filePart); } // We catch the ArgumentException because we want this method to return true if the filename is not valid. FilePart could be for example #¤&%"¤&"% and that would throw ArgumentException on GetExtension catch(ArgumentException) { return true; } if(!String.IsNullOrEmpty(extension)) { // Check the extension first String regexToUseForExtension = invalidChars; Regex unsafeCharactersRegex = new Regex(regexToUseForExtension, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); bool isMatch = unsafeCharactersRegex.IsMatch(extension); if(isMatch) { return isMatch; } // We want to verify here everything but the extension. // We cannot use GetFileNameWithoutExtension because it might be that for example (..\\filename.txt) is passed in asnd that should fail, since that is not a valid filename. fileNameToVerify = filePart.Substring(0, filePart.Length - extension.Length); if(String.IsNullOrEmpty(fileNameToVerify)) { return true; } } // We verify CLOCK$ outside the regex since for some reason the regex is not matching the clock\\$ added. if(String.Compare(fileNameToVerify, "CLOCK$", StringComparison.OrdinalIgnoreCase) == 0) { return true; } Regex unsafeFileNameCharactersRegex = new Regex(regexToUseForFileName, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); return unsafeFileNameCharactersRegex.IsMatch(fileNameToVerify); } /// /// Copy a directory recursively to the specified non-existing directory /// /// Directory to copy from /// Directory to copy to public static void RecursivelyCopyDirectory(string source, string target) { // Make sure it doesn't already exist if(Directory.Exists(target)) throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.FileOrFolderAlreadyExists, CultureInfo.CurrentUICulture), target)); Directory.CreateDirectory(target); DirectoryInfo directory = new DirectoryInfo(source); // Copy files foreach(FileInfo file in directory.GetFiles()) { file.CopyTo(Path.Combine(target, file.Name)); } // Now recurse to child directories foreach(DirectoryInfo child in directory.GetDirectories()) { RecursivelyCopyDirectory(child.FullName, Path.Combine(target, child.Name)); } } /// /// Canonicalizes a file name, including: /// - determines the full path to the file /// - casts to upper case /// Canonicalizing a file name makes it possible to compare file names using simple simple string comparison. /// /// Note: this method does not handle shared drives and UNC drives. /// /// A file name, which can be relative/absolute and contain lower-case/upper-case characters. /// Canonicalized file name. internal static string CanonicalizeFileName(string anyFileName) { // Get absolute path // Note: this will not handle UNC paths FileInfo fileInfo = new FileInfo(anyFileName); string fullPath = fileInfo.FullName; // Cast to upper-case fullPath = fullPath.ToUpper(CultureInfo.CurrentCulture); return fullPath; } /// /// Determines if a file is a template. /// /// The file to check whether it is a template file /// true if the file is a template file internal static bool IsTemplateFile(string fileName) { if(String.IsNullOrEmpty(fileName)) { return false; } string extension = Path.GetExtension(fileName); return (String.Compare(extension, ".vstemplate", StringComparison.OrdinalIgnoreCase) == 0 || string.Compare(extension, ".vsz", StringComparison.OrdinalIgnoreCase) == 0); } /// /// Retrives the configuration and the platform using the IVsSolutionBuildManager2 interface. /// /// A service provider. /// The hierrachy whose configuration is requested. /// The name of the active configuration. /// The name of the platform. /// true if successfull. internal static bool TryGetActiveConfigurationAndPlatform(System.IServiceProvider serviceProvider, IVsHierarchy hierarchy, out string configuration, out string platform) { if(serviceProvider == null) { throw new ArgumentNullException("serviceProvider"); } if(hierarchy == null) { throw new ArgumentNullException("hierarchy"); } configuration = String.Empty; platform = String.Empty; IVsSolutionBuildManager2 solutionBuildManager = serviceProvider.GetService(typeof(SVsSolutionBuildManager)) as IVsSolutionBuildManager2; if(solutionBuildManager == null) { return false; } IVsProjectCfg[] activeConfigs = new IVsProjectCfg[1]; ErrorHandler.ThrowOnFailure(solutionBuildManager.FindActiveProjectCfg(IntPtr.Zero, IntPtr.Zero, hierarchy, activeConfigs)); IVsProjectCfg activeCfg = activeConfigs[0]; // Can it be that the activeCfg is null? System.Diagnostics.Debug.Assert(activeCfg != null, "Cannot find the active configuration"); string canonicalName; ErrorHandler.ThrowOnFailure(activeCfg.get_CanonicalName(out canonicalName)); return ProjectConfig.TrySplitConfigurationCanonicalName(canonicalName, out configuration, out platform); } /// /// Determines whether the shell is in command line mode. /// /// A reference to a Service Provider. /// true if the shell is in command line mode. false otherwise. internal static bool IsShellInCommandLineMode(System.IServiceProvider serviceProvider) { if(serviceProvider == null) { throw new ArgumentNullException("serviceProvider"); } IVsShell shell = serviceProvider.GetService(typeof(SVsShell)) as IVsShell; if(shell == null) { throw new InvalidOperationException(); } object isInCommandLineModeAsObject; ErrorHandler.ThrowOnFailure(shell.GetProperty((int)__VSSPROPID.VSSPROPID_IsInCommandLineMode, out isInCommandLineModeAsObject)); return ((bool)isInCommandLineModeAsObject); } /// /// Saves the dialog state in the solution /// /// A reference to a Service Provider. /// The dialog state internal static void SaveDialogStateInSolution(IServiceProvider serviceProvider, _ProjectLoadSecurityDialogState projectLoadSecurityDialogState) { if(serviceProvider == null) { throw new ArgumentNullException("serviceProvider"); } IVsSolution solution = serviceProvider.GetService(typeof(SVsSolution)) as IVsSolution; if(solution == null) { throw new InvalidOperationException(); } ErrorHandler.ThrowOnFailure(solution.SetProperty((int)__VSPROPID2.VSPROPID_ProjectLoadSecurityDialogState, projectLoadSecurityDialogState)); } /// /// Checks if the project location is secure. /// /// The project folder. /// True if the project location is secure. internal static bool IsProjectLocationSecure(string location) { if(String.IsNullOrEmpty(location) || location.Length > NativeMethods.MAX_PATH) { return false; } Zone zone = Zone.CreateFromUrl(location); if(zone == null) { return false; } // Now use the utilities from the msbuild api to check us the path. Microsoft.VisualStudio.Build.ComInteropWrapper.Utilities utilities = new Microsoft.VisualStudio.Build.ComInteropWrapper.Utilities(); return utilities.CheckPath(location, (int)zone.SecurityZone); } } }