Как правильно выпустить Outlook MailItem? - PullRequest
5 голосов
/ 14 декабря 2010

Я просто не могу выпустить свои Outlook MailItems. После открытия 200 почтовых сообщений сервер Exchange возвращает максимально достигнутые открытые электронные письма.

Я удаляю свой UserProperty из всей выбранной Почты.

Мой код:


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();
  //----------------------------------
 }
}

Есть идеи, что случилось?

Ответы [ 5 ]

3 голосов
/ 14 декабря 2010

Я полагаю, это любая ошибка, как сказал Болу. Еще раз большое спасибо за помощь Болу.

Я сейчас использую следующий обходной путь:

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;
}
3 голосов
/ 14 декабря 2010

Вы можете попробовать это: вместо определения нового MailItem каждый раз в цикле For, вы можете определить mi вне цикла For или даже на уровне вашего класса и повторно использовать его для каждого почтового элемента? например:

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();

РЕДАКТИРОВАТЬ:

Попробуйте создать локальную переменную для каждой ссылки, например:

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

EDIT-2:

Если вы используете Outlook 2010, проверьте это: Выбор надстройки Outlook 2010 не очищается

1 голос
/ 01 декабря 2018

Вы используете многоточечную нотацию (mi.UserProperties.Find), что означает, что компилятор создает неявную переменную для хранения результата вызова mi.UserProperties;вы не можете явно освободить эту переменную.Этот объект содержит ссылку на его родительский объект MailItem.

Сохраните его в явной переменной и освободите его явно, используя Marshal.ReleaseComObject.То же самое для переменной UserProperty up.

Кроме того, не используйте foreach с коллекциями Outlook - этот цикл содержит ссылку на все элементы, пока цикл не завершится.Используйте цикл for и освобождайте элементы явно на каждом шаге цикла сразу после того, как вы закончите с этим элементом

  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  
1 голос
/ 29 января 2012

Просто поместите метод освобождения вне основного условия if.На элементы ссылаются, даже когда вы просто просматриваете их с помощью цикла foreach.Напишите

Marshal.ReleaseComObject(mi)

прямо перед последним "}".Это работает для меня.Я читал, что, как правило, вы должны явно освобождать каждый COM-объект.

1 голос
/ 14 декабря 2010

Попробуйте заменить foreach на цикл for и выполните следующее

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

Также удалите все ссылки на любые внешние объекты COM, которые вы можете использовать.

...