How to release Outlook objects correctly?
Asked Answered
M

5

6

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?

Mosora answered 14/12, 2010 at 9:3 Comment(0)
M
3

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;
}
Mosora answered 14/12, 2010 at 13:38 Comment(0)
T
3

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

Tattler answered 14/12, 2010 at 10:28 Comment(9)
Still the same error. I've nearly the same code in an other methode, but with "Folder.Items" instead "Selection". In this case it work without a problem, even without GC.Mosora
I just tried to replaced ActiveExplorer().Selection with ActiveExplorer().CurrentFolder.Items, this also works without a problem. It looks like the ActiveExplorer().Selection is the problem. Any idea what could help?Mosora
@Wowa, how did you invoke this method?Tattler
via OnClick from a button in my addin ribbonMosora
@Wowa, have you tried to create a local variable for each references? e.g: myExploer=Application.ActiveExplorer(); mySelection=myexplorer.Selection; then use these local variables instead?Tattler
yes, i even tried to use a for loop and released the <code>var item = myexplorer.Selection[i] object too. I don't understand why it works with Folder.Items, but not with _Explorer.SelectionMosora
@Wowa, are you using outlook2010? seems it was reported as a bug. social.msdn.microsoft.com/forums/en-us/vsto/thread/…Tattler
yes i'm using outlook 2010, but it looks like its another problem, because my selection is cleared, and my error comes from the exchange which thinks there are 250 open email. Or it might be another selection but, who knows.Mosora
i don't know if it help, but as long i only grab the MailItem.EntryID all works fine. but if i youse the Save methode or grab the userprobertys i doesn't workMosora
M
3

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;
}
Mosora answered 14/12, 2010 at 13:38 Comment(0)
H
3

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  
Hyalite answered 1/12, 2018 at 18:43 Comment(0)
P
2

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.

Paleography answered 14/12, 2010 at 10:48 Comment(3)
the problem still remains. I believe "Selection" doesn't release the mailitem, because with "CurrentFolder.Items" all works fineMosora
Don't use dot for accessing the objects. Always keep a seperate object and release them. e.g. instead of Application.ActiveExplorer.Selection create Application/ActiveExplorer/Selection objects. Same for the Userproperties. I think userproperties object is not being released properly due to which limit is being reached.Paleography
I already tried to create object for everything. loop with for and foreach and release all object. I release the userproperty with the Selection the same way I'm doing it with my workaround, so i believe this also can't be the problem. BUT it may be possible the userproperty can't be released because the Selection somehow holds it.Mosora
E
1

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.

Estaestablish answered 29/1, 2012 at 12:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.