A context menu only for mail items within outlook

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

A context menu only for mail items within outlook
Follow-up on earlier discussion on context menu's  
Dennis Smit




Posts: 9
Joined: 2010-05-13
Hi!

As a follow-up on: http://www.add-in-express.com/forum/read.php?FID=5&TID=7266&MID=36199#message36199

I wanted to provide the full solution (from my point of view) with the correct releasing of the COM object, Eugene can you verify that this is right?


 private void adxContextMenu_BeforeAddControls(object sender, EventArgs e)
        {
            if (OutlookApp.ActiveExplorer().Selection.Count > 0)
            {
                Explorer explorer = null;
                MailItem item = null;
                
                try
                {
                     explorer = OutlookApp.ActiveExplorer() as Explorer;
                     item = explorer.Selection.Item(1) as MailItem;

                    if (item != null)
                    {
                        adxContextMenu.Controls[0].Visible = true;
                    }
                    else
                    {
                        adxContextMenu.Controls[0].Visible = false;
                    }
                }
                catch (System.Exception exp)
                { }
                finally
                {
                    Marshal.ReleaseComObject(item);
                    Marshal.ReleaseComObject(explorer);
                }
            }
            else
            {
                adxContextMenu.Controls[0].Visible = false;
            }
        }


If I understand correctly, every object that is created through a call (method()) should
be released, however objects that got accessed through properties are released through
their parent?

Thanks in advance, and hopefully the code snippit is helpful to others.

Regards,
Dennis
Posted 11 Jul, 2010 19:49:46 Top
Andrei Smolin


Add-in Express team


Posts: 14115
Joined: 2006-05-11
Hi Dennis,

Dennis Smit wrote:
if (OutlookApp.ActiveExplorer().Selection.Count > 0)


This code line generates two COM objects that you don't release: OutlookApp.ActiveExplorer() and Explorer.Selection. Also note that Explorer.Selection generates an exception when the current folder is a top-level one, Personal Folders for instance.

Also, you don't release Selection in item = explorer.Selection.Item(1) as MailItem.

Regards from Belarus (GMT+2),

Andrei Smolin
Add-in Express Team Leader
Posted 12 Jul, 2010 03:34:31 Top
Dennis Smit




Posts: 9
Joined: 2010-05-13
retry ;-), this is how it should be done? Should I detect when a toplevel folder is selected or let the catch handle it?

Thanks for your patience! As last question, is there a situation where I should NOT release
a COM object created through the API?


  private void adxContextMenu_BeforeAddControls(object sender, EventArgs e)
        {
            Explorer explorer = null;
            Selection selection = null;
            MailItem item = null;

            try
            {
                explorer = OutlookApp.ActiveExplorer() as Explorer;
                selection = explorer.Selection;
                if (selection.Count > 0)
                {
                    item = selection.Item(1) as MailItem;

                    if (item != null)
                    {
                        adxContextMenu.Controls[0].Visible = true;
                    }
                    else
                    {
                        adxContextMenu.Controls[0].Visible = false;
                    }
                }
                else
                {
                    adxContextMenu.Controls[0].Visible = false;
                }
            }
            catch (System.Exception exp)
            { }
            finally
            {
                Marshal.ReleaseComObject(item);
                Marshal.ReleaseComObject(selection);
                Marshal.ReleaseComObject(explorer);
            }
        }
Posted 12 Jul, 2010 08:18:37 Top
Andrei Smolin


Add-in Express team


Posts: 14115
Joined: 2006-05-11
Hi Dennis,

Dennis Smit wrote:
this is how it should be done?


MailItem item = null; 
...
item = selection.Item(1) as MailItem; 


In the case the item is a task, contact, etc, IOW not a mail item, your code will create a corresponding COM object but the cast will set item to null and you will not be able to release the COM object.

object item = null;
...
item = selection.Item(1);
if (item is Outlook.MailItem)
{
   MailItem mail = item as MailItem;
   ...
}
if (item != null) Marshal.ReleaseComObject(item);


Note that Marshal.ReleaseComObject(v) will fire an exception if v is null.

Regards from Belarus (GMT+2),

Andrei Smolin
Add-in Express Team Leader
Posted 12 Jul, 2010 08:54:57 Top
Dennis Smit




Posts: 9
Joined: 2010-05-13
Take 42:



   private void adxContextMenu_BeforeAddControls(object sender, EventArgs e)
        {
            Explorer explorer = null;
            Selection selection = null;
            object item = null;

            try
            {
                explorer = OutlookApp.ActiveExplorer() as Explorer;
                selection = explorer.Selection;
                if (selection.Count > 0)
                {
                    item = selection.Item(1);

                    if (item is MailItem)
                    {
                        adxContextMenu.Controls[0].Visible = true;
                    }
                    else
                    {
                        adxContextMenu.Controls[0].Visible = false;
                    }
                }
                else
                {
                    adxContextMenu.Controls[0].Visible = false;
                }
            }
            catch (System.Exception exp)
            { }
            finally
            {
                MarshalUtils.MaybeReleaseComObject(item);
                MarshalUtils.MaybeReleaseComObject(selection);
                MarshalUtils.MaybeReleaseComObject(explorer);
            }
        }


Is this the right implementation (hopefully useful for others as well)?

Also, any notes on when NOT to release a COM object?

Thanks in advance, and again thanks for your patience!

Regards,
Dennis
Posted 12 Jul, 2010 09:41:53 Top
Andrei Smolin


Add-in Express team


Posts: 14115
Joined: 2006-05-11
Hi Dennis,

If MarshalUtils.MaybeReleaseComObject() checks the argument and releases it if it isn't null, then it's okay.

Dennis Smit wrote:
Also, any notes on when NOT to release a COM object?


You must not release COM objects that Add-in Express passes to you in event parameters.

Regards from Belarus (GMT+2),

Andrei Smolin
Add-in Express Team Leader
Posted 12 Jul, 2010 09:57:09 Top
Dennis Smit




Posts: 9
Joined: 2010-05-13
Hi!

It does that, for completeness:

    public static class MarshalUtils
    {
        public static int MaybeReleaseComObject(object o)
        {
            if (o != null)
            {
                return Marshal.ReleaseComObject(o);
            }
            else
            {
                return -1;
            }
        }
    }


Also

                    if (item is MailItem)
                    {
                        adxContextMenu.Controls[0].Visible = true;
                    }
                    else
                    {
                        adxContextMenu.Controls[0].Visible = false;
                    }

can be reduced to:
                    adxContextMenu.Controls[0].Visible = item is MailItem;
Posted 12 Jul, 2010 10:43:33 Top
Andrei Smolin


Add-in Express team


Posts: 14115
Joined: 2006-05-11
:)

Regards from Belarus (GMT+2),

Andrei Smolin
Add-in Express Team Leader
Posted 13 Jul, 2010 02:46:38 Top