/// <summary> /// Attempts to find the document information for the specified file. /// </summary> /// <param name="absolutePath">The absolute path of the file to search for.</param> /// <returns>A <see cref="DocumentInfo"/> object if the file was found; otherwise, null.</returns> public DocumentInfo FindByPath(string absolutePath) { Tracer.VerifyStringArgument(absolutePath, "absolutePath"); DocumentInfo documentInfo = null; // Make the call to IVsRunningDocumentTable.FindAndLockDocument to try to find the document. uint lockType = unchecked ((uint)_VSRDTFLAGS.RDT_NoLock); IVsHierarchy vsHierarchy; uint hierarchyId; IntPtr punkDocData; uint cookie; int hr = this.Rdt.FindAndLockDocument(lockType, absolutePath, out vsHierarchy, out hierarchyId, out punkDocData, out cookie); NativeMethods.ThrowOnFailure(hr); if (punkDocData != IntPtr.Zero) { try { object docData = Marshal.GetObjectForIUnknown(punkDocData); Tracer.Assert(docData != null, "We should be getting something for punkDocData instead of null."); if (docData != null) { documentInfo = new DocumentInfo(absolutePath, vsHierarchy, hierarchyId, docData, cookie); } } finally { Marshal.Release(punkDocData); } } return(documentInfo); }
/// <summary> /// Notifies all of the listeners that a configuration name has been changed. /// </summary> /// <param name="oldName">The old name of the configuration that was changed.</param> /// <param name="newName">The new name of the configuration that was changed.</param> public void OnCfgNameRenamed(string oldName, string newName) { Tracer.VerifyStringArgument(oldName, "oldName"); Tracer.VerifyStringArgument(newName, "newName"); // Let all of our listeners know that the hierarchy needs to be refreshed. Tracer.WriteLine(classType, "OnCfgNameRenamed", Tracer.Level.Information, "Notifying all of our listeners that the configuration '{0}' has been renamed to '{1}'.", oldName, newName); // There are some cases where the collection is changed while we're iterating it. // To be safe, we'll create a copy of the collection and iterate over that. // We just want a shallow copy, though, and not a deep (Clone) copy. ArrayList clone = new ArrayList(this.Values); foreach (IVsCfgProviderEvents eventItem in clone) { try { eventItem.OnCfgNameRenamed(oldName, newName); } catch (Exception e) { Tracer.WriteLine(classType, "OnCfgNameRenamed", Tracer.Level.Warning, "There was an exception in one of the listener's event handling code: {0}", e.ToString()); } } }
//========================================================================================== // Methods //========================================================================================== /// <summary> /// Combines two registry paths. /// </summary> /// <param name="path1">The first path to combine.</param> /// <param name="path2">The second path to combine.</param> /// <returns>The concatenation of the first path with the second, delimeted with a '\'.</returns> protected string RegistryPathCombine(string path1, string path2) { Tracer.VerifyStringArgument(path1, "path1"); Tracer.VerifyStringArgument(path2, "path2"); return(PackageUtility.EnsureTrailingChar(path1, '\\') + path2); }
/// <summary> /// Generates a unique document name for a new node under the parent node. /// </summary> /// <param name="suggestedRoot">The suggested root to use for the unique name.</param> /// <param name="extension">The extension to use for the new file or folder (with or without the leading '.'). Can be null or empty.</param> /// <param name="isFolder">Indicates whether the new name is intended to be a file or a folder.</param> /// <returns>A unique document name for a new node under the this node.</returns> public string GenerateUniqueName(string suggestedRoot, string extension, bool isFolder) { Tracer.VerifyStringArgument(suggestedRoot, "suggestedRoot"); int suffixNumber = 0; bool foundUnique = false; string uniqueName = String.Empty; // Canonicalize the extension by setting it either to "" or prepend it with a '.' extension = ((extension == null || extension.Length == 0) ? String.Empty : PackageUtility.EnsureLeadingChar(extension, '.')); // We have to make sure that this item doesn't already exist in the hierarchy and the file system. while (!foundUnique) { if (suffixNumber == 0) { uniqueName = suggestedRoot + extension; } else { uniqueName = suggestedRoot + suffixNumber + extension; } // Look in the hierarchy to see if there is an existing item with the proposed name. foundUnique = true; foreach (Node node in this.Children) { if (PackageUtility.FileStringEquals(uniqueName, node.Caption)) { foundUnique = false; break; } } // If the name is unique within the hierarchy, we still need to check the file system. if (foundUnique) { string pathToCheck = Path.Combine(this.AbsoluteDirectory, uniqueName); if (isFolder && Directory.Exists(pathToCheck)) { foundUnique = false; } else if (!isFolder && File.Exists(pathToCheck)) { foundUnique = false; } else { // Ok, we found a unique name. break; } } // Increment the number to append to the root part of the path. suffixNumber++; } Tracer.WriteLineInformation(classType, "GenerateUniqueName", "Found a unique name for a new node. New name = '{0}'.", uniqueName); return(uniqueName); }
//========================================================================================== // Constructors //========================================================================================== public ProjectConfiguration(Project project, string name) { Tracer.VerifyNonNullArgument(project, "project"); Tracer.VerifyStringArgument(name, "name"); this.project = project; this.name = name; }
/// <summary> /// Adds the specified character to the end of the string if it doesn't already exist at the end. /// </summary> /// <param name="value">The string to add the trailing character to.</param> /// <param name="charToEnsure">The character that will be at the end of the string upon return.</param> /// <returns>The original string with the specified character at the end.</returns> public static string EnsureTrailingChar(string value, char charToEnsure) { Tracer.VerifyStringArgument(value, "value"); if (value[value.Length - 1] != charToEnsure) { value += charToEnsure; } return(value); }
int IVsCfgProvider2.DeleteCfgsOfCfgName(string pszCfgName) { Tracer.VerifyStringArgument(pszCfgName, "pszCfgName"); if (this.ProjectConfigurations.Contains(pszCfgName)) { this.ProjectConfigurations.Remove(pszCfgName); } return NativeMethods.S_OK; }
public void Remove(string name) { Tracer.VerifyStringArgument(name, "name"); int index = this.IndexOf(name); if (index >= 0) { this.RemoveAt(index); } }
//========================================================================================== // Methods //========================================================================================== /// <summary> /// Copies the attached project and all of its referenced files to the destination directory. /// </summary> /// <param name="destinationPath">The destination path where the project file will be copied to.</param> /// <returns>A copy of the attached project rooted at <paramref name="destinationDirectory"/> or null if there were errors.</returns> public Project CopyTo(string destinationPath) { Tracer.VerifyStringArgument(destinationPath, "destinationPath"); bool successful; // Reference the attached project. Project sourceProject = this.Project; // Create the destination project and a new project serializer for it. ProjectSerializer destSerializer = (ProjectSerializer)this.MemberwiseClone(); Project destProject = this.CreateProject(destSerializer); // We have to have a back pointer from the serializer to the project otherwise when we go to // save the destination project, we'll have a null project pointer. destSerializer.project = destProject; // Set the destination project's properties. destProject.ProjectGuid = sourceProject.ProjectGuid; destProject.FilePath = destinationPath; string destDirectory = Path.GetDirectoryName(destProject.FilePath); // Create the destination directory if it doesn't already exist. if (!Directory.Exists(destDirectory)) { Directory.CreateDirectory(destDirectory); } // Copy the build settings. destProject.BuildSettings = (BuildSettings)sourceProject.BuildSettings.Clone(); // Copy all of the configurations. destProject.ConfigurationProvider = sourceProject.ConfigurationProvider.Clone(destProject); // Loop through the files, copying each file to the destination directory. // TODO: Change the relative path of linked files. successful = this.CopyNodeFiles(sourceProject.RootNode, destProject, destProject.RootNode); // Loop through the references, adding them to the project. if (successful) { foreach (ReferenceFileNode referenceFile in sourceProject.ReferencesNode.Children) { destProject.AddReference(referenceFile.AbsolutePath, false); } } // Now save the destination project. if (successful) { successful = destProject.Serializer.Save(); } return(successful ? destProject : null); }
public ProjectConfiguration this[string name] { get { Tracer.VerifyStringArgument(name, "name"); int index = this.IndexOf(name); if (index >= 0) { return(this[index]); } return(null); } }
//========================================================================================== // Constructors //========================================================================================== /// <summary> /// Initializes a new instance of the <see cref="DocumentInfo"/> class. /// </summary> public DocumentInfo(string absolutePath, IVsHierarchy vsHierarchy, uint hierarchyId, object documentData, uint cookie) { Tracer.VerifyStringArgument(absolutePath, "absolutePath"); Tracer.VerifyNonNullArgument(documentData, "documentData"); this.absolutePath = absolutePath; this.visualStudioHierarchy = vsHierarchy; this.hierarchyId = hierarchyId; this.documentData = documentData; this.cookie = cookie; // The document is open if it has a hierarchy and a cookie. this.isOpen = (vsHierarchy != null && cookie != NullCookie); }
/// <summary> /// Renames and/or changes the ownership of a document. /// </summary> /// <param name="oldFilePath">Absolute path to the previous document.</param> /// <param name="newFilePath">Absolute path to the current document.</param> /// <param name="newHierarchyId">The hierarchy identifier of the current document or 0 if no change.</param> public void RenameDocument(string oldFilePath, string newFilePath, uint newHierarchyId) { int hr; Tracer.VerifyStringArgument(oldFilePath, "oldFilePath"); Tracer.VerifyStringArgument(newFilePath, "newFilePath"); if (newHierarchyId == NativeMethods.VSITEMID_NIL) { throw new ArgumentException("Cannot specify VSITEMID_NIL for the new hierarchy id.", "newHierarchyId"); } // See if the document needs to be renamed (if it's in the RDT). DocumentInfo docInfo = this.FindByPath(oldFilePath); if (docInfo == null) { return; } // Get an IUnknown pointer for the new hierarchy. IntPtr punkHierarchy = Marshal.GetIUnknownForObject(docInfo.VisualStudioHierarhcy); if (punkHierarchy != IntPtr.Zero) { try { // Get an IVsHierarchy pointer. We have to do this two-step process of getting an IUnknown // and then querying for an IVsHierarchy because in the nested hierarchy case we could get // different pointers. IntPtr pvsHierarchy = IntPtr.Zero; Guid vsHierarchyGuid = typeof(IVsHierarchy).GUID; NativeMethods.ThrowOnFailure(Marshal.QueryInterface(punkHierarchy, ref vsHierarchyGuid, out pvsHierarchy)); try { hr = this.Rdt.RenameDocument(oldFilePath, newFilePath, pvsHierarchy, newHierarchyId); NativeMethods.ThrowOnFailure(hr); } finally { Marshal.Release(pvsHierarchy); } } finally { Marshal.Release(punkHierarchy); } } }
/// <summary> /// Loads a project template file, serializing it into the specified project at the specified destination. /// </summary> /// <param name="templatePath">The absolute path of the template project file to load.</param> /// <param name="destinationPath">The absolute path to the new project file.</param> /// <returns>true if the project file was loaded correctly; otherwise, false.</returns> public bool LoadFromTemplate(string templatePath, string destinationPath) { Tracer.VerifyStringArgument(templatePath, "templatePath"); Tracer.VerifyStringArgument(destinationPath, "destinationPath"); bool successful = false; // Load the template project. if (this.Load(templatePath)) { // Copy the loaded template to the real location of the new project. this.project = this.CopyTo(destinationPath); successful = (this.project != null); } return(successful); }
int IVsCfgProvider2.AddCfgsOfCfgName(string pszCfgName, string pszCloneCfgName, int fPrivate) { Tracer.VerifyStringArgument(pszCfgName, "pszCfgName"); // If we need to clone, then get the configurtaions to clone. if (pszCloneCfgName != null && pszCloneCfgName.Length > 0 && this.ProjectConfigurations.Contains(pszCloneCfgName)) { ProjectConfiguration source = this.ProjectConfigurations[pszCloneCfgName]; ProjectConfiguration clonedConfig = source.Clone(pszCfgName); this.ProjectConfigurations.Add(clonedConfig); } else { // Create a new configuration, since there was nothing to clone. ProjectConfiguration newConfig = new ProjectConfiguration(this.Project, pszCfgName); this.ProjectConfigurations.Add(newConfig); } return NativeMethods.S_OK; }
/// <summary> /// Gets a localized string like "The package requires that service '{0}' be installed. Ensure that this service is available by repairing your Visual Studio installation." /// </summary> /// <param name="serviceName"></param> /// <returns></returns> public static string ErrorMissingService(string serviceName) { Tracer.VerifyStringArgument(serviceName, "serviceName"); return(GetString(StringId.ErrorMissingService, serviceName)); }
//========================================================================================== // Constructors //========================================================================================== /// <summary> /// Initializes a new instance of the <see cref="PropertyPage"/> class. /// </summary> /// <param name="name">The localized name of the property page.</param> protected PropertyPage(string name) { Tracer.VerifyStringArgument(name, "name"); this.name = name; }
//========================================================================================== // Constructors / Finalizer //========================================================================================== /// <summary> /// Initializes a new instance of the <see cref="FileChangeNotificationSuspender"/> class. /// </summary> /// <param name="filePath">The absolute path of the file to suspend notifications about.</param> public FileChangeNotificationSuspender(string filePath) { Tracer.VerifyStringArgument(filePath, "filePath"); this.filePath = filePath; this.Suspend(); }
int IVsProjectFactory.CreateProject(string pszFilename, string pszLocation, string pszName, uint grfCreateFlags, ref Guid iidProject, out IntPtr ppvProject, out int pfCanceled) { IntPtr pUnk = IntPtr.Zero; pfCanceled = 0; ppvProject = IntPtr.Zero; bool loadedSuccessfully = false; try { Tracer.VerifyStringArgument(pszFilename, "pszFilename"); __VSCREATEPROJFLAGS createFlags = (__VSCREATEPROJFLAGS)grfCreateFlags; // Get the right version of the project serializer. ProjectSerializer serializer = this.CreateSerializer(pszFilename); // Do we need to suppress any load failures from being reported to the end user. serializer.SilentFailures = ((createFlags & __VSCREATEPROJFLAGS.CPF_SILENT) == __VSCREATEPROJFLAGS.CPF_SILENT); // Now we need to load the project, either from a template file or from an existing file. bool openExisting = ((createFlags & __VSCREATEPROJFLAGS.CPF_OPENFILE) == __VSCREATEPROJFLAGS.CPF_OPENFILE); bool openFromTemplate = ((createFlags & __VSCREATEPROJFLAGS.CPF_CLONEFILE) == __VSCREATEPROJFLAGS.CPF_CLONEFILE); Tracer.Assert((openExisting && !openFromTemplate) || (!openExisting && openFromTemplate), "The grfCreateFlags are incorrect. You can't have both opening existing and opening from template. Flags={0}", createFlags); if (openExisting) { Tracer.WriteLineInformation(classType, "IVsProjectFactory.CreateProject", "Attempting to load project: File name={0} Location={1} Name={2} GUID={3}.", pszFilename, pszLocation, pszName, iidProject.ToString("B").ToUpper(CultureInfo.InvariantCulture)); loadedSuccessfully = serializer.Load(pszFilename); if (loadedSuccessfully) { Tracer.WriteLineInformation(classType, "IVsProjectFactory.CreateProject", "Successfully loaded project '{0}'.", pszFilename); } else { Tracer.WriteLineInformation(classType, "IVsProjectFactory.CreateProject", "There were errors in loading project '{0}'.", pszFilename); } } else { Tracer.WriteLineInformation(classType, "IVsProjectFactory.CreateProject", "Attempting to create a new project from a template: File name={0} Location={1} Name={2} GUID={3}.", pszFilename, pszLocation, pszName, iidProject.ToString("B").ToUpper(CultureInfo.InvariantCulture)); Tracer.VerifyStringArgument(pszLocation, "pszLocation"); Tracer.VerifyStringArgument(pszName, "pszName"); string destinationFile = Path.Combine(pszLocation, pszName); loadedSuccessfully = serializer.LoadFromTemplate(pszFilename, destinationFile); if (loadedSuccessfully) { Tracer.WriteLineInformation(classType, "IVsProjectFactory.CreateProject", "Successfully loaded project '{0}'.", pszFilename); } else { Tracer.WriteLineInformation(classType, "IVsProjectFactory.CreateProject", "There were errors in loading project '{0}'.", pszFilename); } } if (loadedSuccessfully) { // Once we've loaded the project, we need to return the COM object that the environment is requesting. pUnk = Marshal.GetIUnknownForObject(serializer.Project); int hr = Marshal.QueryInterface(pUnk, ref iidProject, out ppvProject); Tracer.Assert(NativeMethods.Succeeded(hr), "Cannot get the requested project interface ({0}): returned {1}", iidProject.ToString("B").ToUpper(CultureInfo.InvariantCulture), hr); NativeMethods.ThrowOnFailure(hr); } } catch (Exception e) { Package.Instance.Context.NotifyInternalError(e.ToString()); } finally { if (pUnk != IntPtr.Zero) { Marshal.Release(pUnk); } } return(loadedSuccessfully ? NativeMethods.S_OK : NativeMethods.E_FAIL); }
/// <summary> /// Gets a localized string like "{0} (unavailable)". /// </summary> /// <param name="caption">The caption of the unavailable node.</param> /// <returns>A localized string like "{0} (unavailable)".</returns> public static string UnavailableCaption(string caption) { Tracer.VerifyStringArgument(caption, "caption"); return(GetString(StringId.UnavailableCaption, caption)); }
/// <summary> /// Gets a localized string like "The file '{0}' does not exist." /// </summary> /// <param name="fileName">The file name that doesn't exist.</param> /// <returns>A localized string like "The file '{0}' does not exist."</returns> public static string FileDoesNotExist(string fileName) { Tracer.VerifyStringArgument(fileName, "fileName"); return(GetString(StringId.FileDoesNotExist, fileName)); }
/// <summary> /// Loads a project file from disk. /// </summary> /// <param name="filePath">The absolute path of the project file to load.</param> /// <returns>true if the project file was loaded correctly; otherwise, false.</returns> public bool Load(string filePath) { Tracer.VerifyStringArgument(filePath, "filePath"); // Create a new project. this.project = this.CreateProject(this); // Set the project's file path to the one being loaded in. Do this first in case we have // to make the project unavailable it can still display the correct caption in Solution Explorer. this.Project.FilePath = filePath; // Make sure the file exists. if (!File.Exists(filePath)) { if (!this.SilentFailures) { string message = SconceStrings.FileDoesNotExist(filePath); Package.Instance.Context.ShowErrorMessageBox(message); } this.Project.Unavailable = true; Tracer.WriteLine(classType, "Load", Tracer.Level.Warning, "The project file '{0}' does not exist.", filePath); return(false); } try { using (StreamReader stream = new StreamReader(filePath)) { XmlTextReader reader = new XmlTextReader(stream); reader.WhitespaceHandling = WhitespaceHandling.None; XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(reader); XmlNode node = xmlDoc.DocumentElement; // <VisualStudioProject> if (!this.VerifyNode(node, ElementNames.VisualStudioProject)) { this.Project.Unavailable = true; return(false); } node = node.FirstChild; if (!this.ReadProjectNode(node)) { this.Project.Unavailable = true; return(false); } } } catch (XmlException e) { if (!this.SilentFailures) { string projectFileName = Path.GetFileName(filePath); string title = Package.Instance.Context.NativeResources.GetString(ResId.IDS_E_INVALIDPROJECTFILE_TITLE); string message = Package.Instance.Context.NativeResources.GetString(ResId.IDS_E_INVALIDPROJECTFILE, projectFileName); Package.Instance.Context.ShowErrorMessageBox(title, message); } this.Project.Unavailable = true; Tracer.Fail("There was an error parsing '{0}': {1}", filePath, e.ToString()); return(false); } // Once the project has been loaded, it's not dirty anymore. this.Project.ClearDirty(); return(true); }
/// <summary> /// Gets a localized string like "A file or folder with the name '{0}' already exists on disk at this location. Please choose another name." /// </summary> /// <param name="fileOrFolderName">The file or folder name that already exists.</param> /// <returns>A localized string like "A file or folder with the name '{0}' already exists on disk at this location. Please choose another name."</returns> public static string ErrorItemAlreadyExistsOnDisk(string fileOrFolderName) { Tracer.VerifyStringArgument(fileOrFolderName, "fileOrFolderName"); return(GetString(StringId.ErrorItemAlreadyExistsOnDisk, fileOrFolderName)); }
//========================================================================================== // Methods //========================================================================================== /// <summary> /// Gets a localized string like "Please consult the trace log at '{0}' for more information." /// </summary> /// <param name="traceLogPath">The path to the trace log file.</param> /// <returns>A localized string like "Please consult the trace log at '{0}' for more information."</returns> public static string ConsultTraceLog(string traceLogPath) { Tracer.VerifyStringArgument(traceLogPath, "traceLogPath"); return(GetString(StringId.ConsultTraceLog, traceLogPath)); }