簡體   English   中英

C# Outlook 插件優化

[英]C# Outlook Add-in optimization

我最近在這里詢問了 Outlook 中的 VBA 代碼,有人建議我創建一個加載項來分發我的代碼。 我學習了一些 C# 並創建了我的 Outlook 插件。 經過大量學習,我設法讓它工作,但現在我在優化方面遇到了麻煩。 此代碼通過 Tasks 文件夾和 Contacts 文件夾搜索特定的用戶屬性,然后刪除這些項目。

我在大約 900 個項目上運行我的加載項,任務在幾秒鍾內完成,然后我嘗試獲取更大的 PST 文件並在大約 10 000 個項目上運行我的代碼,大約需要 10 分鍾。 內存不斷上升,直到達到大約 500Mo。 我正在運行它的機器非常好,所以我擔心當客戶端在慢速計算機上運行它時,它會花費很長時間。

我將不勝感激對這個項目的任何幫助,我剛剛開始使用 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;
    }

首先,不要遍歷文件夾中的所有項目,使用 Items.Find/FindNext/Restrict。

其次,不要將實時 Outlook 項目存儲在列表中 - 如果是在線 Exchange 存儲,您可能會用完 RPC 通道。 立即處理項目並使用 Marshal.ReleaseComObject 釋放它們,或者將條目 ID 存儲在列表中,稍后使用 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對象系列的Redemption

我建議您在原始循環中立即刪除要刪除的項目。 即,不要將它們添加到列表中並稍后刪除它們。

將它們添加到列表中將阻止垃圾收集器收集它們的內存和它們的非托管資源,這就解釋了為什么你消耗了太多內存。

我不確定,但我想立即刪除項目可能會損壞迭代器( 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 開頭。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM