Controlling Outlook 2007 with C# and Visual Studio Tools for Office

This post describes how to use C# and the Visual Studio Tools for Office to program Outlook 2007. The focus is on showing the preliminary steps necessary to programmatically run a set of Outlook rules.

Background

Before coming to work at Microsoft in July 2006, I had only a slight acquaintance with Outlook. Now, of course, Outlook plays a huge role in my life.

If I'm going to live this intimately with Outlook, then I need better control over our relationship. To help get a handle on a situation that is rapidly spiraling out of control, I have decided to learn how to write code to modify Outlook's behavior.

When I first started using Outlook, I quickly learned to write rules that process messages in my InBox. These rules are great, but I want to have more control over when and how they run. The basic menu commands for rules in Outlook are helpful, but they fall short of what I need.

First Run: Try VBA

I used to write Delphi applications that controlled Word and Excel, so I know a little about VBA. With this knowledge as a starting point, I decided to look into writing some VBA code to try to tame the beast that my mailbox had become.

After a few searches on the Internet, I was able to use some hints from Sue Mosher to cobble together the VBA code shown in Listing 1. The simple logic allows me to programmatically run a set of Outlook Rules.

Listing One: Code to run rules inside of Outlook.

    1:  Public Sub RunRule()
    2:      Dim colRules As Outlook.Rules
    3:      Dim myRule As Outlook.rule
    4:      Dim myNames() As Variant
    5:      Dim name As Variant
    6:          
    7:      myNames = Array("Rule One", "Rule Two")
    8:      
    9:      Set colRules = Application.Session.DefaultStore.GetRules()
   10:      
   11:      For Each name In myNames()
   12:          For Each myRule In colRules
   13:              ' If its a rule we want to run
   14:              If myRule.name = name Then
   15:                  ' Then run it
   16:                  myRule.Execute ShowProgress:=True
   17:              End If
   18:          Next
   19:      Next
   20:  End Sub

The code here is fairly straightforward. Lines 2 through 5 provide a few basic declarations. Line 7 declares an array containing the names of from 1 to n rules. In line 9 there is a call to Outlook to get a list of all the rules I have written. Lines 11 through 18 contain two nested loops that execute the rules; the code ensures that only rules that are part of my array are run. The end result is that I can group together sets of rules and run them easily at a specified time.

This was close to what I wanted. My VB code provides a simple way to get a bit more control over Outlook. Nevertheless, I wasn't completely happy. My core problem was that my code was in VB and I'm just not a VB kind of guy. I'm the C# Community guy, and that means I have an innate desire to tap into the power of the C# language and the Visual Studio debugger.

The VSTO Rewrite

To help me port my code to C#, I downloaded and installed the Visual Studio Tools for Microsoft Office System Beta (VSTO). Bringing in a big gun like this to solve such a simple problem is probably overkill. However, my desire to translate my code to C# could act as forcing function that would inspire me to get up to speed on VSTO. The simple program I created would be starting point allowing me to gain the leverage necessary to tame the raging beast that is my mailbox.

Once the beta was installed, I went to the Visual Studio file menu and chose New | Project | Office | 2007 Add-ins | Outlook Add-in. A simple VSTO for office project was created for me automatically. Without any real effort on my part, I was more than half way to my goal.

I then right clicked on my project in the Solution Explorer and choose Add | New Item from the pop-up menu. Among the installed templates was one called Ribbon Support. I selected that item and clicked the Add button. New files called Ribbon.cs and Ribbon.xml were added to my project. I then uncommented the following boilerplate code which was found at the top of Ribbon.cs:

    1:   public partial class ThisAddIn
    2:      {
    3:          private MyRibbon ribbon;
    4:   
    5:          protected override object RequestService(Guid serviceGuid)
    6:          {
    7:              if (serviceGuid == typeof(Office.IRibbonExtensibility).GUID)
    8:              {
    9:                  if (ribbon == null)
   10:                      ribbon = new MyRibbon();
   11:                  return ribbon;
   12:              }
   13:   
   14:              return base.RequestService(serviceGuid);
   15:          }
   16:      } 

When I ran my project a new tab, shown in Figure 1, had been added to the Ribbon control at the top of many of the pages in Outlook. The page shown in Figure 1 is the one displayed when you create a new email message. The same tab appears in other pages, such as the one to create a new task, or a new calendar appointment. In Figure 1, you can see the other default tabs, called Message, Insert, Options, and Format Text. The last tab, called My Tab, was the one created by my VSTO application.

Figure 1: The new tab created in outlook had a single button in it called My Button.

From VB to C#

The boilerplate code from the Ribbon template had also created a response method or event handler for the button that appears in the Ribbon tab. I deleted the default implementation for that method, and inserted the VB code from Listing 1. After a few minutes work, I translated the VB code to C#. The results can be seen in Listing 2.

Listing 2: A C# translation of the VB code that runs a predefined set of Outlook rules.

    1:  public void OnToggleButton1(Office.IRibbonControl control, bool isPressed)
    2:  {
    3:      object emptyParameter = System.Type.Missing;
    4:      object runVisible = true;
    5:      String[] myNames = new String[] {"Rule One", "Rule Two"};
    6:   
    7:      Outlook.Rules myRules = Globals.ThisAddIn.Application.Session.DefaultStore.GetRules();
    8:   
    9:      foreach (Outlook.Rule myRule in myRules)
   10:      {
   11:          foreach (string name in myNames)
   12:          {
   13:              // If its a rule we want to run
   14:              if (myRule.Name.Equals(name))
   15:              {                         
   16:                  // Then run it
   17:                  myRule.Execute(runVisible, emptyParameter, emptyParameter, emptyParameter);
   18:              }
   19:          }
   20:      }
   21:  }

The code is more or less identical to the code in VB example, except that it is mysteriously better because it is written in C#.

The tricky part is in the call to myRule.Execute. In the VB example, the language allows us to leave off three of the four parameters. C# requires that the parameters be included. But what should I pass in for those parameters?

The best way to get help on the Execute method is to bring up the help inside the Outlook VBA editor. For instance, I could just put the cursor over the word Execute in my VB code and get help. There I learned that Execute takes the following parameters:

  • ShowProgress: Boolean - Show the progress bar
  • Folder: Custom Type - Represents an Outlook Folder
  • IncludeSubFolders: Boolean - Self explanatory.
  • OlRuleExecuteOptions: Custom Enumerated Type - Process all messages, only unread messages, or only messages that had already been read.

Unless you are working in VB, parameters like this can be a bit ungainly. This was a problem I remembered from my Delphi days. I can vaguely recalled the tricks we used to make this work back then. As a result, I knew what I had to do, but not how to do it.

Stumped, I wandered over to Eric Lippert's office, and he told me about something called System.Type.Missing. With that as a hint, I conducted a few more searches on the web, and came up with code found in line 3 of Listing 2. This code allows me to pass in a "null-like" parameter that the Outlook engine would regard as an "empty parameter" or as "missing parameter." Eric had warned me that I would probably need to pass it in as a ref parameter, but that turned out to no longer be necessary.

During my search on the web I also found the code shown on line 4 to declare the boolean first parameter to the Execute method. This parameter defines whether or not a dialog with a Progress Bar in it would appear when the rules were being run. By setting this to true, I can watch a dialog which records the progress of each rule that is run, as shown in Figure 2. In the background I can also watch the rule move my messages around inside of Outlook.

Figure 2: The dialog that appears when my VSTO program has kicked off a rule that I created for handling messages I get from Steve Teixeira.

While rules like the one show above are running, I have the full power of the Visual Studio debugger at my fingertips. I can set breakpoints in my C# code, and I can inspect variables and explore the stack. Now I can feel quite at home while exploring hermetic world of Outlook programming and its esoteric object model.

Summary

The solution I have come up with in this example is not perfect. I have, however, found a way to integrate new functionality into Outlook that gives me greater control over the application than I had in the past. Even when Visual Studio is not loaded, I find that my button and its related functionality is now integrated into Outlook. For me, this is a surprising and quite powerful bit of functionality that is in many ways more than I had originally set out to accomplish.

I am still only beginning to understand how this technology works. In future articles I will hopefully find time to unravel some of the mysterious that were left unexplained in this post. For now, however, I feel like I am well started on my quest to lean how to use C# and Visual Studio to program Outlook.

kick it on DotNetKicks.com