I've finally finished my Form Region Sample for Outlook 2007 that was promised. I've been working on it in earnest for a couple weeks now in my spare time. I am now resisting the urge to continue tweaking it: it is time to lockdown and ship. The urge to tweak is there because this is something I'm actually going to use all of the time. Outlook 2007, you may have noticed, has a new folder for RSS feeds, so you can get your blogs right in Outlook. This is cool, but I wanted to change how the posts were displayed – they always excerpt them and then include a link to the full post. The link then opens IE in another window. I wanted to be able to see the full post in the Outlook view: perfect use for a FormRegion!

I've created a FormRegion that hosts the Windows WebBrowser Control, and automatically shows the link. For the purposes of the sample I decided to put it two places and do it two different ways. I show it as an "adjoining" reason in the Preview pane, and as a "separate" region in the Inspector "Reading" view. I'll leave it up to you to experiment with mixing and matching these views. I'll go into where these are specified when I talk about the FomrRegion manifest below.

Implementation

First, let's go through the implementation. We'll start with the ThisAddin class. If you created and Outlook addin in VSTO 2005, you'll notice that this is different. We called it ThisApplication in VSTO 2005 and it derived directly from Outlook.Application. In VSTO 2005 SE, we have restructured this so the ThisAddin class is separate from the Application. It still gives you strongly typed access to Outlook.Application, it just doesn't derive from it anymore. In my Channel9 interview, I discussed why we made this change. If you have any feedback on this change – good, bad or neutral – please send it along.

The important piece of code in the ThisAddin class is this:

//Override the RequestService call to handle

//requests for the FormRegion service

protected override object RequestService(Guid serviceGuid)

{

if (serviceGuid == typeof(Outlook._FormRegionStartup).GUID)

{

if (this.formRegionManager == null)

this.formRegionManager = new RSSMessages.Regions.FormRegionManager();

return this.formRegionManager;

}

return base.RequestService(serviceGuid);

}

ThisAddin provides a new overridable function that we can be used to provide "services" to Office. If you add a ribbon to the project, you will see a similar piece of code for hooking it up. Office queries VSTO addins for various services (ribbons and FormRegions for now, there are others coming). We worked with the Office team to make this mechanism extensible, so that we could add more integrated support for the important services – you won't have to write this code in VSTO Orcas because we're providing a designer – and Office can add services over time and you can have access to them without VSTO having to change.

Anyway, Office requests the services by their COM guid. In this case it is the guid of the _FormRegionStatup interface. The FormRegionManager class in the project provides the implementation of _FormRegionStartup. Let's look at that next. These are the two methods on _FormRegionStartup in Outlook 2007 Beta2 TR. I make that distinction because this interface has changed since then. I'll discuss those changes – and update this sample – in a future post once they ship. Suffice it to say the changes will make some of the difficulties I discuss below go away. They are a good thing.

#region _FormRegionStartup Members

public void BeforeFormRegionShow(FormRegion formRegion)

{

RegionInstance ri = new RegionInstance(formRegion);

ri.OnFormRegionClose += new FormRegionCloseHandler(ri_OnFormRegionClose);

this.regionInstances.Add(formRegion, ri);

}

public object GetFormRegionStorage(string FormRegionName, object Item, int LCID, OlFormRegionMode FormRegionMode, OlFormRegionSize FormRegionSize)

{

if (FormRegionName == "TQForms.RSSFormRegion" || FormRegionName == "TQForms.PreviewRSSFormRegion")

{

return RSSMessages.Properties.Resources.Rss_Form_Region;

}

return null;

}

#endregion

The first method that gets called is GetFormRegionStorage. The FormRegionName parameter corresponds with the name in the form region manifest file, I'll get to that below. It returns the byte array that is the .ofs file you get from outlook. I'll talk about that below, too. Suffice it to say you simply add the ofs file to your project as a File resource and it is a simple line of code to return it as above. Then you get called on BeforFormRegionShow and get passed the instance of Outlook's FormRegion object. This gets called for each instance of the form region that is visible, and there can be any number visible at any time. So I created a separate class to represent each instance of a form region, called RegionInstance. It holds on to Outlook's FormRegion object and pulls all of the controls on the form out of that. See the function InitItems in RegionInstance.cs to see how this is done.

And that's about it for the implemetation: you hook up to events on the controls the way you would on any control and make them work the way you want. There are some interesting details about what I had to do to get the Icon for View in Browser to show up in the Ribbon, though. I'll cover those when I talk about the manifest below.

Creating a Form Region

Of course, to show a form region you have to create one, this is the .ofs file I alluded to above. The way you create one is to go into Outlook, then go to Tools…Forms…Design a Form. You'll get a dialog to choose which form you want to design – I chose RSS Article for this sample. Then you are presented with an Explorer window with the default view for that form and a bunch of tabs. From there you choose Form Region … New Form Region from the ribbon. It will add a new, blank tab and pop up a tool window with fields. You can drag and drop fields from there, and these are automatically hooked up with the outlook fields for this item. For instance the Subject and RSS Feed boxes in my form are done this way – no coding necessary. You can also show the standard Control Toolbox from the right-click menu on the form and add other controls – like the web browser control and progress bar control that I used – to the tool box and use them as well. When you have the form the way you want it, go back to the Form Region button on the Ribbon and select Save Form Region. You'll get the standard Save dialog and this will save your .ofs file. Then just copy the .ofs file to your project and add it to your resources.

You can also open up my .ofs file in the designer. Just go to the Form Region button on the designer and select Open Form Region. You'll see how my form regions was designed.

Form Region Manifest

In order for the Form Region to show up in Outlook at runtime, it must be described in a manifest and this manifest must be registered. The manifest, as you might imagine, is an XML file with a particular schema. Here is an example from my project:

<?xml version="1.0" encoding="utf-8"?>

<FormRegion xmlns="http://schemas.microsoft.com/office/outlook/12/formregion.xsd">

<name>TQForms.RSSFormRegion</name>

<title>View In Browser</title>

<formRegionType>separate</formRegionType>

<showInspectorCompose>false</showInspectorCompose>

<showInspectorRead>true</showInspectorRead>

<showReadingPane>false</showReadingPane>

<addin>RSSMessages</addin>

<version>1.0</version>

<icons>

<page>..\bin\debug\rssmessages.dll,101</page>

</icons>

</FormRegion>

As noted above, the Name element corresponds to what gets passed in to GetFormRegionStorage. The title is what shows up in the Ribbon (in this case) as the visible name. This particular manifest specifies the formRegionType as "separate" meaning it has its own separate window. The other manifest in the project specifies "adjoining" which means it shares the window. The next three elements declare where the form region will be shown. In this case it shown in the reading Inspector, but not the reading pane in the explorer. RSS Articles don't have a Composing inspector, but it they did, this would be false as well. The addin element corresponds to the name of the addin to call when looking for the FormRegionStorage and the code.

I noted above that there was some weirdness with the icon. The good news is that this weirdness goes away when Office ships, but in interest of full disclosure, I'll tell you what I had to do to make it work in this sample. As you can guess from what it says here, the page icon is a resource in my dll. But in this case it *MUST* be "win32resource" not a managed resource. There is no simple way to add a win32resource to a dll in Visual Studio. As you can see I created a simple resource script – res.rc – in my project. I added a custom pre-build step to compile that rc file into a .res file. So far so good. But it turns out to get the res file linked into the dll, I had to manually edit the .csproj file of the project. Open up the .csproj file in notepad and look for the <Win32Resource> element and you'll see what I did. It turns out there is no way that I could find to get VS to add this element, but it is honored by msbuild and passes it on to the compiler as a /win32resource directive. Again, though, the requirement to do this will be going away soon. Stay tuned for further updates.

So, we have a Form Region manifest now, how do you register it? You associate it with a "Message class" – in this case IPM.Post.RSS – and add the path to the manifest as a named value under that key under FormRegions in the registry:

HKEY_CURRENT_USER\Software\Microsoft\Office\Outlook\FormRegions\<MessageClass>.

See the sample registry script in the project to get the exact location.

So that's the story on Form Regions for right now. As I said, this gets easier when Office releases – and easier yet in Orcas. Hope this is enough to get you going in VSTO 2005 SE.