Beware of AutoSave and DocumentBeforeSave
One of the cool things about Word is that it auto-saves your work so that if the machine dies or the app crashes you can get most of it back again. One of the other cool things about Word is that you can customise the built-in dialogs -- such as the Save As dialog -- to save yourself some development time and keeping the UI familiar to users.
Unfortunately these things don't work too well together right now. I have code similar to this in dotWord:
/// Called when the document is opened.
protected
void
ThisDocument_Open()
{
ThisApplication.DocumentBeforeSave += new Word.ApplicationEvents4_DocumentBeforeSaveEventHandler(BeforeSaveHandler);
}
private
void
BeforeSaveHandler(Word.Document Doc, ref bool SaveAsUI, ref bool Cancel)
{
// Get the default Save-As dialog to show to the user
Word.Dialog fileSaveAsDlg;
fileSaveAsDlg = thisApplication.Dialogs[Word.WdWordDialog.wdDialogFileSaveAs];
// Show the dialog. This will actually save the document if the
// user clicks the "Save" button.
object missing = Type.Missing;
fileSaveAsDlg.Show(ref missing);
// Oooh, fun! It's like a choose-your-own-adventure
if
(MessageBox.Show("Do you want to crash [Yes] or show a silly dialog [No]?",
"Save bug"
, MessageBoxButtons.YesNo) == DialogResult.Yes)
Cancel = false;
else
Cancel = true;
}
In the real code I actually do some work to compute a decent file-name based on the blog title and today's date, but I omitted that from the sample since it uses reflection code that just gets in the way of the example.
Anyway, as the final MessgeBox suggests, you can either set the Cancel parameter to true (cancel the save operation) or false (continue the save operation). Neither is particularly cool in the case of an AutoSave, as indicated by the choice in the message box text. There doesn't seem to be a way to detect AutoSaves either. The good news is that AutoRecover can fully recover the file (since it really is saved before Word crashes), but still, Word shouldn't crash (and the silly dialog should go away, too!)
IMHO the AutoSave should not even trigger the DocumentBeforeSave event because it's not a real "save" -- the user hasn't committed to saving the file yet, so they may not want to give it a name or update a database or call a web service or perform other operations that you would typically do in this event handler. I think that either there should be a separate event for the AutoSave (or at a minimum a flag / parameter that you can query to figure out you're in an AutoSave) or else it should not trigger any events at all.
What do you think? Either way, this little gotcha is something to look out for that you're not likely to come across in normal testing of your application. The default AutoSave timeout for Word is 10 minutes, which probably means it never gets triggered when you're doing your testing. (It repros in VBA as well, so it's not just a managed code / VSTO thing).
Comments
- Anonymous
February 15, 2004
Is there a way to change the autosave interval programmatically?
Bruce - Anonymous
February 15, 2004
Sure -- Application.SaveInterval or something similar. Check MSDN - Anonymous
February 15, 2004
Make that Application.Options.SaveInterval.
I checked VBA's IntelliSense ;-) - Anonymous
February 20, 2004
I wholeheartedly agree. There is a big difference between an AutoRecover save ("Keep a copy of this in case I decide it is useful but the application crashes") and a real Save ("Commit this to disk, overwriting the previous version")
I can't believe the office team implemented this event without a flag or a good way to distinguish between Save and AutoRecover.
Has anyone found such a flag? - Anonymous
July 29, 2004
The comment has been removed - Anonymous
June 18, 2005
The comment has been removed - Anonymous
November 02, 2005
I just ran into this AutoRecover problem, and I'm still looking for a workaround. There is definitely a difference, in my opinion, between this type of save and an actual user-initiated save, and it is very frustrating that I can't check for it.
I've run into some other problems that I haven't seen mentioned anywhere, related to the fact that these events are application-level events, not restricted to the template in which they are contained. If you have DocumentBeforeSave code attached to a loaded template, it runs irregardless of whether or not the ActiveDocument contains that code. Every time you save ANY document, the code specific to that one template will run.
So I've had to add code to check for attached template name before firing certain events or code to loop through all open documents checking for any documents based on the template in question before firing others.
This may be obvious, but to those of us who have focused all of our development efforts primarily on single documents and are new to class modules in Office, it would have been nice if the documentation had said, "By the way, this code is going to run anytime the user saves anything."
I'm ready to go back to putting my code in the FileSave and FileSaveAs events, etc.
Thanks for posting your frustration. It helps to know that others are facing the same problems and feeling the same irritation at the seeming lack of foresight. - Anonymous
March 03, 2006
We have similar situation, as you've raised. And used flas to determine if user has explicity wanted a save ( either in Save, Save as or Doc close). However when user presses Ctrl+S, it by passes all menu click events and comes to before save event. IN this case, none of the flags are set, and we assume that its autosave and IGNORE the save :-( Any workaround for this? - Anonymous
June 08, 2006
I did what Trumpet, Inc. suggested, and it seemed to work (in Word 2003). That is, encapsulate all of the code in the BeforeSaveHandler with
if(SaveAsUI)
{
...
}
I am getting no problem with AutoRecovery saves, or just performing a normal save.