Miscellaneous Debris

Avner Kashtan's Frustrations and Exultations

VSTO for Outlook 2007 - Building the Add-in (part 2)

Writing the Outlook add-in described in my previous post was composed of the following steps:

1) Creating the project

Ah, the wonders of VSTO. Saving us all the unnecessary hassle of adding COM references, implementing interfaces and working too hard. After installing VSTO 2005 SE we can create a new Outlook 2007 Add-in project that creates both the add-in project and the MSI Setup project that can be used to install it.

2) Building the Context Menu

To add my own menu items to each item's Context Menu, I use the new ItemContextMenuDisplay event that is exposed by the Outlook 2007 object model. In the pre-supplied Startup method I simply add the following event registration:

this.Application.ItemContextMenuDisplay += new Microsoft.Office.Interop.Outlook.ApplicationEvents_11_ItemContextMenuDisplayEventHandler(Application_ItemContextMenuDisplay);

In my event handler method I start by fetching the current Outlook folder:

MAPIFolder currentFolder = Application.ActiveExplorer().CurrentFolder;

and creating the root of the popup menu tree:

// Create a new button in the commandBar. The command bar itself is received as a parameter to the event
// handler  method.

CommandBarPopup rootButton = (CommandBarPopup)commandBar.Controls.Add
(Office.MsoControlType.msoControlPopup, Type.Missing, "MoveToFolder", commandBar.Controls.Count + 1, Type.Missing);
 

rootButton.BeginGroup = true;
rootButton.Tag = "MoveToSubFolder";
rootButton.Caption = "Move To...";
rootButton.Visible = true;

Now I recursively go over the current folder and its subfolders, adding new buttons under the rootButton as I go along.

Things to note:

  •  I create a different menu control depending on whether I'm creating a leaf node or a node that has children - one is a Button, the other a Popup. For some reason I couldn't create a PopupButton, maybe it's a control that's reserved for a toolbar and can't be used in a ContextMenu. This means that a node with children cannot be clicked, and we can't copy items to it. There may be a workaround to this using the OnAction property rather than the Click event, but I haven't gotten around to checking it out. I'd appreciate feedback.
  • I'm saving the FullFolderPath in each node's Tag object. This is so I can access it later when I'm moving the items. I originally wanted to save the EntryID + Store's EntryID in the Tag for a totally unique identifier, but for some reason Outlook crashed whenever I tried to save that in it. I have no idea why.
  • Note the recursion - each folder is addings its leaf-nodes as buttons, and sending each non-leaf children to another call to AddFolder.
private void AddFolder(MAPIFolder folder, CommandBarPopup menu)
{
      foreach (MAPIFolder subFolder in folder.Folders)
      {
MsoControlType linkType = (subFolder.Folders.Count > 0) ? 
               MsoControlType
.msoControlPopup : MsoControlType.msoControlButton;

     
CommandBarControl folderLink = menu.Controls.Add
(linkType, Type.Missing, subFolder.Name, 1, Type.Missing);
 
            folderLink.Tag = subFolder.FullFolderPath; 
            folderLink.Caption = subFolder.Name;

 
            if (linkType == MsoControlType.msoControlPopup)
            {
AddFolder (subFolder, folderLink as CommandBarPopup);
            }
            else
            {
(folderLink as CommandBarButton).Click += new
                             _CommandBarButtonEvents_ClickEventHandler
(
            MoveToFolder);
            }             
      }
}

3) Moving the items

As we could see above, each leaf node's Click event is handled by the MoveToFolder method:

Again, noteworthies:

  • The FullFolderPath we saved earlier is translated to a MAPIFolder object using the GetFolderFromPath function, a glaring omission in the Outlook object model that we have to rectify by hand. I'll post the full (and simply) code for this in a different post. It's included in the attached project. 
  • Note that we're casting the items in the current selection to MailItem objects, meaning standard outlook email messages. We're ignoring non-MailItems in this code. Since the COM object model doesn't give us any shared base-classes or interfaces for other entities, we need to write some ugly code to handle PostItems, AppointmentItems and so forth.

 

 
void MoveToFolder(CommandBarButton Ctrl, ref bool CancelDefault)
{
          MAPIFolder destFolder = GetFolderFromPath(Ctrl.Tag);
 
          foreach (object item in Application.ActiveExplorer().Selection)
          {
                    MailItem mi = item as MailItem;
                    if (mi != null)
                    {
                             mi.Move(destFolder);
           }
                    else
                    {       
                             // Can only copy MailItems;
                    }
          }
}

4) Profit!

Well, maybe not. But this is the entire extent of the code needed to implement this add-in. I've attached the whole project (including the MSI project) so you can install it at home, or use the code as a base for whatever add-in you feel like writing. The pre-built MSI is in the MoveToFolderAddInSetup\Debug folder. Enjoy!

Comments

... said:

Du musst ein Fachmann sein - wirklich guter Aufstellungsort, den du hast!

# March 14, 2007 4:28 PM

automotivespikedcarpetrunner said:

<a href="httpwwwgmauvzrdcnpage81html">1985suzukigs700</a> 1985suzukigs700,<a href="httpwwwuiidlecxcnpage8html">datarecoveryservicesecurity</a> datarecoveryservicesecurity,<a href="httpwwwgmauvzrdcnpage85html">mistletoekissdogvideo</a> mistletoekissdogvideo,<a href="httpwwwgmauvzrdcnpage87html">allhomebuildersindallasfortworth</a> allhomebuildersindallasfortworth,<a href="httpwwwuiidlecxcnpage4html">finddirectvdealers</a> finddirectvdealers,<a href="httpwwwuiidlecxcnindexhtml">howmuchsalttofloatapotato</a> howmuchsalttofloatapotato,<a href="httpwwwgmauvzrdcnpage95html">e-mailhotmailaddress250mbinbox</a> e-mailhotmailaddress250mbinbox,<a href="httpwwwuiidlecxcnpage4html">hddirectvmpg4</a> hddirectvmpg4,<a href="httpwwwuiidlecxcnpage8html">windowsundeletesecurity</a> windowsundeletesecurity,<a href="httpwwwgmauvzrdcnpage97html">suzukib-ing</a> suzukib-ing,

# August 2, 2007 8:00 AM

Joe said:

Hello,

can you also imitate the CTRL+SHIFT+V also?

Thanks.

joe

# August 8, 2007 1:03 PM

Kyle said:

Great post! I am attempting to build an add-in where the buttons will be created dynamically similar to what you have done. I noticed though that my ClickEventHandler will only fire once.

I am developing the add-in for Outlook 2003. Does that make a difference? Thanks.

# September 14, 2007 1:35 PM

Koen said:

I tried this, but i am not getting anything under the rootbutton.

# January 17, 2008 10:17 AM

Andrei Smolin said:

> For some reason I couldn't create a PopupButton

Only the following control types are available for the CommandBarControls.Add method: msoControlButton, msoControlEdit, msoControlDropdown, msoControlComboBox, or msoControlPopup. Alas, that's a non-rectifyable restriction of the Office model.

> I originally wanted to save the EntryID + Store's EntryID but for some reason Outlook crashed

It looks like a bug. I didn't find a KB article, though. I tested saving a string in Tag on Outlook (=Office) 2003 and 2007. I found out the limit: it's 255 characters :) When exceeding this limit I get an ArgumentException: Value does not fall within the expected range. I also reproduced this in VBA: Invalid procedure call or argument.

> we need to write some ugly code to handle PostItems, AppointmentItems and so forth

We can use the late binding.

# April 16, 2008 9:18 AM

Mathias Pain said:

Hi there, great article/example.

Almost the thing I was searching for.

Is there a possibility to use an specific PublicDirectory instead of the currentFolder?

I'm very new to this topic (actually started today) and I would need this really fast :/

regards, Mathias Pain

# June 11, 2008 5:24 AM

Mathias Pain said:

Hi just encountered another problem with this code. Just found out that the Click-Eventhandler gets called multiple times after building the Menutree. This happens because the menubutton gets assigned the click handler over and over again.

could someone help me with this?

I changed the code from moving the mail to copying it and now I get multiple copies because of the multiple-invoked eventhandler.

# June 11, 2008 6:38 AM

Matthew Butler said:

Hiya,

Ive been fishing around for the last couple days trying to find a solution to the same problem Mathias. Seems even the MSDN example (can't find the link right now), its the VSTO_Rules one suffers from the same problem. If anybody knows how to solve this, please help :(

To summarise, the button event handler is being added every time you add the button to the context menu.

I have tried using a boolean to check whether the event handler has been added, but I have observed that after a short period of time, the event handler will be deregistered anyway and then I am left with no event handler for the button at all.

# June 20, 2008 8:42 AM

Matthew Butler said:

Update: A somewhat temporary solution is to de-register the event handler in the handler itself (It will then be re-added when the menutree is created). Seems to work so far.

# June 20, 2008 8:50 AM

Sue Mosher said:

For anyone wondering how to deal with the issue of multiple event handlers, take a look at the ContextMenuClose event, which will fire when the context menu disappears. Use that event to unsubscribe from the event handler, remove the button from the menu, and release any Outlook objects you've instantiated (including CommandBar controls).

Also, note that the code in the MoveToFolder procedure acts on the ActiveExplorer.Selection collection, which is not the same thing as the item(s) that the context menu is firing for. That item or those items are contained in the Selection collection passed to the ItemContextMenuDisplay event. It is possible, for example, for the user to select 10 items in the Explorer window, but then right-click on a single item that is not in that selection. The Selection from the ItemContextMenuDisplay event handler would correctly include just that one item, not the 10 items.

# July 14, 2008 6:40 PM

Joao said:

Hi, can you tell me how to build an MSI with the Add-IN?

Thanks

# August 15, 2008 3:17 PM

Rudolph Scott said:

Hi. I have the same problem as Mathias. Can someone tell me how to de-register the event handler in the handler itself, i.e. in VB code please. Thank You.

# November 26, 2008 5:56 AM

Natalias said:

With Christmas all of you!

# January 11, 2009 4:50 AM

ipad app for printing said:

The man who has made up his mind to win will never say "impossible ".

-----------------------------------

# December 18, 2010 1:05 PM

ipad reviews said:

-----------------------------------------------------------

"In browsing for web sites associated to net internet hosting and particularly comparison internet hosting linux strategy web, your website came up."

# January 3, 2011 7:14 AM

anti virus software reviews said:

"Hi. this can be kind of an -unconventional- question , but have other site visitors asked you how get the menu bar to look like you have obtained it? I also have a weblog and am  really searching to alter close to the theme, nonetheless am terrified to demise to mess with it for anxiety of the lookup engines punishing me. I am incredibly new to all of this  ...so i am just not optimistic exactly tips on how to attempt to to it all yet. I am going to just maintain working on it a single working day at a time."

--------------------------------------------------------------------  

Film and Visual Studies

# January 17, 2011 6:17 AM

insignia tv reviews said:

"Congratulations on getting one of the most sophisticated blogs Ive appear throughout in some time!  Its just incredible how considerably you can take away from  some thing merely simply because of how visually gorgeous it can be.  Youve put with each other a excellent blog area --great graphics, movies, layout.  This is definitely a must-see  weblog!"

--------------------------------------------------------------------    

Human Evolutionary Biology

# March 12, 2011 9:51 PM

Marcos Schelling said:

I do not even comprehend how I stopped up ideal here, having said that I thought this put up was good. I don't recognize who you might be but surely you're going to a renowned blogger inside the event you aren't already. Cheers!

# July 1, 2011 3:08 AM

Ashlee Truver said:

Couldn't be written any better. Reading this post reminds me of my old room mate! He always kept talking about this. I will forward this write-up to him. Pretty positive he will have a good read. Thanks for sharing!

# July 5, 2011 6:50 AM

rtyecript said:

I really liked the article, and the very cool blog

# August 21, 2011 9:59 PM

clomid acheter said:

This artists is of are sign, body with that. Of the Patients are and medicines.They one. It Eliminate in the the ancient these to prescribe many.

# September 6, 2011 8:12 PM

facebook said:

I don't disagree with this blog

# October 4, 2011 6:20 AM

news said:

That was a truly good article

# October 4, 2011 8:13 AM

ثبت دامنه said:

Extremely well executed blog post!!

# November 12, 2011 9:28 AM

Car DVD Player said:

This surely makes perfect sense to me!!!

# December 4, 2011 11:14 PM

judi bola said:

I could not think you are more right!!

# December 21, 2011 5:13 PM

Foro XXX, Foro Descarga. Foro, Foro Download said:

You couldn't be more factual!!

# December 23, 2011 1:16 PM

ibcbet said:

Remarkably well executed post...

# January 6, 2012 6:34 AM

amateure said:

That was very academic blog post..

# January 6, 2012 8:48 AM

consulta tarotista said:

This surely makes perfect sense to me.

# January 19, 2012 3:13 AM

Power Shovel said:

Could be this blogs best blog on the web.

# January 23, 2012 12:44 AM

backlink said:

That is very illuminating blog post!!!

# January 25, 2012 9:47 PM

ELECTRICAL TAPE - ADHESIVE TAPE said:

Thankfully some bloggers can still write. Thanks for this blog..

# January 27, 2012 5:32 AM

snel geld lenen zonder bkr toetsing said:

I don't disagree with this article...

# January 29, 2012 1:50 AM

reputation manager said:

You could not be more right on.

# January 31, 2012 4:11 AM

oliva cigars said:

All around well thought out piece...

# February 2, 2012 12:47 AM

leugens said:

Youre unquestionably correct on this piece..

# February 4, 2012 2:46 AM

The Estore has major manufacturers for you. (Acer, LG, Sony) said:

I fully agree completely!!

# March 7, 2012 3:48 AM

Seminar Geschäftsführer said:

Some enlightening blog!!

# March 8, 2012 2:56 AM

anvelope said:

Strikingly well executed post..

# March 9, 2012 11:41 AM

Gila Bola said:

You couldnt be more on the money..

# March 14, 2012 10:21 AM

edu links said:

Thankfully some bloggers can write. Thanks for this read...

# March 16, 2012 4:20 AM

myed.com said:

This makes great sense to me!

# March 20, 2012 8:53 AM

chaudesuperbe said:

You're quite correct with this piece...

# March 29, 2012 9:46 AM

calvin klein underwear said:

I dont disagree with this post...

# March 30, 2012 2:47 AM

Sydney Airport limousines said:

Thank god some bloggers can write. Thanks for this post!

# March 30, 2012 6:12 AM

Sydney Airport Limousines said:

You couldnt be more on the money!!

# March 31, 2012 5:14 AM

Christmas stockings said:

I couldnt agree with you more!!

# April 14, 2012 3:09 AM

agen bola betme88 said:

nice article dude, thanks for sharing ^^

# May 18, 2012 3:48 AM

buy edu backlinks said:

Hi there, I thought this is probably a good place to touch base and let you know, as soon as I attempt to view your RSS I get a error: “XML parsing

failed” (I use Opera)? If its not something on my end then I hope that you can fix it: I would love to sign up to your rss to Google Newsreader.

Looking forward to hopefully doing so soon, Cheers, Juliet Birkner in Tashkent

# July 28, 2012 11:15 AM

Torres said:

Hello colleagues, how is everything, and what you wish for to say

about this piece of writing, in my view its really awesome in support of me.

# January 29, 2013 7:15 AM