最近我在这里询问了Outlook中的VBA代码,建议我创建一个外接程序来分发我的代码。我学习了一些C#,并创建了我的Outlook插件。经过大量的学习,我设法让它发挥作用,但现在我在优化方面遇到了困难。此代码会遍历“任务”文件夹和“联系人”文件夹,搜索特定的用户属性,然后删除这些项。
我正在运行我的外接程序大约900个项目,任务在几秒钟内完成,然后我试图获得一个更大的PST文件,并运行我的代码对大约10 000项,它需要大约10分钟。内存不断上升,直到达到500 it左右。我正在运行的这台机器非常好,所以我担心当一个客户端在一台缓慢的计算机上运行它时,它将花费很长时间。
我非常感谢在这个项目上的任何帮助,我刚刚开始使用C#,我不是一个程序员,我可以谷歌我的方式通过这个,但它有它的局限性。
非常感谢!
以下是单击按钮时发生的代码:
private void button1_Click(object sender, EventArgs e)
{
label2.Visible = true;
listBox1.Visible = false;
label4.Visible = false;
button1.Enabled = false;
Update();
Outlook.Store goodStore = null;
string selStore = listBox1.SelectedItem.ToString();
foreach (Outlook.Store store in Globals.ThisAddIn.Application.Session.Stores)
{
string exType = store.ExchangeStoreType.ToString();
if (exType != "olExchangePublicFolder")
{
if (Strings.InStr(store.DisplayName.ToString(), selStore) > 0)
{
goodStore = store;
}
}
}
if (goodStore == null)
{
MessageBox.Show("Error");
string keyname = @"HKEY_CURRENT_USER\Software\Microsoft\Office\Outlook\Addins\TACleanUpAddin";
Registry.SetValue(keyname, "LoadBehavior", "0", RegistryValueKind.DWord);
Environment.Exit(1);
}
Outlook.Folder taskFolder = (Outlook.Folder)goodStore.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderTasks);
Outlook.Folder contactFolder = (Outlook.Folder)goodStore.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts);
Outlook.Folder deletedFolder = (Outlook.Folder)goodStore.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderDeletedItems);
string uProperty = "crmxml";
string uPropertyCLS = "crmLinkState";
Outlook.UserProperty objProperty;
Outlook.UserProperty objPropertyCLS;
List<Outlook.TaskItem> tlist = new List<Outlook.TaskItem>();
List<Outlook.ContactItem> clist = new List<Outlook.ContactItem>();
foreach (Outlook.TaskItem ti in taskFolder.Items)
{
objProperty = ti.UserProperties.Find(uProperty, Outlook.OlUserPropertyType.olText);
if (objProperty == null)
{
Debug.Print("prop is null!");
}
else
{
string strProperty = objProperty.Value.ToString();
if (Strings.InStr(strProperty, "<phonecall><activityid>") > 0)
{
tlist.Add(ti);
}
else if (Strings.InStr(strProperty, "<letter><activityid>") > 0)
{
tlist.Add(ti);
}
else if (Strings.InStr(strProperty, "<fax><activityid>") > 0)
{
tlist.Add(ti);
}
}
}
foreach (Outlook.ContactItem ci in contactFolder.Items)
{
objPropertyCLS = ci.UserProperties.Find(uPropertyCLS, Outlook.OlUserPropertyType.olNumber);
if (objPropertyCLS == null)
{
Debug.Print("propCLS is null!");
}
else
{
clist.Add(ci);
}
}
foreach (Outlook.TaskItem ti in tlist)
{
ti.Delete();
}
foreach (Outlook.ContactItem ci in clist)
{
ci.Delete();
}
label2.Visible = false;
label3.Visible = true;
button2.Enabled = true;
}发布于 2015-11-11 23:51:46
首先,不要循环遍历文件夹中的所有项目,使用Items.Find/FindNext或Items.Restrict。
第二,不要将活动Outlook项存储在列表中--在联机Exchange存储的情况下,您可以耗尽RPC通道。要么立即处理这些条目并使用Marshal.ReleaseComObject释放它们,要么将条目ids存储在列表中,然后使用Application.Session.GetItemFromID重新打开项目(使用Marshal.ReleaseComObject仍然是个好主意)。
第三,确保您没有使用多点表示法,特别是在循环中。
string query = "@SQL=\"http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/MyPropName/0x0000001F\" = 'SomeValue' "
Outlook.Items items = taskFolder.Items;
Outlook.TaskItem ti = items.Find(query);
while (ti != null)
{
//do something
ti = items.FindNext();
}可以使用OutlookSpy检索属性的DASL名称的实际值--选择一个具有该属性集的项,单击OutlookSpy带上的IMessage按钮,找到该属性,请参阅"DASL“编辑框。
您的下一个优化可能是将搜索移动到单独的线程中。不幸的是,Outlook不能从外接程序中的次级线程中使用,因此它要么是扩展的MAPI (C++或Delphi),要么是赎罪 (我是它的作者)和它的RDO对象系列。
发布于 2015-11-11 22:11:30
我建议您删除要在原始循环中立即删除的项。也就是说,不要将它们添加到列表中,以后再删除它们。
将它们添加到列表中将阻止垃圾收集器收集它们的内存和它们的非托管资源,这就解释了您为什么占用了太多的内存。
我不确定,但我想,立即删除项可能会损坏(taskFolder.Items的)迭代器。如果是这种情况,那么只需迭代以最后一项开始,以第一项结尾的项,如下所示:
for (int i = contactFolder.Items.Count; i >= 1; i--)
{
Outlook.ContactItem ci = contactFolder.Items[i];
objPropertyCLS = ci.UserProperties.Find(uPropertyCLS, Outlook.OlUserPropertyType.olNumber);
if (objPropertyCLS == null)
{
Debug.Print("propCLS is null!");
}
else
{
ci.Delete();
}
}请注意,Outlook对象模型中的集合从索引1开始,而不是0。
https://stackoverflow.com/questions/33659796
复制相似问题