我正在创建一个 Microsoft Outlook 加载项(Visual Studio 2012、C#、COM 加载项,无 VSTO,Outlook 2010/2013/2016),用户必须能够在其中编写和读取必须映射到/从的各种字段消息离开/进入 Microsoft Exchange 时的 MIME 标头(即来自命名空间 PS_INTERNET_HEADERS 的属性)。
当用户转发消息时,我想将原始消息中的属性复制到转发的消息中。我通过监听事件 Application.ItemLoad 和 MailItem.Forward 来做到这一点,其中复制发生在后者的事件处理程序中。
这在我的开发机器上的 Outlook 2013 版本 15.0.4771.1000 中运行良好,但在虚拟机上运行的 Outlook 2013 版本 15.0.4771.1000 中却不行。在具有 Outlook 2010 的其他虚拟机上,它也不起作用。
问题是,如果我在 Inspectors.NewInspector 的事件处理程序中读取转发消息的属性值,我会意外得到空值。但是,如果我更改主题,保存转发消息的草稿并重新打开它,则属性值符合预期。因此,属性以某种方式发生了变化,但是当我第一次在 NewInspector 的事件处理程序中读取它们时,这并没有反映出来。我做错了什么?
下面是一些展示问题的示例代码。我只包含了我认为证明问题所必需的清理代码。
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);
}
}
}