Advice on releasing objects

Add-in Express™ Support Service
That's what is more important than anything else

Advice on releasing objects
New to ADX, request input on releasing objects... 
Mark McCray




Posts: 17
Joined: 2010-04-15
Hi Everyone,

This is my first ADX add-in and I have a couple of simple questions. I have read the blogs and this is how I understand releasing should be handled. Could I get some comments on if this is correct?

I am targeting Outlook 2010 and newer only.

Here is the code:

        private string GetRecipientEmailAddresses(Outlook.MailItem mail, Outlook.OlMailRecipientType pType)
        {
            List<String> addresses = new List<string>();
            Outlook.Recipients recipients = null;
            Outlook.Recipient  recipient = null;
            Outlook.ExchangeUser user = null;

            try
            {
                recipients = mail.Recipients;
                for (int i = 1; i <= recipients.Count; i++)
                {
                    recipient = recipients[i];
                    if ((Outlook.OlMailRecipientType) recipient.Type == pType)
                    {
                        user = recipient.AddressEntry.GetExchangeUser();
                        if (user != null)
                        {
                            addresses.Add(FormatEmailAddress(user.Name, user.PrimarySmtpAddress));
                            Marshal.ReleaseComObject(user);
                        }
                        else
                        {
                            addresses.Add(FormatEmailAddress(recipient.Name, recipient.Address));
                        }
                    }
                    Marshal.ReleaseComObject(recipient);
                }
                Marshal.ReleaseComObject(recipients);
            }
            catch (Exception ex)
            {
                EventLog.WriteEntry("Application", "Coyote Analytics Office Addin:" + ex.Message, EventLogEntryType.Error);
            }
            finally
            {
                if (recipients != null) Marshal.ReleaseComObject(recipients);
                if (recipient != null) Marshal.ReleaseComObject(recipient);
                if (user != null) Marshal.ReleaseComObject(user);
            }

            return String.Join(";", addresses);
        }


I release the recipient within the for loop. Is that correct/necessary?

Even after releasing the recipient object, it is still "NOT NULL" when the finally block executes, which calls another release. This does not seem correct. Should I be setting the object to null after releasing it?

Thanks for the comments!

Mark
Posted 30 Jun, 2015 11:14:48 Top
nwein




Posts: 577
Joined: 2011-03-28
You should release your AddressEntry object as well (i.e. do not call recipient.AddressEntry.GetExchangeUser() but separate it to AddressEntry ae = recipient.AddressEntry; and then ae.GetExchangeUser() so you can release the ae object).
Other than that your code looks good. As for your question - you definitely need to release the recipient in the loop (the way you do), otherwise the COM object will not be released.
I know that the ADX people like to nullify any COM object when its use is done so you won't accidentally call it again, I personally don't do it as the finally block will handle any unreleased, last instances in case there was an error or anything of that sort.
Posted 30 Jun, 2015 11:51:54 Top
Mark McCray




Posts: 17
Joined: 2010-04-15
Thanks nwein,

If the object is released twice, do you know of any issues? Seems like it should just realize the count is zero and move on.

One other question. Notice the email item being passed in as a parameter. In C#, I don't think it is passed by reference, so I am wondering if that needs to be released as well?


I had already caught the address entry, but thank you for pointing it out.

Mark
Posted 30 Jun, 2015 12:27:51 Top
nwein




Posts: 577
Joined: 2011-03-28
Sorry, I usually declare the Marshaled object only in their own scope... in your case, yes, you'd need to set the recipient to null after releasing it.
As for the MailItem object, if you're not going to use it anymore (after calling GetRecipientEmailAddresses) then you should release it as well. I personally like to clean up objects where they are declared and not inside calling methods so that I know the status of every object, but it's up to you.
Posted 30 Jun, 2015 13:21:23 Top
Andrei Smolin


Add-in Express team


Posts: 18823
Joined: 2006-05-11
Hello Mark,

Thank you, Nir!

You release recipient correctly. You may want to nullify it as using a non-nullified object after you release it raises the "COM object that has been separated from its underlying RCW cannot be used" exception. Using a nullified object raises NullReferenceException so you'll be one step closer to locating of the issue.

And Nir is correct about AddressEntry.

As well as Nir, we follow this practice: the caller is responsible for releasing the COM object it creates. In your case the caller is the method invoking GetRecipientEmailAddresses().


Andrei Smolin
Add-in Express Team Leader
Posted 01 Jul, 2015 03:20:24 Top