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!

Published Wednesday, January 03, 2007 3:00 PM by Avner Kashtan
Filed under: , , ,

Comments

# Miscellaneous Debris : VSTO for Outlook 2007 - New Features, More Fun (part 1)@ Wednesday, January 03, 2007 8:19 AM

PingBack from http://weblogs.asp.net/avnerk/archive/2007/01/03/vsto-for-outlook-2007-new-features-more-fun-part-1.aspx

Miscellaneous Debris : VSTO for Outlook 2007 - New Features, More Fun (part 1)

# re: VSTO for Outlook 2007 - Building the Add-in (part 2)@ Wednesday, March 14, 2007 4:28 PM

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

...

# re: VSTO for Outlook 2007 - Building the Add-in (part 2)@ Thursday, August 02, 2007 8:00 AM

<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,

automotivespikedcarpetrunner

# re: VSTO for Outlook 2007 - Building the Add-in (part 2)@ Wednesday, August 08, 2007 1:03 PM

Hello,

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

Thanks.

joe

Joe

# re: VSTO for Outlook 2007 - Building the Add-in (part 2)@ Friday, September 14, 2007 1:35 PM

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.

Kyle

# re: VSTO for Outlook 2007 - Building the Add-in (part 2)@ Thursday, January 17, 2008 10:17 AM

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

Koen

# re: VSTO for Outlook 2007 - Building the Add-in (part 2)@ Wednesday, April 16, 2008 9:18 AM

> 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.

Andrei Smolin

# re: VSTO for Outlook 2007 - Building the Add-in (part 2)@ Wednesday, June 11, 2008 5:24 AM

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

Mathias Pain

# re: VSTO for Outlook 2007 - Building the Add-in (part 2)@ Wednesday, June 11, 2008 6:38 AM

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.

Mathias Pain

# re: VSTO for Outlook 2007 - Building the Add-in (part 2)@ Friday, June 20, 2008 8:42 AM

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.

Matthew Butler

# re: VSTO for Outlook 2007 - Building the Add-in (part 2)@ Friday, June 20, 2008 8:50 AM

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.

Matthew Butler

# re: VSTO for Outlook 2007 - Building the Add-in (part 2)@ Monday, July 14, 2008 6:40 PM

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.

Sue Mosher

# re: VSTO for Outlook 2007 - Building the Add-in (part 2)@ Friday, August 15, 2008 3:17 PM

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

Thanks

Joao

Leave a Comment

(required) 
(required) 
(optional)
(required)