我需要为Outlook文件夹中的所有联系人获取EntryIDs。如果我在一个文件夹中有6000个联系人,执行大约需要100秒钟(如果后台线程或主线程,我尝试了这两个线程,这都不重要)。代码如下:
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位进行测试。
发布于 2017-11-27 21:07:16
使用MAPITable.GetTable从单个调用中的多个项检索属性,而不打开它们(这真的很昂贵)。
其次,OOM不能在辅助线程上使用--它从未被支持过,而Outlook 2016一旦检测到除了主UI线程之外,它就会引发异常。只有扩展的MAPI (C++或Delphi)是线程安全的.您还可以使用赎罪 (任何语言--我是它的作者)和它的RDO系列对象--它是基于100%扩展的MAPI的,可以从二级线程中使用。特别是,您可以使用
RDOFolder.Items.MAPITable.ExecSQL("SELECT EntryID FROM FOLDER WHERE MessageClass = 'IPM.Contact' ")检索所有联系人的条目ids作为记录集。
发布于 2017-11-27 13:09:51
好的,明白了。分割块中的"for“并保持同时存在的Outlook.ContactItem对象的数量(如我上面的注释)是优化的一部分,但更重要的是另一件事。
医生说你不能使用Items.SetColumns("EntryID"),但从来不解释原因。实际上,您不能将它传递到那里,因为EntryID总是返回的!因此,传递任何其他轻量级属性(我使用了“缩写”)就可以做到这一点。它只返回EntryID和初始值字段设置的对象,这将提高4-5倍的性能。
再加上块优化,我现在可以在6秒内在后台线程中完成所有的工作(主线程甚至更快)。
https://stackoverflow.com/questions/47508605
复制相似问题