What worked for me like a glove was to implement the interface IVsRunningDocTableEvents3 overriding the method of OnBeforeSave.
That way I knew exactly when the project was to be saved and carry out the actions I needed.
Ex.:
uint cookie;
var runningDocumentTable = (IVsRunningDocumentTable)GetGlobalService(typeof(SVsRunningDocumentTable));
runningDocumentTable.AdviseRunningDocTableEvents(new RunningDocTableEventsHandler(), out cookie);
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
namespace YourProject
{
    internal class RunningDocTableEventsHandler : IVsRunningDocTableEvents3
    {
        #region Methods
        public int OnAfterFirstDocumentLock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining)
        {
            return VSConstants.S_OK;
        }
        public int OnBeforeLastDocumentUnlock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining)
        {
            return VSConstants.S_OK;
        }
        public int OnAfterSave(uint docCookie)
        {
            return VSConstants.S_OK;
        }
        public int OnAfterAttributeChange(uint docCookie, uint grfAttribs)
        {
            return VSConstants.S_OK;
        }
        public int OnBeforeDocumentWindowShow(uint docCookie, int fFirstShow, IVsWindowFrame pFrame)
        {
            return VSConstants.S_OK;
        }
        public int OnAfterDocumentWindowHide(uint docCookie, IVsWindowFrame pFrame)
        {
            return VSConstants.S_OK;
        }
        public int OnAfterAttributeChangeEx(uint docCookie, uint grfAttribs, IVsHierarchy pHierOld, uint itemidOld, string pszMkDocumentOld, IVsHierarchy pHierNew, uint itemidNew, string pszMkDocumentNew)
        {
            return VSConstants.S_OK;
        }
        public int OnBeforeSave(uint docCookie)
        {
            /////// MY CODE ////////
            return VSConstants.S_OK;
        }
        #endregion Methods
    }
}