Outlook加载项ItemAdd事件处理程序



我开发了一个outlook插件,它已经被许多用户使用。在我们的插件中,我们有一个功能,可以捕获存储在任何特定outlook文件夹下的任何电子邮件,以捕获我正在使用ItemAdd事件。

用户A和用户B具有相同的共享邮箱。

目前,当用户A注册了一个共享文件夹来捕获来自addin的电子邮件时,只有用户A会触发ItemAdd事件,用户B也使用我们addin的同一共享邮箱,但对他来说,该事件不会触发。这是意料之中的事吗?如果有邮件被添加到特定文件夹中,我们是否有任何触发事件?

以下是如何注册事件的代码示例片段:

Interop.Folder fldr = this.GetFolder(folder.EntryId);
if (fldr != null)
{
Interop.Items items = fldr.Items;
items.ItemAdd += MappedItems_ItemAdd;
}
public Interop.Folder GetFolder(string entryId)
{
Interop.Folder retVal = null;
try
{
try
{
retVal = m_outlook.Application.Session.GetFolderFromID(entryId) as Interop.Folder;
}
catch { }
if (retVal != null)
{
try
{
string name = retVal.Name;
}
catch (Exception)
{
retVal = null;
}
}
return retVal;
}

问题的原因与Outlook无关,而是垃圾收集器在基于.net的应用程序中的工作方式。例如,在代码中,您在if条件的有限范围内声明源项集合:

Interop.Folder fldr = this.GetFolder(folder.EntryId);
if (fldr != null)
{
Interop.Items items = fldr.Items;
items.ItemAdd += MappedItems_ItemAdd;
}

因此,当代码完成并超出if条件时,items对象被标记为从堆中滑动。GC可能会在对象运行的任何时候删除它,你永远不会从中接收到事件。为了避免这种问题,你需要在类级别声明源对象,这样它就永远不会超出作用域,GC也不会标记它进行收集:

// declare at the class the source object of events
Interop.Items items = null;
// in the code somewhere you may set it up to handle events
if (fldr != null)
{
items = fldr.Items;
items.ItemAdd += MappedItems_ItemAdd;
}