I am creating a Microsoft Outlook add-in (Visual Studio 2012, C#, COM add-in, no VSTO, Outlook 2010/2013/2016), where users must be able to compose and read various fields that must be mapped to/from MIME headers when messages leave/enter Microsoft Exchange (i.e. properties from namespace PS_INTERNET_HEADERS).
When a user forwards a message, I want to copy properties from the original message to the forwarded message. I do this by listening to events Application.ItemLoad and MailItem.Forward, where the copying takes place in the event handler for the latter.
This works fine in Outlook 2013 version 15.0.4771.1000 on my development machine, but not in Outlook 2013 version 15.0.4771.1000 running on a virtual machine. On other virtual machines with Outlook 2010 it doesn't work either.
The problem is that if I read property values in an event handler for Inspectors.NewInspector for the forwarded message, I unexpectedly get empty values. But if I change e.g. the subject, save the draft of the forwarded message and reopen it, the property values are as expected. Thus the properties are somehow changed, but that is not reflected when I read them the first time in the event handler for NewInspector. What do I do wrong?
Below is some sample code that exhibits the problem. I included only the clean-up code that I deemed necessary to prove the problem.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Outlook = Microsoft.Office.Interop.Outlook;
namespace ForwardTest
{
public class Application
{
private readonly Outlook.Application application;
private readonly HashSet<MailItem> loadedMailItems;
public Application(Outlook.Application application)
{
this.application = application;
loadedMailItems = new HashSet<MailItem>();
application.ItemLoad += ItemLoad;
application.Inspectors.NewInspector += NewInspector;
}
private void ItemLoad(object item)
{
loadedMailItems.Add(new MailItem((Outlook.MailItem)item));
}
private void NewInspector(Outlook.Inspector inspector)
{
var mailItem = (Outlook.MailItem)inspector.CurrentItem;
// Next line unexpectedly shows empty values for some Outlook versions.
System.Windows.Forms.MessageBox.Show(Properties.Get(mailItem), Properties.FooName);
}
}
public class MailItem
{
private readonly Outlook.MailItem mailItem;
public MailItem(Outlook.MailItem mailItem)
{
this.mailItem = mailItem;
((Outlook.ItemEvents_10_Event)mailItem).Forward += Forward;
}
private void Forward(object forward, ref bool cancel)
{
var value = Properties.Get(mailItem);
Properties.Set((Outlook.MailItem)forward, "FW: " + value);
Marshal.ReleaseComObject(forward);
}
}
public static class Properties
{
public const string FooName = "http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/MMHS-Foo";
public static string Get(Outlook.MailItem mailItem)
{
var propertyAccessor = mailItem.PropertyAccessor;
var values = (object[])propertyAccessor.GetProperties(new[] { FooName });
var value = values[0] as string ?? string.Empty;
Marshal.ReleaseComObject(propertyAccessor);
return value;
}
public static void Set(Outlook.MailItem mailItem, string value)
{
var propertyAccessor = mailItem.PropertyAccessor;
propertyAccessor.SetProperty(FooName, value);
Marshal.ReleaseComObject(propertyAccessor);
}
}
}