Beware of AutoSave and DocumentBeforeSave

Beware of AutoSave and DocumentBeforeSave

  • Comments 9

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).

  • Is there a way to change the autosave interval programmatically?

    Bruce
  • Sure -- Application.SaveInterval or something similar. Check MSDN
  • Make that Application.Options.SaveInterval.

    I checked VBA's IntelliSense ;-)
  • 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?
  • I am working on a similar problem, and I've found (at least in my initial tests) that if you only display your save-as dialog box when the SaveAsUI boolean is true, you don't get any sort of annoying crash or pop-up. It seems that if you are programmatically displaying the SaveAs dialog, you would only want to do that if Word was going to display it anyway.
  • Following up on this (I'm posting because I spent many, many hours trying to find a solution, and was unable to find anyone who actually got DocumentBeforeSave to work for them under Word 2000):

    "and I've found (at least in my initial tests) that if you only display your save-as dialog box when the SaveAsUI boolean is true, you don't get any sort of annoying crash or pop-up"

    This is true for Word XP and 2003 - but Word 2000 (in MS's infinite wisdom), always passes TRUE in for SaveAsUI, no matter what. This means that you have to play games to determine whether the event is a Save or a SaveAs.

    Here's how I worked around this (it's ugly...). In my AppEvents class, I have 3 variables for detecting the "Save state":

    Private m_FileSaveIsRunning As Boolean
    Private m_FileSaveAsIsRunning As Boolean
    Private m_ClosingDocument As Document

    I then have a regular module with FileSave and FileSaveAs overriden. When FileSave is called, it sets the FileSaveIsRunning property of the AppEvents class to TRUE, executes the regular Save functionality, then sets the FileSaveIsRunning property to FALSE.

    Something similar occurs for the FileSaveAs override.

    In the AppEvents class, implement DocumentBeforeClose, and set the m_ClosingDocument property to the document currently being closed.

    Then, implement DocumentBeforeSave, with the following logic:

    If FileSaveIsRunning is true, do nothing (accept default behavior)

    If FileSaveAsIsRunning is true, perform your custom SaveAs behavior (custom dialogs, whatever).

    If both are true, throw an exception or a messagebox saying there is a problem (I seriously doubt this can happen, but better safe than sorry!)

    If both FileSaveAsIsRunning and FileSaveIsRunning are false, we have one of two possible situations:

    a) We are getting called because a document is closing, Word asked the user if they want to save changes, and the user clicked Yes

    or

    b) Word is auto-saving the document


    We can detect condition (a) by comparing the m_ClosingDocument variable with the Doc variable passed to DocumentBeforeSave - if they are the same, then we are in situation (a).

    Otherwise, we assume situation (b), and just the default save behavior do its thing.

    At the end of the DocumentBeforeSave sub, I always set m_ClosingDocument to 'Nothing', just to keep things tidy (I'm pretty sure that this is not necessary, but it may create a circular reference somewhere that we wish we didn't have).

    Anyway - that's quite a bit of extra work just b/c MS forgot to set that UpdateUI variable in Word 2000 - but it seems to work as desired.

    The AutoSave definitely doesn't mess the code up anymore, and I haven't found a situation yet where the behavior doesn't work properly.

    Anyway - I hope this helps anyone else who is struggling with this like I was...

    - K
  • 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.
  • 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?
  • 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.
Page 1 of 1 (9 items)