Outlook Add-In Crashes or Your server administrator has limited the number of items you can open simultaneously

◇◆丶佛笑我妖孽 提交于 2019-12-12 02:26:21

问题


I have created a simple Outlook Add-in for copying contacts from one folder to another.(~5000 contacts)

Why I need this? There is a weird way for creating a public address book as described here.

So why not copy all the contacts in the public folder? I want my team to have a shared addressbook with my contacts but with only Fullname and emails as information.

I have added a toolbar with two Buttons. Choose folders and Synchronize.

My Problem is that when running Synchronization after a while I get

Your server administrator has limited the number of items you can open simultaneously. Try closing messages you have opened or removing attachments and images from unsent messages you are composing.

I used Marshal.ReleaseComObject in every Object, tried to add some delay between Add. But still get the same error.

Then I found a post here in StackOverflow saying to add GC.Collect that stopped the error above but the Outlook always crashes at the end of Synchronizing and sometimes at the middle of it.

Any help will be appreciated.

Synchronize Code

 private Task SynchronizeContactsSync()
    {
        return Task.Run(async () =>
        {
            if (!synchronizing)
            {
                synchronizing = true;

                Outlook.Folder toFolder = null;
                Outlook.Folder fromFolder = null;
                try
                {
                    if (!string.IsNullOrWhiteSpace(tEntryID) && !string.IsNullOrWhiteSpace(tStoreID) &&
                    !string.IsNullOrWhiteSpace(fStoreID) && !string.IsNullOrWhiteSpace(tEntryID))
                    {
                        toFolder = Application.Session.GetFolderFromID(tEntryID, tStoreID) as Outlook.Folder;
                        fromFolder = Application.Session.GetFolderFromID(fEntryID, fStoreID) as Outlook.Folder;
                    }

                    if (toFolder != null && fromFolder != null)
                    {
                        toFolder.InAppFolderSyncObject = false;
                        int currentItem = 0;


                        int itemCount = fromFolder.Items.Count;

                        //I dont want to use foreach because it keeps reference of each object until is done
                        //I cast it to list because i cant use for statement with fromFolder.Items

                        List<Outlook.ContactItem> items = fromFolder.Items.Cast<Outlook.ContactItem>().ToList(); ;

                        for (int i = 0; i < items.Count; i++)
                        {

                            //await Task.Delay(33);
                            await addContactSync(items[i], toFolder);
                            if (items[i] != null) Marshal.ReleaseComObject(items[i]);
                            GC.Collect();
                            GC.WaitForPendingFinalizers();
                            GC.Collect();
                            GC.WaitForPendingFinalizers();
                            currentItem++;
                            syncText = "Synchronize progress " + currentItem + " of " + itemCount;
                        }

                        synchronizing = false;
                        syncText = "No Synchronize in progress";



                    }
                    MessageBox.Show("Done.", "Synchronize", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    if (toFolder != null) Marshal.ReleaseComObject(toFolder);
                    if (fromFolder != null) Marshal.ReleaseComObject(fromFolder);
                    toFolder.InAppFolderSyncObject = true;
                }
                catch (Exception ex)
                {
                    if (toFolder != null) Marshal.ReleaseComObject(toFolder);
                    if (fromFolder != null) Marshal.ReleaseComObject(fromFolder);
                    toFolder.InAppFolderSyncObject = true;
                    synchronizing = false;
                    syncText = "No Synchronize in progress";
                    MessageBox.Show(ex.Message, "Synchronize", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            else
            {
                MessageBox.Show("Check you settings or please wait for the synchronization to finish.", "Synchronize", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        });
    }



    private Task addContactSync(Outlook.ContactItem item, Outlook.Folder toFolder)
    {
        return Task.Run(() =>
        {
            try
            {

                if (!string.IsNullOrWhiteSpace(item.Email1Address))
                {
                    string filter = "[FullName] = '" + item.FullName + "'";// "[NickName] = '" + item.NickName + "' or [Email1Address] = '" + item.Email1Address + "' or 

                    Outlook.ContactItem matches = (Outlook.ContactItem)toFolder.Items.Find(filter);
                    if (matches == null)
                    {
                        Outlook.ContactItem contact = toFolder.Items.Add(Outlook.OlItemType.olContactItem);
                        contact.FullName = item.FullName;
                        contact.NickName = item.NickName;
                        contact.Email1Address = item.Email1Address;
                        contact.Email2Address = item.Email2Address;
                        contact.Save();
                        Marshal.ReleaseComObject(contact);
                        itemSyncCount++;
                        lastItemSync = DateTime.Now;
                    }
                    else
                    {
                        matches.Email1Address = item.Email1Address;
                        matches.Email2Address = item.Email2Address;
                        matches.Save();
                        itemSyncCount++;
                        lastItemSync = DateTime.Now;
                    }

                    if (item != null) Marshal.ReleaseComObject(item);
                    if (matches != null) Marshal.ReleaseComObject(matches);

                }
            }
            catch (Exception ex)
            {
                Marshal.ReleaseComObject(item);
                MessageBox.Show(ex.Message, "Contact", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        });
    }

回答1:


Do not use any LINQ statements against Outlook collections. Or you will trap into such situations. For example:

 List<Outlook.ContactItem> items = fromFolder.Items.Cast<Outlook.ContactItem>().ToList(); ;

The line of code creates a new COM object for each item in the folder simultaneously. Instead, you can iterate over all items in the folder in the for loop and release objects instantly by using the Marshal.ReleaseComObject method.

 for (int i = 0; i < items.Count; i++)
 {
     object item = items[i];
     ...
     Marshal.ReleaseComObject(item); item = null;
 }

Use System.Runtime.InteropServices.Marshal.ReleaseComObject to release an Outlook object when you have finished using it. This is particularly important if your add-in attempts to enumerate more than 256 Outlook items in a collection that is stored on a Microsoft Exchange Server. If you do not release these objects in a timely manner, you can reach the limit imposed by Exchange on the maximum number of items opened at any one time. Then set a variable to Nothing in Visual Basic (null in C#) to release the reference to the object. Read more about that in the Systematically Releasing Objects article.



来源:https://stackoverflow.com/questions/36826927/outlook-add-in-crashes-or-your-server-administrator-has-limited-the-number-of-it

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!