开发者

How to release Outlook objects correctly?

I just can't release my Outlook MailItems. After opening 200 Mails the Exchange Sever returns the maximum open Emails is reached.

I'm remove my UserProperty from all selected Mail.

My Code:


foreach (var selection in Globals.ThisAddIn.Application.ActiveExplorer().Selection)
{
 if (selection is MailItem)
 {
  MailItem mi = (MailItem)selection;
  UserProperty up = mi.UserProperties.Find("MyProp");
  if (up != null)
  {
   up.Delete();
   //##################################
   // I also tried :
   //----------------------------------
   //    Marshal.ReleaseComObject(up);
   //    up = null;
   //----------------------------------
  }

  mi.Save();

  //##################################
  // I also tried :
  //----------------------------开发者_开发百科------
  //     mi.Close(OlInspectorClose.olDiscard);
  //----------------------------------


  // I don't know if this loop is necessary, but I have found it somewhere on the web
  while (Marshal.ReleaseComObject(mi) > 0);
  mi = null;

  //##################################
  // I also tried :
  //----------------------------------
  //    GC.Collect();
  //    GC.WaitForPendingFinalizers();
  //----------------------------------
 }
}

Any idea what's wrong?


You can try this: Instead of defining a new MailItem everytime within the For loop, can you define mi outside the For loop or even in your class level, and reuse it for each mailitems? e.g:

MailItem mi;
foreach (var selection in Globals.ThisAddIn.Application.ActiveExplorer().Selection)
{
 if (selection is MailItem)
 {   
   mi= (MailItem)selection;
   // your other code...
 }
 }
mi=null;
GC.Collect();
GC.WaitForPendingFinalizers();

EDIT:

Try to create local variable for each references e.g:

Outlook.Explorer myExplorer=Application.ActiveExplorer(); 
Outlook.Selection mySelection=myexplorer.Selection; 
foreach (var selection in mySelection)
{
}
myExplorer=null;
mySelection=null;
//....

EDIT-2:

IF you are using Outlook 2010 check this: Outlook 2010 addin selection not clearing


I believe its any kind of bug like Bolu said. Again much thanks for your help Bolu.

I'm now using following workaround:

List entryids = new List();

foreach (var selection in Globals.ThisAddIn.Application.ActiveExplorer().Selection)
{
    MailItem mi = selection as MailItem;
    if (mi != null)
    {
        // For any reason it's not possible to change the mail here

        entryids.Add(mi.EntryID);

        Marshal.ReleaseComObject(mi);
        mi = null;

    }
}

foreach (string id in entryids)
{
    MailItem mi = Globals.ThisAddIn.Application.ActiveExplorer().Session.GetItemFromID(id);

    // My changes on the mail

    mi.Save();
    Marshal.ReleaseComObject(mi);
    mi = null;
}


You are using multiple dot notation (mi.UserProperties.Find), which means the compiler creates an implicit variable to hold the result of the mi.UserProperties call; you cannot explicitly release that variable. That object holds a reference to its parent MailItem object.

Store it in an explicit variable and release it explicitly using Marshal.ReleaseComObject. Ditto for the UserProperty up variable.

Also, do not use foreach with Outlook collections - that loop holds a reference to all items until the loop exits. Use a for loop and release the items explicitly on each step of the loop immediately after you are done with that item

  Selection selectedItems = Globals.ThisAddIn.Application.ActiveExplorer().Selection; 
  for (int i = 1; i <= selectedItems.Count; i++)
  {
    object selection = selectedItems[i];
    MailItem mi = selection as MailItem;
    if (mi != null) //can have items other than MailItem
    {
      UserProperties props = mi.UserProperties;
      UserProperty up = props.Find("MyProp");
      if (up != null)
      {
        ...
        Marshal.ReleaseComObject(up);
      };
      Marshal.ReleaseComObject(props);
      Marshal.ReleaseComObject(mi);
    }; //if   
    Marshal.ReleaseComObject(selection);
  }; //for  


Try to replace foreach with a for loop and do the following

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

Also remove all the reference to any outlook COM object that you might be using.


Just put the releasing method outside the main if condition. Items get referenced even when you just loop through them with the foreach loop. Write

Marshal.ReleaseComObject(mi)

right before the last "}". This works for me. I read that generally you have to release every COM object explicitly.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜