/// <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(); } UIThread.DoOnUIThread(delegate() { IVsExtensibility3 extensibility = this.Node.ProjectMgr.Site.GetService(typeof(IVsExtensibility)) as IVsExtensibility3; if (extensibility == null) { throw new InvalidOperationException(); } extensibility.EnterAutomationFunction(); try { IVsUIHierarchyWindow uiHierarchy = UIHierarchyUtilities.GetUIHierarchyWindow(this.node.ProjectMgr.Site, HierarchyNode.SolutionExplorer); if (uiHierarchy == null) { throw new InvalidOperationException(); } uiHierarchy.ExpandItem(node.ProjectMgr.InteropSafeIVsUIHierarchy, this.node.ID, EXPANDFLAGS.EXPF_ExpandFolder); } finally { extensibility.ExitAutomationFunction(); } }); }
/// <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(); } UIThread.DoOnUIThread(delegate() { IVsExtensibility3 extensibility = this.project.Site.GetService(typeof(IVsExtensibility)) as IVsExtensibility3; if (extensibility == null) { throw new InvalidOperationException(); } extensibility.EnterAutomationFunction(); try { this.project.Remove(false); } finally { extensibility.ExitAutomationFunction(); } }); }
/// <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); IVsExtensibility3 extensibility = this.parent.Target.Node.ProjectMgr.Site.GetService(typeof(IVsExtensibility)) as IVsExtensibility3; if (extensibility == null) { throw new InvalidOperationException(); } extensibility.EnterAutomationFunction(); try { this.pi.SetValue(this.parent.Target, value, index); } finally { extensibility.ExitAutomationFunction(); } } }
/// <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(); } UIThread.DoOnUIThread(delegate() { IVsExtensibility3 extensibility = this.Node.ProjectMgr.Site.GetService(typeof(IVsExtensibility)) as IVsExtensibility3; if (extensibility == null) { throw new InvalidOperationException(); } extensibility.EnterAutomationFunction(); try { this.node.Remove(removeFromStorage: true, promptSave: false); } finally { extensibility.ExitAutomationFunction(); } }); }
/// <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(); } IVsExtensibility3 extensibility = this.Node.ProjectMgr.Site.GetService(typeof(IVsExtensibility)) as IVsExtensibility3; if (extensibility == null) { throw new InvalidOperationException(); } extensibility.EnterAutomationFunction(); try { this.node.Remove(true); } finally { extensibility.ExitAutomationFunction(); } }
private void Fire(HierarchyNode node, Action <IVsExtensibility3, ProjectItem> fire) { // When we are in suspended mode. Do not fire anything if (this._suspended) { return; } // Project has to be opened if (!this._project.IsProjectOpened) { return; } // We don't want to fire events for references here. OAReferences should do the job if (node is ReferenceNode) { return; } IVsExtensibility3 vsExtensibility = this._project.GetService(typeof(IVsExtensibility)) as IVsExtensibility3; if (vsExtensibility != null) { object obj = node.GetAutomationObject(); ProjectItem item = obj as ProjectItem; if (item != null) { fire(vsExtensibility, item); } } }
/// <summary> /// Defines the beginning of the scope of an automation function. This constuctor /// calls EnterAutomationFunction to signal the Shell that the current function is /// changing the status of the automation objects. /// </summary> public AutomationScope(IServiceProvider provider) { Utilities.ArgumentNotNull("provider", provider); extensibility = provider.GetService(typeof(IVsExtensibility)) as IVsExtensibility3; Assumes.Present(extensibility); ErrorHandler.ThrowOnFailure(extensibility.EnterAutomationFunction()); inAutomation = true; }
/// <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; IVsExtensibility3 extensibility = this.Project.Project.Site.GetService(typeof(IVsExtensibility)) as IVsExtensibility3; if (extensibility == null) { throw new InvalidOperationException(); } EnvDTE.ProjectItem itemAdded = null; extensibility.EnterAutomationFunction(); try { // 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); } finally { extensibility.ExitAutomationFunction(); } return(itemAdded); }
/// <summary> /// Defines the beginning of the scope of an automation function. This constuctor /// calls EnterAutomationFunction to signal the Shell that the current function is /// changing the status of the automation objects. /// </summary> public AutomationScope(IServiceProvider provider) { Utilities.ArgumentNotNull("provider", provider); extensibility = provider.GetService(typeof(EnvDTE.IVsExtensibility)) as IVsExtensibility3; if (null == extensibility) { throw new InvalidOperationException(); } ErrorHandler.ThrowOnFailure(extensibility.EnterAutomationFunction()); inAutomation = true; }
/// <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) { return(UIThread.DoOnUIThread(delegate() { if (this.Project == null || this.Project.Project == null || this.Project.Project.Site == null || this.Project.Project.IsClosed) { throw new InvalidOperationException(); } //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; IVsExtensibility3 extensibility = this.Project.Project.Site.GetService(typeof(IVsExtensibility)) as IVsExtensibility3; if (extensibility == null) { throw new InvalidOperationException(); } HierarchyNode newFolder = null; extensibility.EnterAutomationFunction(); //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); try { newFolder = proj.CreateFolderNodes(name); } finally { extensibility.ExitAutomationFunction(); } return newFolder.GetAutomationObject() as ProjectItem; })); }
/// <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) { 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"); } IVsExtensibility3 extensibility = this.Node.ProjectMgr.Site.GetService(typeof(IVsExtensibility)) as IVsExtensibility3; if (extensibility == null) { throw new InvalidOperationException(); } bool isOpen = false; extensibility.EnterAutomationFunction(); try { IVsUIHierarchy hier; uint itemid; IVsWindowFrame windowFrame; isOpen = VsShellUtilities.IsDocumentOpen(this.Node.ProjectMgr.Site, this.Node.Url, logicalViewGuid, out hier, out itemid, out windowFrame); } finally { extensibility.ExitAutomationFunction(); } return(isOpen); }
/// <include file='doc\VsShellUtilities.uex' path='docs/doc[@for="Utilities.IsInAutomationFunction"]/*' /> /// <devdoc> /// Is an extensibility object executing an automation function. /// </devdoc> /// <param name="serviceProvider">The service provider.</param> /// <returns>true if the extensibility object is executing an automation function.</returns> public static bool IsInAutomationFunction(IServiceProvider serviceProvider) { Utilities.ArgumentNotNull("serviceProvider", 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); }
/// <devdoc> /// Is an extensibility object executing an automation function. /// </devdoc> /// <param name="serviceProvider">The service provider.</param> /// <returns>true if the extensiblity object is executing an automation function.</returns> public static bool IsInAutomationFunction(IServiceProvider serviceProvider) { if (serviceProvider == null) { throw new ArgumentException("serviceProvider"); } IVsExtensibility3 extensibility = serviceProvider.GetService(typeof(EnvDTE.IVsExtensibility)) as IVsExtensibility3; if (extensibility == null) { return false; } int inAutomation = 0; ErrorHandler.ThrowOnFailure(extensibility.IsInAutomationFunction(out inAutomation)); return inAutomation != 0; }
/// <summary> /// Adds an item to the project. /// </summary> /// <param name="path">The full path of the item to add.</param> /// <param name="op">The VSADDITEMOPERATION to use when adding the item.</param> /// <returns>A ProjectItem object. </returns> public virtual EnvDTE.ProjectItem AddItem(string path, VSADDITEMOPERATION op) { return(UIThread.DoOnUIThread(delegate() { 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; IVsExtensibility3 extensibility = this.Project.Project.Site.GetService(typeof(IVsExtensibility)) as IVsExtensibility3; if (extensibility == null) { throw new InvalidOperationException(); } EnvDTE.ProjectItem itemAdded = null; extensibility.EnterAutomationFunction(); try { 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); } finally { extensibility.ExitAutomationFunction(); } 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(); } IVsExtensibility3 extensibility = this.project.Site.GetService(typeof(IVsExtensibility)) as IVsExtensibility3; if (extensibility == null) { throw new InvalidOperationException(); } extensibility.EnterAutomationFunction(); try { // 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.project.Save(this.project.Url, 0, 0)); } 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)); } // 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)); } } } finally { extensibility.ExitAutomationFunction(); } }
/// <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(); } IVsExtensibility3 extensibility = this.Node.ProjectMgr.Site.GetService(typeof(IVsExtensibility)) as IVsExtensibility3; if (extensibility == null) { throw new InvalidOperationException(); } extensibility.EnterAutomationFunction(); 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; IntPtr projectPtr = IntPtr.Zero; 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 { extensibility.ExitAutomationFunction(); if (docData != IntPtr.Zero) { Marshal.Release(docData); } } }
/// <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) { if (this.Node == null || this.Node.ProjectMgr == null || this.Node.ProjectMgr.IsClosed || this.Node.ProjectMgr.Site == null) { throw new InvalidOperationException(); } // tell extensibility we are entering automation IServiceProvider serviceProvider = this.Node.ProjectMgr.Site; IVsExtensibility3 extensibility = this.Node.ProjectMgr.Site.GetService(typeof(IVsExtensibility)) as IVsExtensibility3; if (extensibility == null) { throw new InvalidOperationException(); } IVsWindowFrame windowFrame = null; IntPtr docData = IntPtr.Zero; extensibility.EnterAutomationFunction(); 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 { // make sure we tell extensibility that we have left automation extensibility.ExitAutomationFunction(); if (docData != IntPtr.Zero) { Marshal.Release(docData); } } // Get the automation object and return it return((windowFrame != null) ? VsShellUtilities.GetWindowObject(windowFrame) : null); }
/// <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) { UIThread.DoOnUIThread(delegate() { if (fileName == null) { throw new ArgumentNullException("fileName"); } if (this.project == null || this.project.Site == null || this.project.IsClosed) { throw new InvalidOperationException(); } IVsExtensibility3 extensibility = this.project.Site.GetService(typeof(IVsExtensibility)) as IVsExtensibility3; if (extensibility == null) { throw new InvalidOperationException(); } extensibility.EnterAutomationFunction(); try { // 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 = IntPtr.Zero; uint cookie; try { ErrorHandler.ThrowOnFailure(rdt.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_NoLock, this.project.Url, out hier, out itemid, out unkData, out cookie)); } finally { 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 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. ArgumentException on Path.IsRooted shoud become InvalidOperationException. 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)); } } } finally { extensibility.ExitAutomationFunction(); } }); }