none
Outlook freeze/restart trying to Save() current appointment (AccessViolationException) RRS feed

  • Question

  • I maintain an Outlook VSTO add-in. If the user opens an appointment window, and while it's open the sender updates the appointment, when the user closes the appointment window there's about a one in six chance Outlook will freeze, crash, and restart. It doesn't happen every time. Debugger shows an AccessViolationException that my add-in is unable to catch.

    Upon restart, users get the error, "Outlook experienced a serious problem with the '<Addin Name>' add-in. If you have seen this message multiple times, you should disable this add-in and check to see if an update is available. Do you want to disable this add-in?"

    We've seen this almost entirely on Outlook 2010. This happens with no other add-ins enabled.

    Here are the exception details:

    System.AccessViolationException was unhandled by user code
      HResult=-2147467261
      Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
      Source=Outlook Scheduler
      StackTrace:
           at Microsoft.Office.Interop.Outlook._AppointmentItem.Save()
           at Outlook_Scheduler.App_Code.AppointmentItemWrapper.Close() in c:\...\Outlook Scheduler\App_Code\AppointmentItemWrapper.cs:line 139
           at Outlook_Scheduler.App_Code.InspectorWrapper.Inspector_Close() in c:\...\Outlook Scheduler\App_Code\InspectorWrapper.cs:line 63
      InnerException: 

    And here's the Close() event handler that's firing, abbreviated:

    internal class AppointmentItemWrapper : InspectorWrapper {
      //... other members ...
      protected override void Close() {
        if (Globals.ThisAddIn.Application.ActiveInspector() != null)
        {
          try
          {
            var currentAppointment = (Outlook.AppointmentItem)Globals.ThisAddIn.Application.ActiveInspector().CurrentItem;
            var lastModificationTime = currentAppointment.LastModificationTime;
            var creationTime = currentAppointment.CreationTime;
            // ...
            if (...)
            {
              // ...
            }
            else if (currentAppointment.Saved && // If user clicked "yes" on save prompt, or if item has not been modified since last save or creation.
              !(creationTime.Equals(lastModificationTime))) // If item has been modified since creation.
            {
              // [[[This is the code path taken]]]
              // ...
              currentAppointment.Save(); // <=== Occasional "AccessViolationException" not caught by catch statement, below. Outlook freezes/restarts. HResult=-2147467261, Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
            }
          }
          catch (Exception e)
          {
            // Log exception
          }
        }
        // ...
      }
    }

    Note the currentAppointment.Save() line. The debugger shows the exception there, but at runtime it's not caught.

    The else-if block was added because we had issues where the user was prompted to save each appointment, even if it was unmodified.

    The appointments have some UserProperty on them.

    Does anyone know what's wrong here or how to troubleshoot further? I'm new to VSTO and didn't write this, so I'm not sure if the Outlook object model is being handled properly. The InspectorWrapper class appears to be from this article.




    • Edited by JVimes3 Wednesday, April 1, 2015 9:32 PM
    Wednesday, April 1, 2015 8:56 PM

Answers

  • Hello,

    The Close event handler is not suitable for saving items. Try to remove or comment the following line of code:

    currentAppointment.Save();

    The Close method of the Inspector class accepts the OlInspectorClose enumeration which is used to indicate the save mode. And you are trying to overwrite/change the chosen way in the code.

    Also I'd suggest breaking the chain of calls and declaring each property or method on a single line of code:

    Application.ActiveInspector().CurrentItem

    For example, the ActiveInspector method returns an instance of the Inspector class. Then the CurrentItem property of the Inspector class returns an instance of the AppointmentItem class. Both objects are left alive. Instead, I'd recommend releasing them instantly. Use System.Runtime.InteropServices.Marshal.ReleaseComObject to release an Outlook object when you have finished using it. Then set a variable to Nothing in Visual Basic (null in C#) to release the reference to the object. Read more about that in the Systematically Releasing Objects article.

    Finally, always install the latest updates and service packs for Office applications. 

    Wednesday, April 1, 2015 10:08 PM

All replies

  • Hello,

    The Close event handler is not suitable for saving items. Try to remove or comment the following line of code:

    currentAppointment.Save();

    The Close method of the Inspector class accepts the OlInspectorClose enumeration which is used to indicate the save mode. And you are trying to overwrite/change the chosen way in the code.

    Also I'd suggest breaking the chain of calls and declaring each property or method on a single line of code:

    Application.ActiveInspector().CurrentItem

    For example, the ActiveInspector method returns an instance of the Inspector class. Then the CurrentItem property of the Inspector class returns an instance of the AppointmentItem class. Both objects are left alive. Instead, I'd recommend releasing them instantly. Use System.Runtime.InteropServices.Marshal.ReleaseComObject to release an Outlook object when you have finished using it. Then set a variable to Nothing in Visual Basic (null in C#) to release the reference to the object. Read more about that in the Systematically Releasing Objects article.

    Finally, always install the latest updates and service packs for Office applications. 

    Wednesday, April 1, 2015 10:08 PM
  • Removing the Save() call fixes the crash issue, but reintroduces an old bug where the user was prompted, "Want to save your changes?" multiple times when Outlook is closed. My predecessor tried to fix that with the Save() call, but it sounds like that's not the right way.

    Your comment about releasing COM objects and this StackOverflow answer of yours make me think the original save-prompt bug was due to Outlook objects not released properly. I'm planning to find all references to Inspectors and AppointmentItems and make sure they're being explicitly released.

    Any other object types you think I should look for?

    I need to read more about releasing COM objects. I've seen a few articles saying that Marshal.ReleaseComObject() is considered dangerous [1,2,3]. Let me know what you think. The answer on this thread talks about another approach that calls the garbage collector. I see my codebase doing that in multiple spots, but I don't know if correctly.

    Thursday, April 2, 2015 8:51 PM
  • Refer to the Systematically Releasing Objects article in MSDN for more information about releasing COM objects.

    There is a difference where to call the Save method. Not all event handlers are suitable for that. 


    Thursday, April 2, 2015 9:18 PM
  • To follow up for other readers, my fix was to move the saving-related code to the ItemChange event handler on our collection of appointment items (the collection returned by Application.GetNamespace("MAPI").GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderCalendar).Items).

    Thanks so much for the help, Eugene!

    Tuesday, June 2, 2015 9:07 PM