Reputation: 1811
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?
Upvotes: 6
Views: 9189
Reputation: 66255
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
Upvotes: 3
Reputation: 1647
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.
Upvotes: 2
Reputation: 1832
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.
Upvotes: 1
Reputation: 1811
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;
}
Upvotes: 3
Reputation: 8786
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
Upvotes: 3