/// <summary> /// Adds a folder to the collection of ProjectItems with the given name. /// The kind must be null, empty string, or the string value of vsProjectItemKindPhysicalFolder. /// Virtual folders are not supported by this implementation. /// </summary> /// <param name="name">The name of the new folder to add</param> /// <param name="kind">A string representing a Guid of the folder kind.</param> /// <returns>A ProjectItem representing the newly added folder.</returns> public override ProjectItem AddFolder(string name, string kind) { Project.CheckProjectIsValid(); //Verify name is not null or empty Utilities.ValidateFileName(Project.Project.Site, name); //Verify that kind is null, empty, or a physical folder if (!(string.IsNullOrEmpty(kind) || kind.Equals(EnvDTE.Constants.vsProjectItemKindPhysicalFolder))) { throw new ArgumentException("Parameter specification for AddFolder was not meet", "kind"); } for (HierarchyNode child = NodeWithItems.FirstChild; child != null; child = child.NextSibling) { if (child.Caption.Equals(name, StringComparison.OrdinalIgnoreCase)) { throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "Folder already exists with the name '{0}'", name)); } } ProjectNode proj = Project.Project; HierarchyNode newFolder = null; using (var scope = new AutomationScope(Project.Project.Site)) { //In the case that we are adding a folder to a folder, we need to build up //the path to the project node. name = Path.Combine(NodeWithItems.VirtualNodeName, name); newFolder = proj.CreateFolderNodes(name); } return newFolder.GetAutomationObject() as ProjectItem; }
/// <summary> /// Sets the value of the property at the specified index. /// </summary> /// <param name="index1">The index of the item to set.</param> /// <param name="index2">Reserved for future use.</param> /// <param name="index3">Reserved for future use.</param> /// <param name="index4">Reserved for future use.</param> /// <param name="value">The value to set.</param> public void set_IndexedValue(object index1, object index2, object index3, object index4, object value) { ThreadHelper.JoinableTaskFactory.Run(async delegate { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); ParameterInfo[] par = pi.GetIndexParameters(); int len = Math.Min(par.Length, 4); if (len == 0) { this.Value = value; } else { object[] index = new object[len]; Array.Copy(new object[4] { index1, index2, index3, index4 }, index, len); using (AutomationScope scope = new AutomationScope(this.parent.Target.Node.ProjectMgr.Site)) { this.pi.SetValue(this.parent.Target, value, index); } } }); }
/// <summary> /// Adds an item to the project. /// </summary> /// <param name="path">The full path of the item to add.</param> /// <param name="op">The <paramref name="VSADDITEMOPERATION"/> to use when adding the item.</param> /// <returns>A ProjectItem object. </returns> protected virtual EnvDTE.ProjectItem AddItem(string path, VSADDITEMOPERATION op) { if (this.Project == null || this.Project.Project == null || this.Project.Project.Site == null || this.Project.Project.IsClosed) { throw new InvalidOperationException(); } return(UIThread.DoOnUIThread(delegate() { ProjectNode proj = this.Project.Project; EnvDTE.ProjectItem itemAdded = null; using (AutomationScope scope = new AutomationScope(this.Project.Project.Site)) { VSADDRESULT[] result = new VSADDRESULT[1]; ErrorHandler.ThrowOnFailure(proj.AddItem(this.NodeWithItems.ID, op, path, 0, new string[1] { path }, IntPtr.Zero, result)); string fileName = System.IO.Path.GetFileName(path); string fileDirectory = proj.GetBaseDirectoryForAddingFiles(this.NodeWithItems); string filePathInProject = System.IO.Path.Combine(fileDirectory, fileName); itemAdded = this.EvaluateAddResult(result[0], filePathInProject); } return itemAdded; })); }
/// <summary> /// Adds an item to the project. /// </summary> /// <param name="path">The full path of the item to add.</param> /// <param name="op">The <paramref name="VSADDITEMOPERATION"/> to use when adding the item.</param> /// <returns>A ProjectItem object. </returns> protected virtual ProjectItem AddItem(string path, VSADDITEMOPERATION op) { CheckProjectIsValid(); return(ThreadHelper.JoinableTaskFactory.Run(async delegate { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); ProjectNode proj = this.Project.Project; ProjectItem itemAdded = null; using (AutomationScope scope = new AutomationScope(this.Project.Project.Site)) { VSADDRESULT[] result = new VSADDRESULT[1]; ErrorHandler.ThrowOnFailure(proj.AddItem(this.NodeWithItems.ID, op, path, 0, new string[1] { path }, IntPtr.Zero, result)); string fileName = System.IO.Path.GetFileName(path); string fileDirectory = proj.GetBaseDirectoryForAddingFiles(this.NodeWithItems); string filePathInProject = System.IO.Path.Combine(fileDirectory, fileName); itemAdded = this.EvaluateAddResult(result[0], filePathInProject); } return itemAdded; })); }
/// <summary> /// Opens the file item in the specified view. /// </summary> /// <param name="ViewKind">Specifies the view kind in which to open the item (file)</param> /// <returns>Window object</returns> public override EnvDTE.Window Open(string viewKind) { return(UIThread.DoOnUIThread(delegate() { if (this.Node == null || this.Node.ProjectMgr == null || this.Node.ProjectMgr.IsClosed || this.Node.ProjectMgr.Site == null) { throw new InvalidOperationException(); } IVsWindowFrame windowFrame = null; IntPtr docData = IntPtr.Zero; using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { try { // Validate input params Guid logicalViewGuid = VSConstants.LOGVIEWID_Primary; try { if (!(String.IsNullOrEmpty(viewKind))) { logicalViewGuid = new Guid(viewKind); } } catch (FormatException) { // Not a valid guid throw new ArgumentException(SR.GetString(SR.ParameterMustBeAValidGuid, CultureInfo.CurrentUICulture), "viewKind"); } uint itemid; IVsHierarchy ivsHierarchy; uint docCookie; IVsRunningDocumentTable rdt = this.Node.ProjectMgr.Site.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; Debug.Assert(rdt != null, " Could not get running document table from the services exposed by this project"); if (rdt == null) { throw new InvalidOperationException(); } ErrorHandler.ThrowOnFailure(rdt.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_NoLock, this.Node.Url, out ivsHierarchy, out itemid, out docData, out docCookie)); // Open the file using the IVsProject3 interface ErrorHandler.ThrowOnFailure(this.Node.ProjectMgr.OpenItem(this.Node.ID, ref logicalViewGuid, docData, out windowFrame)); } finally { if (docData != IntPtr.Zero) { Marshal.Release(docData); } } } // Get the automation object and return it return ((windowFrame != null) ? VsShellUtilities.GetWindowObject(windowFrame) : null); })); }
/// <summary> /// Creates a new project item from an existing item template file and adds it to the project. /// </summary> /// <param name="fileName">The full path and file name of the template project file.</param> /// <param name="name">The file name to use for the new project item.</param> /// <returns>A ProjectItem object. </returns> public override EnvDTE.ProjectItem AddFromTemplate(string fileName, string name) { if (this.Project == null || this.Project.Project == null || this.Project.Project.Site == null || this.Project.Project.IsClosed) { throw new InvalidOperationException(); } return(UIThread.DoOnUIThread(delegate() { ProjectNode proj = this.Project.Project; EnvDTE.ProjectItem itemAdded = null; using (AutomationScope scope = new AutomationScope(this.Project.Project.Site)) { string fixedFileName = fileName; if (!File.Exists(fileName)) { string tempFileName = GetTemplateNoZip(fileName); if (File.Exists(tempFileName)) { fixedFileName = tempFileName; } } // Determine the operation based on the extension of the filename. // We should run the wizard only if the extension is vstemplate // otherwise it's a clone operation VSADDITEMOPERATION op; if (Utilities.IsTemplateFile(fixedFileName)) { op = VSADDITEMOPERATION.VSADDITEMOP_RUNWIZARD; } else { op = VSADDITEMOPERATION.VSADDITEMOP_CLONEFILE; } VSADDRESULT[] result = new VSADDRESULT[1]; // It is not a very good idea to throw since the AddItem might return Cancel or Abort. // The problem is that up in the call stack the wizard code does not check whether it has received a ProjectItem or not and will crash. // The other problem is that we cannot get add wizard dialog back if a cancel or abort was returned because we throw and that code will never be executed. Typical catch 22. ErrorHandler.ThrowOnFailure(proj.AddItem(this.NodeWithItems.ID, op, name, 0, new string[1] { fixedFileName }, IntPtr.Zero, result)); string fileDirectory = proj.GetBaseDirectoryForAddingFiles(this.NodeWithItems); string templateFilePath = System.IO.Path.Combine(fileDirectory, name); itemAdded = this.EvaluateAddResult(result[0], templateFilePath); } return itemAdded; })); }
/// <summary> /// Removes the project from the current solution. /// </summary> public virtual void Delete() { CheckProjectIsValid(); UIThread.DoOnUIThread(delegate() { using (AutomationScope scope = new AutomationScope(this.project.Site)) { this.project.Remove(false); } }); }
/// <summary> /// Removes the item from its project and its storage. /// </summary> public virtual void Delete() { CheckProjectIsValid(); UIThread.DoOnUIThread(delegate() { using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { this.node.Remove(true); } }); }
/// <summary> /// Removes the project from the current solution. /// </summary> public virtual void Delete() { if (this.project == null || this.project.Site == null || this.project.IsClosed) { throw new InvalidOperationException(); } using (AutomationScope scope = new AutomationScope(this.project.Site)) { this.project.Remove(false); } }
/// <summary> /// Removes the item from its project and its storage. /// </summary> public virtual void Delete() { if (this.node == null || this.node.ProjectMgr == null || this.node.ProjectMgr.IsClosed || this.node.ProjectMgr.Site == null) { throw new InvalidOperationException(); } using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { this.node.Remove(true); } }
/// <summary> /// Removes the project item from hierarchy. /// </summary> public virtual void Remove() { CheckProjectIsValid(); ThreadHelper.JoinableTaskFactory.Run(async delegate { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { this.node.Remove(false); } }); }
/// <summary> /// Removes the project item from hierarchy. /// </summary> public virtual void Remove() { if (this.node == null || this.node.ProjectMgr == null || this.node.ProjectMgr.IsClosed || this.node.ProjectMgr.Site == null) { throw new InvalidOperationException(); } UIThread.DoOnUIThread(delegate() { using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { this.node.Remove(false); } }); }
/// <summary> /// Removes the project from the current solution. /// </summary> public virtual void Delete() { if (project == null || project.Site == null || project.IsClosed) { throw new InvalidOperationException(); } UIThread.DoOnUIThread(delegate { using (var scope = new AutomationScope(project.Site)) { project.Remove(false); } }); }
/// <summary> /// Expands the view of Solution Explorer to show project items. /// </summary> public virtual void ExpandView() { if (this.node == null || this.node.ProjectMgr == null || this.node.ProjectMgr.IsClosed || this.node.ProjectMgr.Site == null) { throw new InvalidOperationException(); } using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { IVsUIHierarchyWindow uiHierarchy = UIHierarchyUtilities.GetUIHierarchyWindow(this.node.ProjectMgr.Site, HierarchyNode.SolutionExplorer); if (uiHierarchy == null) { throw new InvalidOperationException(); } ErrorHandler.ThrowOnFailure(uiHierarchy.ExpandItem(this.node.ProjectMgr, this.node.ID, EXPANDFLAGS.EXPF_ExpandFolder)); } }
/// <summary> /// Expands the view of Solution Explorer to show project items. /// </summary> public virtual void ExpandView() { CheckProjectIsValid(); UIThread.DoOnUIThread(delegate() { using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { IVsUIHierarchyWindow uiHierarchy = UIHierarchyUtilities.GetUIHierarchyWindow(this.node.ProjectMgr.Site, HierarchyNode.SolutionExplorer); if (uiHierarchy == null) { throw new InvalidOperationException(); } ErrorHandler.ThrowOnFailure(uiHierarchy.ExpandItem(this.node.ProjectMgr, this.node.ID, EXPANDFLAGS.EXPF_ExpandFolder)); } }); }
/// <summary> /// Adds a folder to the collection of ProjectItems with the given name. /// /// The kind must be null, empty string, or the string value of vsProjectItemKindPhysicalFolder. /// Virtual folders are not supported by this implementation. /// </summary> /// <param name="name">The name of the new folder to add</param> /// <param name="kind">A string representing a Guid of the folder kind.</param> /// <returns>A ProjectItem representing the newly added folder.</returns> public override ProjectItem AddFolder(string name, string kind) { if (this.Project == null || this.Project.Project == null || this.Project.Project.Site == null || this.Project.Project.IsClosed) { throw new InvalidOperationException(); } return(UIThread.DoOnUIThread(delegate() { //Verify name is not null or empty Utilities.ValidateFileName(this.Project.Project.Site, name); //Verify that kind is null, empty, or a physical folder if (!(string.IsNullOrEmpty(kind) || kind.Equals(EnvDTE.Constants.vsProjectItemKindPhysicalFolder))) { throw new ArgumentException("Parameter specification for AddFolder was not meet", "kind"); } for (HierarchyNode child = this.NodeWithItems.FirstChild; child != null; child = child.NextSibling) { if (child.Caption.Equals(name, StringComparison.OrdinalIgnoreCase)) { throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "Folder already exists with the name '{0}'", name)); } } ProjectNode proj = this.Project.Project; HierarchyNode newFolder = null; using (AutomationScope scope = new AutomationScope(this.Project.Project.Site)) { //In the case that we are adding a folder to a folder, we need to build up //the path to the project node. name = Path.Combine(this.NodeWithItems.VirtualNodeName, name); newFolder = proj.CreateFolderNodes(name); } return newFolder.GetAutomationObject() as ProjectItem; })); }
/// <summary> /// Creates a new project item from an existing item template file and adds it to the project. /// </summary> /// <param name="fileName">The full path and file name of the template project file.</param> /// <param name="name">The file name to use for the new project item.</param> /// <returns>A ProjectItem object. </returns> public override EnvDTE.ProjectItem AddFromTemplate(string fileName, string name) { if(this.Project == null || this.Project.Project == null || this.Project.Project.Site == null || this.Project.Project.IsClosed) { throw new InvalidOperationException(); } ProjectNode proj = this.Project.Project; EnvDTE.ProjectItem itemAdded = null; using(AutomationScope scope = new AutomationScope(this.Project.Project.Site)) { // Determine the operation based on the extension of the filename. // We should run the wizard only if the extension is vstemplate // otherwise it's a clone operation VSADDITEMOPERATION op; if(Utilities.IsTemplateFile(fileName)) { op = VSADDITEMOPERATION.VSADDITEMOP_RUNWIZARD; } else { op = VSADDITEMOPERATION.VSADDITEMOP_CLONEFILE; } VSADDRESULT[] result = new VSADDRESULT[1]; // It is not a very good idea to throw since the AddItem might return Cancel or Abort. // The problem is that up in the call stack the wizard code does not check whether it has received a ProjectItem or not and will crash. // The other problem is that we cannot get add wizard dialog back if a cancel or abort was returned because we throw and that code will never be executed. Typical catch 22. ErrorHandler.ThrowOnFailure(proj.AddItem(this.NodeWithItems.ID, op, name, 0, new string[1] { fileName }, IntPtr.Zero, result)); string fileDirectory = proj.GetBaseDirectoryForAddingFiles(this.NodeWithItems); string templateFilePath = System.IO.Path.Combine(fileDirectory, name); itemAdded = this.EvaluateAddResult(result[0], templateFilePath); } return itemAdded; }
/// <summary> /// Sets the value of the property at the specified index. /// </summary> /// <param name="index1">The index of the item to set.</param> /// <param name="index2">Reserved for future use.</param> /// <param name="index3">Reserved for future use.</param> /// <param name="index4">Reserved for future use.</param> /// <param name="value">The value to set.</param> public void set_IndexedValue(object index1, object index2, object index3, object index4, object value) { ParameterInfo[] par = pi.GetIndexParameters(); int len = Math.Min(par.Length, 4); if (len == 0) { this.Value = value; } else { object[] index = new object[len]; Array.Copy(new object[4] { index1, index2, index3, index4 }, index, len); using (AutomationScope scope = new AutomationScope(this.parent.Target.Node.ProjectMgr.Site)) { this.pi.SetValue(this.parent.Target, value, index); } } }
/// <summary> /// Creates a new project item from an existing item template file and adds it to the project. /// </summary> /// <param name="fileName">The full path and file name of the template project file.</param> /// <param name="name">The file name to use for the new project item.</param> /// <returns>A ProjectItem object. </returns> public override ProjectItem AddFromTemplate(string fileName, string name) { CheckProjectIsValid(); ProjectNode proj = Project.Project; ProjectItem itemAdded = null; using (var scope = new AutomationScope(Project.Project.Site)) { // Determine the operation based on the extension of the filename. // We should run the wizard only if the extension is vstemplate // otherwise it's a clone operation VSADDITEMOPERATION op; if (Utilities.IsTemplateFile(fileName)) { op = VSADDITEMOPERATION.VSADDITEMOP_RUNWIZARD; } else { op = VSADDITEMOPERATION.VSADDITEMOP_CLONEFILE; } var result = new VSADDRESULT[1]; // It is not a very good idea to throw since the AddItem might return Cancel or Abort. // The problem is that up in the call stack the wizard code does not check whether it has received a ProjectItem or not and will crash. // The other problem is that we cannot get add wizard dialog back if a cancel or abort was returned because we throw and that code will never be executed. Typical catch 22. ErrorHandler.ThrowOnFailure(proj.AddItem(NodeWithItems.ID, op, name, 0, new string[1] { fileName }, IntPtr.Zero, result)); string fileDirectory = proj.GetBaseDirectoryForAddingFiles(NodeWithItems); string templateFilePath = Path.Combine(fileDirectory, name); itemAdded = EvaluateAddResult(result[0], templateFilePath); } return(itemAdded); }
/// <summary> /// Gets a value indicating whether the project item is open in a particular view type. /// </summary> /// <param name="viewKind">A Constants.vsViewKind* indicating the type of view to check./param> /// <returns>A Boolean value indicating true if the project is open in the given view type; false if not. </returns> public override bool get_IsOpen(string viewKind) { return(UIThread.DoOnUIThread(delegate() { if (this.Node == null || this.Node.ProjectMgr == null || this.Node.ProjectMgr.IsClosed || this.Node.ProjectMgr.Site == null) { throw new InvalidOperationException(); } // Validate input params Guid logicalViewGuid = VSConstants.LOGVIEWID_Primary; try { if (!(String.IsNullOrEmpty(viewKind))) { logicalViewGuid = new Guid(viewKind); } } catch (FormatException) { // Not a valid guid throw new ArgumentException(SR.GetString(SR.ParameterMustBeAValidGuid, CultureInfo.CurrentUICulture), "viewKind"); } bool isOpen = false; using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { IVsUIHierarchy hier; uint itemid; IVsWindowFrame windowFrame; isOpen = VsShellUtilities.IsDocumentOpen(this.Node.ProjectMgr.Site, this.Node.Url, logicalViewGuid, out hier, out itemid, out windowFrame); } return isOpen; })); }
/// <summary> /// Gets a value indicating whether the project item is open in a particular view type. /// </summary> /// <param name="viewKind">A Constants.vsViewKind* indicating the type of view to check./param> /// <returns>A Boolean value indicating true if the project is open in the given view type; false if not. </returns> public override bool get_IsOpen(string viewKind) { bool isOpen = false; ThreadHelper.JoinableTaskFactory.Run(async delegate { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); CheckProjectIsValid(); // Validate input params Guid logicalViewGuid = VSConstants.LOGVIEWID_Primary; try { if (!(String.IsNullOrEmpty(viewKind))) { logicalViewGuid = new Guid(viewKind); } } catch (FormatException) { // Not a valid guid throw new ArgumentException(SR.GetString(SR.ParameterMustBeAValidGuid, CultureInfo.CurrentUICulture), "viewKind"); } using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { IVsUIHierarchy hier; uint itemid; IVsWindowFrame windowFrame; isOpen = VsShellUtilities.IsDocumentOpen(this.Node.ProjectMgr.Site, this.Node.Url, logicalViewGuid, out hier, out itemid, out windowFrame); } }); return(isOpen); }
/// <summary> /// Adds an item to the project. /// </summary> /// <param name="path">The full path of the item to add.</param> /// <param name="op"> /// The <paramref name="VSADDITEMOPERATION" /> to use when adding the item. /// </param> /// <returns>A ProjectItem object. </returns> protected virtual ProjectItem AddItem(string path, VSADDITEMOPERATION op) { CheckProjectIsValid(); ProjectNode proj = Project.Project; ProjectItem itemAdded = null; using (var scope = new AutomationScope(Project.Project.Site)) { var result = new VSADDRESULT[1]; ErrorHandler.ThrowOnFailure(proj.AddItem(NodeWithItems.ID, op, path, 0, new string[1] { path }, IntPtr.Zero, result)); string fileName = Path.GetFileName(path); string fileDirectory = proj.GetBaseDirectoryForAddingFiles(NodeWithItems); string filePathInProject = Path.Combine(fileDirectory, fileName); itemAdded = EvaluateAddResult(result[0], filePathInProject); } return(itemAdded); }
/// <summary> /// Sets the value of the property at the specified index. /// </summary> /// <param name="index1">The index of the item to set.</param> /// <param name="index2">Reserved for future use.</param> /// <param name="index3">Reserved for future use.</param> /// <param name="index4">Reserved for future use.</param> /// <param name="value">The value to set.</param> public void set_IndexedValue(object index1, object index2, object index3, object index4, object value) { ParameterInfo[] par = pi.GetIndexParameters(); int len = Math.Min(par.Length, 4); if(len == 0) { this.Value = value; } else { object[] index = new object[len]; Array.Copy(new object[4] { index1, index2, index3, index4 }, index, len); using(AutomationScope scope = new AutomationScope(this.parent.Target.Node.ProjectMgr.Site)) { this.pi.SetValue(this.parent.Target, value, index); } } }
/// <summary> /// Saves or Save Asthe project. /// </summary> /// <param name="isCalledFromSaveAs">Flag determining which Save method called , the SaveAs or the Save.</param> /// <param name="fileName">The name of the project file.</param> private void DoSave(bool isCalledFromSaveAs, string fileName) { if (fileName == null) { throw new ArgumentNullException("fileName"); } if (project == null || project.Site == null || project.IsClosed) { throw new InvalidOperationException(); } UIThread.DoOnUIThread(delegate { using (var scope = new AutomationScope(project.Site)) { // If an empty file name is passed in for Save then make the file name the project name. if (!isCalledFromSaveAs && string.IsNullOrEmpty(fileName)) { // Use the solution service to save the project file. Note that we have to use the service // so that all the shell's elements are aware that we are inside a save operation and // all the file change listenters registered by the shell are suspended. // Get the cookie of the project file from the RTD. var rdt = project.Site.GetService(typeof (SVsRunningDocumentTable)) as IVsRunningDocumentTable; if (null == rdt) { throw new InvalidOperationException(); } IVsHierarchy hier; uint itemid; IntPtr unkData; uint cookie; ErrorHandler.ThrowOnFailure(rdt.FindAndLockDocument((uint) _VSRDTFLAGS.RDT_NoLock, project.Url, out hier, out itemid, out unkData, out cookie)); if (IntPtr.Zero != unkData) { Marshal.Release(unkData); } // Verify that we have a cookie. if (0 == cookie) { // This should never happen because if the project is open, then it must be in the RDT. throw new InvalidOperationException(); } // Get the IVsHierarchy for the project. IVsHierarchy prjHierarchy = project.InteropSafeIVsHierarchy; // Now get the solution. var solution = project.Site.GetService(typeof (SVsSolution)) as IVsSolution; // Verify that we have both solution and hierarchy. if ((null == prjHierarchy) || (null == solution)) { throw new InvalidOperationException(); } ErrorHandler.ThrowOnFailure(solution.SaveSolutionElement((uint) __VSSLNSAVEOPTIONS.SLNSAVEOPT_SaveIfDirty, prjHierarchy, cookie)); } else { // We need to make some checks before we can call the save method on the project node. // This is mainly because it is now us and not the caller like in case of SaveAs or Save that should validate the file name. // The IPersistFileFormat.Save method only does a validation that is necesseray to be performed. Example: in case of Save As the // file name itself is not validated only the whole path. (thus a file name like file\file is accepted, since as a path is valid) // 1. The file name has to be valid. string fullPath = fileName; try { if (!Path.IsPathRooted(fileName)) { fullPath = Path.Combine(project.ProjectFolder, fileName); } } // We want to be consistent in the error message and exception we throw. fileName could be for example #�&%"�&"% and that would trigger an ArgumentException on Path.IsRooted. catch (ArgumentException) { throw new InvalidOperationException(SR.GetString(SR.ErrorInvalidFileName, CultureInfo.CurrentUICulture)); } // It might be redundant but we validate the file and the full path of the file being valid. The SaveAs would also validate the path. // If we decide that this is performance critical then this should be refactored. Utilities.ValidateFileName(project.Site, fullPath); if (!isCalledFromSaveAs) { // 2. The file name has to be the same if (!NativeMethods.IsSamePath(fullPath, project.Url)) { throw new InvalidOperationException(); } ErrorHandler.ThrowOnFailure(project.Save(fullPath, 1, 0)); } else { ErrorHandler.ThrowOnFailure(project.Save(fullPath, 0, 0)); } } } }); }
/// <summary> /// Saves or Save As the file /// </summary> /// <param name="isCalledFromSaveAs">Flag determining which Save method called , the SaveAs or the Save.</param> /// <param name="fileName">The name of the project file.</param> private void DoSave(bool isCalledFromSaveAs, string fileName) { if (fileName == null) { throw new ArgumentNullException("fileName"); } if (this.Node == null || this.Node.ProjectMgr == null || this.Node.ProjectMgr.IsClosed || this.Node.ProjectMgr.Site == null) { throw new InvalidOperationException(); } using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { IntPtr docData = IntPtr.Zero; try { IVsRunningDocumentTable rdt = this.Node.ProjectMgr.Site.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; Debug.Assert(rdt != null, " Could not get running document table from the services exposed by this project"); if (rdt == null) { throw new InvalidOperationException(); } // First we see if someone else has opened the requested view of the file. uint itemid; IVsHierarchy ivsHierarchy; uint docCookie; int canceled; string url = this.Node.Url; ErrorHandler.ThrowOnFailure(rdt.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_NoLock, url, out ivsHierarchy, out itemid, out docData, out docCookie)); // If an empty file name is passed in for Save then make the file name the project name. if (!isCalledFromSaveAs && fileName.Length == 0) { ErrorHandler.ThrowOnFailure(this.Node.ProjectMgr.SaveItem(VSSAVEFLAGS.VSSAVE_SilentSave, url, this.Node.ID, docData, out canceled)); } else { Utilities.ValidateFileName(this.Node.ProjectMgr.Site, fileName); // Compute the fullpath from the directory of the existing Url. string fullPath = fileName; if (!Path.IsPathRooted(fileName)) { string directory = Path.GetDirectoryName(url); fullPath = Path.Combine(directory, fileName); } if (!isCalledFromSaveAs) { if (!NativeMethods.IsSamePath(this.Node.Url, fullPath)) { throw new InvalidOperationException(); } ErrorHandler.ThrowOnFailure(this.Node.ProjectMgr.SaveItem(VSSAVEFLAGS.VSSAVE_SilentSave, fullPath, this.Node.ID, docData, out canceled)); } else { ErrorHandler.ThrowOnFailure(this.Node.ProjectMgr.SaveItem(VSSAVEFLAGS.VSSAVE_SilentSave, fullPath, this.Node.ID, docData, out canceled)); } } if (canceled == 1) { throw new InvalidOperationException(); } } catch (COMException e) { throw new InvalidOperationException(e.Message); } finally { if (docData != IntPtr.Zero) { Marshal.Release(docData); } } } }
/// <summary> /// Adds an item to the project. /// </summary> /// <param name="path">The full path of the item to add.</param> /// <param name="op">The <paramref name="VSADDITEMOPERATION"/> to use when adding the item.</param> /// <returns>A ProjectItem object. </returns> protected virtual EnvDTE.ProjectItem AddItem(string path, VSADDITEMOPERATION op) { if(this.Project == null || this.Project.Project == null || this.Project.Project.Site == null || this.Project.Project.IsClosed) { throw new InvalidOperationException(); } return UIThread.DoOnUIThread(delegate() { ProjectNode proj = this.Project.Project; EnvDTE.ProjectItem itemAdded = null; using (AutomationScope scope = new AutomationScope(this.Project.Project.Site)) { VSADDRESULT[] result = new VSADDRESULT[1]; ErrorHandler.ThrowOnFailure(proj.AddItem(this.NodeWithItems.ID, op, path, 0, new string[1] { path }, IntPtr.Zero, result)); string fileName = System.IO.Path.GetFileName(path); string fileDirectory = proj.GetBaseDirectoryForAddingFiles(this.NodeWithItems); string filePathInProject = System.IO.Path.Combine(fileDirectory, fileName); itemAdded = this.EvaluateAddResult(result[0], filePathInProject); } return itemAdded; }); }
/// <summary> /// Removes the project from the current solution. /// </summary> public virtual void Delete() { if(this.project == null || this.project.Site == null || this.project.IsClosed) { throw new InvalidOperationException(); } using(AutomationScope scope = new AutomationScope(this.project.Site)) { this.project.Remove(false); } }
/// <summary> /// Adds an item to the project. /// </summary> /// <param name="path">The full path of the item to add.</param> /// <param name="op"> /// The <paramref name="VSADDITEMOPERATION" /> to use when adding the item. /// </param> /// <returns>A ProjectItem object. </returns> protected virtual ProjectItem AddItem(string path, VSADDITEMOPERATION op) { CheckProjectIsValid(); ProjectNode proj = Project.Project; ProjectItem itemAdded = null; using (var scope = new AutomationScope(Project.Project.Site)) { var result = new VSADDRESULT[1]; ErrorHandler.ThrowOnFailure(proj.AddItem(NodeWithItems.ID, op, path, 0, new string[1] {path}, IntPtr.Zero, result)); string fileName = Path.GetFileName(path); string fileDirectory = proj.GetBaseDirectoryForAddingFiles(NodeWithItems); string filePathInProject = Path.Combine(fileDirectory, fileName); itemAdded = EvaluateAddResult(result[0], filePathInProject); } return itemAdded; }
/// <summary> /// Saves or Save Asthe project. /// </summary> /// <param name="isCalledFromSaveAs">Flag determining which Save method called , the SaveAs or the Save.</param> /// <param name="fileName">The name of the project file.</param> private void DoSave(bool isCalledFromSaveAs, string fileName) { if (fileName == null) { throw new ArgumentNullException("fileName"); } if (this.project == null || this.project.Site == null || this.project.IsClosed) { throw new InvalidOperationException(); } using (AutomationScope scope = new AutomationScope(this.project.Site)) { // If an empty file name is passed in for Save then make the file name the project name. if (!isCalledFromSaveAs && string.IsNullOrEmpty(fileName)) { // Use the solution service to save the project file. Note that we have to use the service // so that all the shell's elements are aware that we are inside a save operation and // all the file change listenters registered by the shell are suspended. // Get the cookie of the project file from the RTD. IVsRunningDocumentTable rdt = this.project.Site.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; if (null == rdt) { throw new InvalidOperationException(); } IVsHierarchy hier; uint itemid; IntPtr unkData; uint cookie; ErrorHandler.ThrowOnFailure(rdt.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_NoLock, this.project.Url, out hier, out itemid, out unkData, out cookie)); if (IntPtr.Zero != unkData) { Marshal.Release(unkData); } // Verify that we have a cookie. if (0 == cookie) { // This should never happen because if the project is open, then it must be in the RDT. throw new InvalidOperationException(); } // Get the IVsHierarchy for the project. IVsHierarchy prjHierarchy = HierarchyNode.GetOuterHierarchy(this.project); // Now get the soulution. IVsSolution solution = this.project.Site.GetService(typeof(SVsSolution)) as IVsSolution; // Verify that we have both solution and hierarchy. if ((null == prjHierarchy) || (null == solution)) { throw new InvalidOperationException(); } ErrorHandler.ThrowOnFailure(solution.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_SaveIfDirty, prjHierarchy, cookie)); } else { // We need to make some checks before we can call the save method on the project node. // This is mainly because it is now us and not the caller like in case of SaveAs or Save that should validate the file name. // The IPersistFileFormat.Save method only does a validation that is necesseray to be performed. Example: in case of Save As the // file name itself is not validated only the whole path. (thus a file name like file\file is accepted, since as a path is valid) // 1. The file name has to be valid. string fullPath = fileName; try { if (!Path.IsPathRooted(fileName)) { fullPath = Path.Combine(this.project.ProjectFolder, fileName); } } // We want to be consistent in the error message and exception we throw. fileName could be for example #¤&%"¤&"% and that would trigger an ArgumentException on Path.IsRooted. catch (ArgumentException) { throw new InvalidOperationException(SR.GetString(SR.ErrorInvalidFileName, CultureInfo.CurrentUICulture)); } // It might be redundant but we validate the file and the full path of the file being valid. The SaveAs would also validate the path. // If we decide that this is performance critical then this should be refactored. Utilities.ValidateFileName(this.project.Site, fullPath); if (!isCalledFromSaveAs) { // 2. The file name has to be the same if (!NativeMethods.IsSamePath(fullPath, this.project.Url)) { throw new InvalidOperationException(); } ErrorHandler.ThrowOnFailure(this.project.Save(fullPath, 1, 0)); } else { ErrorHandler.ThrowOnFailure(this.project.Save(fullPath, 0, 0)); } } } }