in Nodejs/Product/Nodejs/SharedProject/ProjectNode.cs [6752:6869]
public virtual int SaveItem(VSSAVEFLAGS saveFlag, string silentSaveAsName, uint itemid, IntPtr docData, out int cancelled)
{
cancelled = 0;
// Validate itemid
if (itemid == VSConstants.VSITEMID_ROOT || itemid == VSConstants.VSITEMID_SELECTION)
{
return VSConstants.E_INVALIDARG;
}
var node = this.NodeFromItemId(itemid);
if (node == null)
{
return VSConstants.E_FAIL;
}
var existingFileMoniker = node.GetMkDocument();
// We can only perform save if the document is open
if (docData == IntPtr.Zero)
{
throw new InvalidOperationException(SR.GetString(SR.CanNotSaveFileNotOpeneInEditor, node.Url));
}
var docNew = string.Empty;
var returnCode = VSConstants.S_OK;
IPersistFileFormat ff = null;
IVsPersistDocData dd = null;
var shell = this.Site.GetService(typeof(SVsUIShell)) as IVsUIShell;
Utilities.CheckNotNull(shell);
try
{
//Save docdata object.
//For the saveas action a dialog is show in order to enter new location of file.
//In case of a save action and the file is readonly a dialog is also shown
//with a couple of options, SaveAs, Overwrite or Cancel.
ff = Marshal.GetObjectForIUnknown(docData) as IPersistFileFormat;
Utilities.CheckNotNull(ff);
if (VSSAVEFLAGS.VSSAVE_SilentSave == saveFlag)
{
ErrorHandler.ThrowOnFailure(shell.SaveDocDataToFile(saveFlag, ff, silentSaveAsName, out docNew, out cancelled));
}
else
{
dd = Marshal.GetObjectForIUnknown(docData) as IVsPersistDocData;
Utilities.CheckNotNull(dd);
ErrorHandler.ThrowOnFailure(dd.SaveDocData(saveFlag, out docNew, out cancelled));
}
// We can be unloaded after the SaveDocData() call if the save caused a designer to add a file and this caused
// the project file to be reloaded (QEQS caused a newer version of the project file to be downloaded). So we check
// here.
if (this.IsClosed)
{
cancelled = 1;
return (int)OleConstants.OLECMDERR_E_CANCELED;
}
else
{
// if a SaveAs occurred we need to update to the fact our item's name has changed.
// this includes the following:
// 1. call RenameDocument on the RunningDocumentTable
// 2. update the full path name for the item in our hierarchy
// 3. a directory-based project may need to transfer the open editor to the
// MiscFiles project if the new file is saved outside of the project directory.
// This is accomplished by calling IVsExternalFilesManager::TransferDocument
// we have three options for a saveas action to be performed
// 1. the flag was set (the save as command was triggered)
// 2. a silent save specifying a new document name
// 3. a save command was triggered but was not possible because the file has a read only attrib. Therefore
// the user has chosen to do a save as in the dialog that showed up
var emptyOrSamePath = string.IsNullOrEmpty(docNew) || CommonUtils.IsSamePath(existingFileMoniker, docNew);
var saveAs = ((saveFlag == VSSAVEFLAGS.VSSAVE_SaveAs)) ||
((saveFlag == VSSAVEFLAGS.VSSAVE_SilentSave) && !emptyOrSamePath) ||
((saveFlag == VSSAVEFLAGS.VSSAVE_Save) && !emptyOrSamePath);
if (saveAs)
{
returnCode = node.AfterSaveItemAs(docData, docNew);
// If it has been cancelled recover the old name.
if ((returnCode == (int)OleConstants.OLECMDERR_E_CANCELED || returnCode == VSConstants.E_ABORT))
{
// Cleanup.
this.DeleteFromStorage(docNew);
if (ff != null)
{
returnCode = shell.SaveDocDataToFile(VSSAVEFLAGS.VSSAVE_SilentSave, ff, existingFileMoniker, out docNew, out cancelled);
}
}
else if (returnCode != VSConstants.S_OK)
{
ErrorHandler.ThrowOnFailure(returnCode);
}
}
}
}
catch (COMException e)
{
Trace.WriteLine("Exception :" + e.Message);
returnCode = e.ErrorCode;
// Try to recover
// changed from MPFProj:
// http://mpfproj10.codeplex.com/WorkItem/View.aspx?WorkItemId=6982
if (ff != null && cancelled == 0)
{
ErrorHandler.ThrowOnFailure(shell.SaveDocDataToFile(VSSAVEFLAGS.VSSAVE_SilentSave, ff, existingFileMoniker, out docNew, out cancelled));
}
}
return returnCode;
}