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.
{
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!
51 Comments
Comments have been disabled for this content.
... said
Du musst ein Fachmann sein - wirklich guter Aufstellungsort, den du hast!
automotivespikedcarpetrunner said
1985suzukigs700 1985suzukigs700,datarecoveryservicesecurity datarecoveryservicesecurity,mistletoekissdogvideo mistletoekissdogvideo,allhomebuildersindallasfortworth allhomebuildersindallasfortworth,finddirectvdealers finddirectvdealers,howmuchsalttofloatapotato howmuchsalttofloatapotato,e-mailhotmailaddress250mbinbox e-mailhotmailaddress250mbinbox,hddirectvmpg4 hddirectvmpg4,windowsundeletesecurity windowsundeletesecurity,suzukib-ing suzukib-ing,
Joe said
Hello, can you also imitate the CTRL+SHIFT+V also? Thanks. joe
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.
Koen said
I tried this, but i am not getting anything under the rootbutton.
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.
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
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.
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.
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.
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.
Joao said
Hi, can you tell me how to build an MSI with the Add-IN? Thanks
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.
Natalias said
With Christmas all of you!
ipad app for printingDA said
The man who has made up his mind to win will never say "impossible ". -----------------------------------
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."
anti virus software reviewsDA 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
insignia tv reviewsDA 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
Marcos SchellingDA 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!
Ashlee TruverDA 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!
rtyecript said
I really liked the article, and the very cool blog
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.
facebook said
I don't disagree with this blog
news said
That was a truly good article
ثبت دامنه said
Extremely well executed blog post!!
Car DVD Player said
This surely makes perfect sense to me!!!
judi bola said
I could not think you are more right!!
Foro XXX, Foro Descarga. Foro, Foro Download said
You couldn't be more factual!!
ibcbet said
Remarkably well executed post...
amateure said
That was very academic blog post..
consulta tarotista said
This surely makes perfect sense to me.
Power Shovel said
Could be this blogs best blog on the web.
backlink said
That is very illuminating blog post!!!
ELECTRICAL TAPE - ADHESIVE TAPE said
Thankfully some bloggers can still write. Thanks for this blog..
reputation manager said
You could not be more right on.
oliva cigars said
All around well thought out piece...
leugens said
Youre unquestionably correct on this piece..
The Estore has major manufacturers for you. (Acer, LG, Sony) said
I fully agree completely!!
Seminar Geschäftsführer said
Some enlightening blog!!
anvelope said
Strikingly well executed post..
Gila Bola said
You couldnt be more on the money..
edu links said
Thankfully some bloggers can write. Thanks for this read...
myed.com said
This makes great sense to me!
chaudesuperbe said
You're quite correct with this piece...
calvin klein underwear said
I dont disagree with this post...
Sydney Airport limousines said
Thank god some bloggers can write. Thanks for this post!
Sydney Airport Limousines said
You couldnt be more on the money!!
Christmas stockings said
I couldnt agree with you more!!
agen bola betme88 said
nice article dude, thanks for sharing ^^
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
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.