Home > database >  Cause of and fix for "The operation cannot be performed because the message has been changed&qu
Cause of and fix for "The operation cannot be performed because the message has been changed&qu

Time:07-20

The code I am trying to get to work simply adds a 'C' to a mails subject or removes it, if it already is there. The following is just a simplification of the original problem that yields the same problem. I'm using the .NET framework 4.7.2 and Add-In Express Regions for the UI (Which I don't think matters).

The ThisAddIn class contains the following:

    private static Explorer _explorer;

    private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
        {initializing code}
        _explorer = Application.ActiveExplorer();
    }

    public static MailItem GetMail()
    {
        var selection = _explorer.Selection;
        if (selection.Count == 0)
            return null;
        return selection[1];
    }

And the button-click event in the Form only has this code:

    private void button1_Click(object sender, EventArgs e)
    {
        var mail = ThisAddIn.GetMail();
        if (mail.Subject.StartsWith("C"))
            mail.Subject = mail.Subject.TrimStart('C');
        else
            mail.Subject = "C"   mail.Subject;
        mail.Save();
    }

And this actually works fine for mails from my personal mailbox, but throws exceptions for mails from Exchange, so the ones I get to load by clicking this button:

Mails that only appear after clicking this button throw the exception

Clicking the button once works fine, but clicking it once again on always throws an System.Runtime.InteropServices.COMException with 'The function cannot be performed because the message has been changed.' as message. Which I get, since it has indeed be changed. And looking through StackOverflow I read, that I have to release the COM objects with System.Runtime.InterServices.Marshal.ReleaseComObject(). My question here are:

  • Why do I have to explicitly release objects in 2022? It really feels like I'm doing something way outdated.
  • How? Is it really the correct Method?
  • What (do I release)? The mails? The _explorer? Everything? I am especially confused about this one, since whatever I try to release, it does not seem to fix it. Also Where do I release "it" - in the ThisAddIn or the Form?

I appreciate any help!

CodePudding user response:

Don't keep objects alive if you don't need them to get the events fired. Otherwise, you may get sync issues with Exchange. This is also a possible indication of using the code (modifying objects) on multiple threads. Instead, you may get the currently selected items from the region class where a button click is handled.

Note, in Add-in Express form regions you may use the ExplorerObj or InspectorObj properties to get the items where the form region is displayed for.

CodePudding user response:

If you don't use Marshal.ReleaseComObject, it will be released by the GC at some undetermined future time a few seconds later. If the object is still alive (before GC releases it), Outlook caches it and returns the same stale object. That wouldn't be a problem, but Exchange likes to tweak objects after they are saved. E.g. the following sequence will result in the error you are seeing:

  1. You modify an object
  2. OST provider pushes the change to the server
  3. Exchange modifies it
  4. The change is pulled from the server to OST
  5. You modify the same object from (1) again.

The solution is to release objects are soon as you are done with them so that they are reopened anew the next time you need to modify them.

Note that if a message is selected, Outlook might cache it itself even if you release it with Marshal.ReleaseComObject. Appointment are worse than messages in this respect - you might need to select a different folder and come back to flush Outlook cache.

  • Related