First of all, this problem only happens on a few client machines and I can not replicate it on any of my test machines.
So I have the following test code in LINQPad:
var application = new Application();
var session = application.Session;
const string entryId = "arbitrary entry ID";
const string propertyName = "http://schemas.microsoft.com/mapi/string/{31A9B8DA-D4A0-4B96-87AE-01D6E9BCFCCE}/Test/0x0000001F";
// Save test property for the first time.
var mail = (MailItem)session.GetItemFromID(entryId);
var propertyAccessor = mail.PropertyAccessor;
propertyAccessor.SetProperty(propertyName, 1);
mail.Save();
Marshal.ReleaseComObject(propertyAccessor);
Marshal.ReleaseComObject(mail);
// Save test property for the second time.
mail = (MailItem)session.GetItemFromID(entryId);
var propertyAccessor = mail.PropertyAccessor;
propertyAccessor.SetProperty(propertyName, 2);
mail.Save();
Marshal.ReleaseComObject(propertyAccessor);
Marshal.ReleaseComObject(mail);
Marshal.ReleaseComObject(session);
Marshal.ReleaseComObject(application);
The second mail.Save()
call has a 100% rate on these few client machines to throw the exception: System.Runtime.InteropServices.COMException (0x80040109): The operation cannot be performed because the message has been changed.
Since the above code properly releases the first mail
object and retrieves the second mail
object using entry ID again. The chance to have something changing the mail
object between the second retrieval of the object and calling its Save()
method is very low, not to mention the 100% reproducible rate.
I can only think that it looks like a bug in Outlook that it may permanently mark a mail object as changed as soon as anything calls the Save()
method once.
Does any one know if there is a work around?
These machines are using the latest version of Office 2016.
IMAP4 is one of the worst - every time you try to touch any of the store objects, it tries to sync. You can try to bypass the IMAP4 layer and go directly to the PST provider used as the underlying local storage. In Extended MAPI (C++ or Delphi), you can do that using the IProxyStoreObject interface. In case of languages other than C++ or Delphi, you can use Redemption and its RDOSession.Stores.UnwrapStore
method - the message can be then opened from the unwrapped store using RDOStore.GetMessageFromID
.
User contributions licensed under CC BY-SA 3.0