首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用VSTO加快获取Outlook文件夹中所有联系人的EntryID值

如何使用VSTO加快获取Outlook文件夹中所有联系人的EntryID值
EN

Stack Overflow用户
提问于 2017-11-27 10:21:19
回答 2查看 279关注 0票数 1

我需要为Outlook文件夹中的所有联系人获取EntryIDs。如果我在一个文件夹中有6000个联系人,执行大约需要100秒钟(如果后台线程或主线程,我尝试了这两个线程,这都不重要)。代码如下:

代码语言:javascript
复制
List<Outlook.ContactItem> contactItemsList = null;
Outlook.Items folderItems = null;
Outlook.MAPIFolder folderSuggestedContacts = null;
Outlook.NameSpace ns = null;
Outlook.MAPIFolder folderContacts = null;
object itemObj = null;
try
{
    contactItemsList = new List<Outlook.ContactItem>();
    ns = Application.GetNamespace("MAPI");
    // getting items from the Contacts folder in Outlook
    folderContacts = ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts);
    folderItems = folderContacts.Items;
    for (int i = 1; folderItems.Count >= i; i++)
    {
        itemObj = folderItems[i];
        if (itemObj is Outlook.ContactItem)
            contactItemsList.Add(itemObj as Outlook.ContactItem);
        else
            Marshal.ReleaseComObject(itemObj);
    }
    Marshal.ReleaseComObject(folderItems);
    folderItems = null;
}
catch (Exception ex)
{
    System.Windows.Forms.MessageBox.Show(ex.Message);
}
finally
{
    if (folderItems != null)
        Marshal.ReleaseComObject(folderItems);
    if (folderContacts != null)
        Marshal.ReleaseComObject(folderContacts);
    if (folderSuggestedContacts != null)
        Marshal.ReleaseComObject(folderSuggestedContacts);
    if (ns != null)
        Marshal.ReleaseComObject(ns);
}
var ids = contactItemsList.Select(c => c.EntryID).ToArray();

收集物品的部分大约需要5-8秒,而最后一行大约需要80-90秒。

有更快的路吗?我最初想到的是Items.SetColumns,但事实证明它不适用于EntryID (这似乎是Outlook开发人员的奇怪决定,因为EntryID只是一个字符串,SetColumns用于快速检索字符串属性)。

而且,Outlook几乎冻结了所有时间(~100秒),即使使用BackgroundWorker。你可以意外地点击一些东西,但这就像FPS的速率是1-2 FPS左右。背景执行似乎没有多大帮助。我怀疑这是因为当正在执行的任务不是CPU密集型的时候,后台执行是很棒的,但是获取EntryIDs是一项繁重的操作,因此对UI造成严重的干扰。

我还有一些遗留的C++/COM代码,它们也是这样做的,而且速度也很慢。看来.NET互操作并不是问题的根本原因。也许还有另一个API调用,我应该使用它吗?

我目前正在用Outlook 2010 64位进行测试。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-11-27 21:07:16

使用MAPITable.GetTable从单个调用中的多个项检索属性,而不打开它们(这真的很昂贵)。

其次,OOM不能在辅助线程上使用--它从未被支持过,而Outlook 2016一旦检测到除了主UI线程之外,它就会引发异常。只有扩展的MAPI (C++或Delphi)是线程安全的.您还可以使用赎罪 (任何语言--我是它的作者)和它的RDO系列对象--它是基于100%扩展的MAPI的,可以从二级线程中使用。特别是,您可以使用

代码语言:javascript
复制
RDOFolder.Items.MAPITable.ExecSQL("SELECT EntryID FROM FOLDER WHERE MessageClass = 'IPM.Contact' ")

检索所有联系人的条目ids作为记录集。

票数 2
EN

Stack Overflow用户

发布于 2017-11-27 13:09:51

好的,明白了。分割块中的"for“并保持同时存在的Outlook.ContactItem对象的数量(如我上面的注释)是优化的一部分,但更重要的是另一件事。

医生说你不能使用Items.SetColumns("EntryID"),但从来不解释原因。实际上,您不能将它传递到那里,因为EntryID总是返回的!因此,传递任何其他轻量级属性(我使用了“缩写”)就可以做到这一点。它只返回EntryID和初始值字段设置的对象,这将提高4-5倍的性能。

再加上块优化,我现在可以在6秒内在后台线程中完成所有的工作(主线程甚至更快)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47508605

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档