public virtual int SaveAs()

in vsintegration/src/FSharp.ProjectSystem.Base/Project/ProjectNode.cs [3406:3539]


        public virtual int SaveAs(string newFileName, bool saveCopyAs)
        {
            Debug.Assert(!String.IsNullOrEmpty(newFileName), "Cannot save project file for an empty or null file name");

            newFileName = newFileName.Trim();

            string errorMessage = String.Empty;

            if (newFileName.Length > NativeMethods.MAX_PATH)
            {
                errorMessage = String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.PathTooLong, CultureInfo.CurrentUICulture), newFileName);
            }
            else
            {
                string fileName = String.Empty;

                try
                {
                    fileName = Path.GetFileNameWithoutExtension(newFileName);
                }
                // 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)
                {
                    errorMessage = SR.GetString(SR.ErrorInvalidFileName, CultureInfo.CurrentUICulture);
                }

                if (errorMessage.Length == 0)
                {
                    // If there is no filename or it starts with a leading dot issue an error message and quit.
                    // For some reason the save as dialog box allows to save files like "......ext"
                    if (String.IsNullOrEmpty(fileName) || fileName[0] == '.')
                    {
                        errorMessage = SR.GetString(SR.FileNameCannotContainALeadingPeriod, CultureInfo.CurrentUICulture);
                    }
                    else if (Utilities.ContainsInvalidFileNameChars(newFileName))
                    {
                        errorMessage = SR.GetString(SR.ErrorInvalidFileName, CultureInfo.CurrentUICulture);
                    }
                    else if (!saveCopyAs)
                    {   
                        // verify folder only when we save project file itself, not its copy
                        string url = Path.GetDirectoryName(newFileName);
                        string oldUrl = Path.GetDirectoryName(this.Url);

                        if (!NativeMethods.IsSamePath(oldUrl, url))
                        {
                            errorMessage = String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.SaveOfProjectFileOutsideCurrentDirectory, CultureInfo.CurrentUICulture), this.ProjectFolder);
                        }
                    }
                }
            }
            if (errorMessage.Length > 0)
            {
                // If it is not called from an automation method show a dialog box.
                if (!Utilities.IsInAutomationFunction(this.Site))
                {
                    string title = null;
                    OLEMSGICON icon = OLEMSGICON.OLEMSGICON_CRITICAL;
                    OLEMSGBUTTON buttons = OLEMSGBUTTON.OLEMSGBUTTON_OK;
                    OLEMSGDEFBUTTON defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST;
                    VsShellUtilities.ShowMessageBox(this.Site, title, errorMessage, icon, buttons, defaultButton);
                    return VSConstants.OLE_E_PROMPTSAVECANCELLED;
                }

                throw new InvalidOperationException(errorMessage);
            }

            string oldName = this.filename;

            IVsSolution solution = this.Site.GetService(typeof(SVsSolution)) as IVsSolution;
            Debug.Assert(solution != null, "Could not retrieve the solution form the service provider");
            if (solution == null)
            {
                throw new InvalidOperationException();
            }

            SuspendFileChanges fileChanges = new SuspendFileChanges(this.Site, oldName);
            fileChanges.Suspend();
            try
            {
                if (saveCopyAs)
                {
                    // preserve encoding of BuildProject.
                    // if encoding of StreamWriter differs from encoding used by BuildProject then Save will change encoding in xml processing instruction
                    var targetEncoding = 
                        this.BuildProject.Xml.Encoding
                        ;
                    using (var writer = new StreamWriter(newFileName, false, targetEncoding))
                    {
                        // Save(TextWriter) overload is used to avoid internal modification of the FullName property
                        // all we need for 'saveCopyAs' is store content of this project file to another location without extra changes
                        this.BuildProject.Save(writer);
                    }
                }
                else
                {
                    int canRenameContinue = 0;
                    ErrorHandler.ThrowOnFailure(solution.QueryRenameProject(InteropSafeIVsProject, this.filename, newFileName, 0, out canRenameContinue));

                    if (canRenameContinue == 0)
                    {
                        return VSConstants.OLE_E_PROMPTSAVECANCELLED;
                    }

                    // Save the project file and project file related properties.
                    this.SaveMSBuildProjectFileAs(newFileName);

                    this.SetProjectFileDirty(false);


                    // TODO: If source control is enabled check out the project file.

                    //Redraw.
                    this.OnPropertyChanged(this, (int)__VSHPROPID.VSHPROPID_Caption, 0);

                    ErrorHandler.ThrowOnFailure(solution.OnAfterRenameProject(InteropSafeIVsProject, oldName, this.filename, 0));

                    IVsUIShell shell = this.Site.GetService(typeof(SVsUIShell)) as IVsUIShell;
                    Debug.Assert(shell != null, "Could not get the ui shell from the project");
                    if (shell == null)
                    {
                        throw new InvalidOperationException();
                    }
                    shell.RefreshPropertyBrowser(0);
                }

            }
            finally
            {
                fileChanges.Resume();
            }

            return VSConstants.S_OK;
        }