none
Net 4.5 Outlook add-in releasing com objects RRS feed

  • Question

  • I have seen a plethora of information on the need to release references to Outlook COM objects. Mostly using ReleaseComObject

    What is the definitive answer to this question:

    Using .Net 4.5 and VSTO 4.0 - Is it necessary to explicitly release references to Objects?

    Sunday, January 25, 2015 3:38 PM

Answers

  • Hello Andrew,

    You can find the definitive answer in the Systematically Releasing Objects article in MSDN (the official source). It states the following:

    All Outlook add-ins should systematically release their references to Outlook objects when they are no longer needed. Failing to systematically release reference to Outlook objects can prevent Microsoft Office Outlook from shutting down properly.

    Use System.Runtime.InteropServices.Marshal.ReleaseComObject to release an Outlook object when you have finished using it. Then set a variable to Nothing in Visual Basic (null in C#) to release the reference to the object.

    Also you may consider using the GC methods for swiping the heap instead - an uncontrolled way of releasing COM objects. Don't forget to call them twice, for example:

    GC.Collect
    GC.WaitForPendingFinalizers
    GC.Collect
    GC.WaitForPendingFinalizers
    As for me, I prefer using the ReleaseComObject methods inplace.

    Sunday, January 25, 2015 4:16 PM

All replies

  • Hello Andrew,

    You can find the definitive answer in the Systematically Releasing Objects article in MSDN (the official source). It states the following:

    All Outlook add-ins should systematically release their references to Outlook objects when they are no longer needed. Failing to systematically release reference to Outlook objects can prevent Microsoft Office Outlook from shutting down properly.

    Use System.Runtime.InteropServices.Marshal.ReleaseComObject to release an Outlook object when you have finished using it. Then set a variable to Nothing in Visual Basic (null in C#) to release the reference to the object.

    Also you may consider using the GC methods for swiping the heap instead - an uncontrolled way of releasing COM objects. Don't forget to call them twice, for example:

    GC.Collect
    GC.WaitForPendingFinalizers
    GC.Collect
    GC.WaitForPendingFinalizers
    As for me, I prefer using the ReleaseComObject methods inplace.

    Sunday, January 25, 2015 4:16 PM
  • That is for Outlook 2007

    I should have added -  For Outlook 2103

    Sunday, January 25, 2015 4:47 PM
  • That is for all Outlook versions since 2000. It doesn't matter what Outlook version you are using at the moment. The rule depends on the COM / OLE Automation technology which is not changed.
    Sunday, January 25, 2015 5:31 PM
  • Its true that COM rules have not changed

    However there is nothing to stop Microsoft making a version of .Net which can automatically release COM references

    And since the Documentation "Systematically Releasing Objects" for Outlook 2103 no longer mentions using ReleaseComObject it is a reasonable assumption that it is NOT necessary to "manually" release COM references

     So i don't have a definitive answer as yet.

    Sunday, January 25, 2015 5:48 PM
  • Nothing has changed. If you don't believe me, try to reproduce any of the well-known issues related to not-releasing underlying COM objects.
    Sunday, January 25, 2015 5:53 PM
  • There is no definite answer because it all depends on what your code does. If all you do is display a message box on Outlook startup, you have nothing to worry about. If on the other hand you loop through a few thousand messages, you'd better make sure you are not using multiple dot notation and everything is released immediately using ReleaseComObject.

    Keep in mind that .Net *will* eventually release all COM objects (so there are no leaks), the question is whether that "eventually" will be soon enough to make Outlook and the underlying MAPI provider happy - e.g. online Exchange store will throw a tantrum if you have 250 messages open.


    Dmitry Streblechenko (MVP)
    http://www.dimastr.com/redemption
    Redemption - what the Outlook
    Object Model should have been
    Version 5.5 is now available!

    Sunday, January 25, 2015 6:44 PM
  • Yet another fact that nothing has changed so far.
    Sunday, January 25, 2015 7:06 PM
  • Hi Dmitry

    "Keep in mind that .Net *will* eventually release all COM objects (so there are no leaks)"

    Release ( = decrement COM count) or garbage collect ?

    I don't do any foreach or other C# iterations or looping

    However I do have a LINQ .Where(...) statement - which I assume iterates - how would one handle this?

     

    Monday, January 26, 2015 9:24 AM
  • LINQ statements don't decrement COM reference counters.

    The garbage collector decrements reference counters when the heap is swiped.

    Monday, January 26, 2015 12:08 PM
  • "Release" as in "undo all calls to AddRef by calling Release".

    It is a pretty bad idea to use LINQ with Outlook collections - it is as inefficient as explicitly loping through the collection items, and you don't get to say when items are released - use the functions that deal with searching, e.g. Items.Find/FindNext/Restrict whenever possible.


    Dmitry Streblechenko (MVP)
    http://www.dimastr.com/redemption
    Redemption - what the Outlook
    Object Model should have been
    Version 5.5 is now available!

    Monday, January 26, 2015 1:17 PM
  • I understand your point

    Monday, January 26, 2015 4:23 PM
  • Hi Eugene, can you give me some light in what are those well-known issue when you not release underlying COM object.. I have an issue, with an outlook add-in, I save an mail item in the disk, then I open and press "Replay all" button, the close the windows mail.

    After that, I try to delete the saved mail and windows says can't delete because is in use, when I debug my code, I know one of the object is not release it, but... unfortunately the develop who do this add-in save all inspectorNewItem in a dictionary, like this:

     private void Inspectors_NewInspector(Inspector inspector)
            {
                MailItem mailItem = null;
                try
                {
                    mailItem = inspector.CurrentItem as MailItem;
                    if (mailItem != null)
                    {
                        ((ItemEvents_10_Event)mailItem).Close += Inspectors_CloseInspector;
    
                        ComposeManager composeManager = new ComposeManager(mailItem);
                        _mailItemToManagerMap.Add(mailItem, composeManager);
                        mailItem.BeforeAttachmentAdd += composeManager.AttachmentAdded;
                    }
                }
                catch (Exception ex)
                {
                    Logging.LogException(ex, Logging.GetModuleAndMethodName());
                }
            }

    as you can see we not have a release object in the finally, well the issue occurs,  because they assume they can release all object in the close event, like this:

     void Inspectors_CloseInspector(ref bool cancel)
            {
                MailItem mailItem = null;
    
                try
                {
                    mailItem = Application.ActiveInspector().CurrentItem as MailItem;
    
                    if (mailItem != null && _mailItemToManagerMap.ContainsKey(mailItem))
                    {
                        ComposeManager composeManager = _mailItemToManagerMap[mailItem];
    
                        composeManager.CancelAllUploads();
                        composeManager.CloseUploadDialog();
    
                        mailItem.BeforeAttachmentAdd -= composeManager.AttachmentAdded;
    
                        _mailItemToManagerMap.Remove(mailItem);
                    }
                }
                catch (Exception ex)
                {
                    Logging.LogException(ex, Logging.GetModuleAndMethodName());
                }
                finally
                {
                    if (mailItem != null)
                    {
                        // We need to release mailobject twice here
                        // One reference is never released from Inspectors_NewInspector call
                        // and other from  Application.ActiveInspector().CurrentItem in this method
                        Marshal.ReleaseComObject(mailItem);
                        Marshal.ReleaseComObject(mailItem);
                        mailItem = null;
                    }
                }
            }

    If I loop on _mailItemToManagerMap and release all item there the issue is fix, but as you can see they assume the COMM object is unRelease it in the collection to use it in other part of the system

    But in some way, the first item add it to the collection is never found in the collection and never release it... not sure why...

    Thursday, September 20, 2018 8:43 PM