Office Add-Ins

Develop Add-Ins For PowerPoint And Visio Using VSTO

Paul Stubbs

This article discusses:
  • Extensibility for Microsoft Office applications
  • PowerPoint object model
  • Visio object model
This article uses the following technologies:
Microsoft Office

Contents

PowerPoint 2007
PowerPoint 2007 Object Model
Create a Presentation
Add a Title Slide
Add a Bulleted Slide
Set the Presentation Theme
Create a Ribbon
Visio 2007
Visio 2007 Object Model
Create New Document
Adding Shapes
Connecting Shapes
Adding a Background Page
Set the Document Theme
Create a Commandbar
Summary

Microsoft Visual Studio 2005 Tools for the Microsoft Office system (VSTO) is a powerful set of tools and features that let developers extend and customize Microsoft® Office applications using Visual Basic® and Visual C#®. With the release of the 2007 Microsoft Office system comes a new version of VSTO. This new version, Microsoft Visual Studio® 2005 Tools for the 2007 Microsoft Office system (known as Visual Studio 2005 Tools for Office Second Edition, or VSTO 2005 SE), adds new capabilities for Word, Excel®, Outlook®, PowerPoint®, Visio®, and InfoPath®. Available as a free download it can be installed on top of Visual Studio 2005 Professional Edition or above and on top of VSTO 2005.

With VSTO 2005 SE, you customize 2007 Microsoft Office system features (including the Ribbon, custom task panes, and Outlook form regions) in your add-ins. The VSTO 2005 SE runtime also adds support for your existing VSTO 2005 applications in the 2007 Office system. And it can be used to create Office 2003 add-ins.

This new release is the first that has included support for PowerPoint and Visio. Let's look at the added support for these two applications, looking at how you can easily create great new apps.

PowerPoint 2007

Support for PowerPoint was one of the most requested additions to VSTO 2005 SE. There are many tasks, such as generating and updating presentations, that can be made easier using VSTO add-ins. A typical example of presentation generation is creating a new presentation by stitching together existing slides from a slide library stored on a server. Other common scenarios include creating new slides programmatically and updating existing slides with current data. I want to walk you through some of the common tasks associated with creating and updating slides. Note that this discussion pertains primarily to the 2007 Office system.

When you install VSTO 2005 SE, it adds two folders under the Office node in the Visual Studio New Project dialog (see Figure 1): one for creating add-ins that target Office 2003 and one for add-ins that target the 2007 Office system apps. Let's start creating a new PowerPoint add-in by selecting the PowerPoint Add-in template shown in the 2007 Add-ins folder.

Figure 1 VSTO Templates

Figure 1** VSTO Templates **(Click the image for a larger view)

The PowerPoint project template creates a class called ThisAddIn. You will see that there are two events: ThisAddIn_Startup and ThisAddIn_Shutdown. ThisAddIn_Startup is called when the add-in is loaded. (This is a good place to put your initialization code.) ThisAddIn_Shutdown is called when the add-in is being unloaded. (This is where you should put your cleanup code.)

PowerPoint 2007 Object Model

PowerPoint has a rich object model you can use to create add-ins. And you do not need to understand the entire object model to get started.

As in all Office applications, the top-level object for PowerPoint is the Application object, which represents the entire PowerPoint application. The VSTO programming model gives you easy access to this Application object. Typing Me.Application returns a PowerPoint.Application type. Unlike shared add-ins, there is no need to cast the object to the correct Office Application type because the VSTO project template sets the correct type for the add-in you are creating. (For example, calling Me.Application in a Word add-in returns a Microsoft.Office.Interop.Word.Application object.)

The Application object contains a Presentations collection that, in turn, contains a Presentation object. The Presentation object, which represents the actual .ppt document, contains a Slides collection that holds the Slide objects (there's one Slide object for each slide in your presentation). And each slide contains a Shapes collection, which holds Shape objects. The Shape objects are the items that you see on your slides, such as the title, text frames, pictures, and charts (see Figure 2).

Figure 2 Shape Objects on a PowerPoint Slide

Figure 2** Shape Objects on a PowerPoint Slide **(Click the image for a larger view)

Create a Presentation

You use a reference to the Application object to create a new Presentation and add it to the Presentations collection. First, create a variable to hold a reference to the new Presentation object that you will create. Then all you need to do is call the Add method on the Presentations collection:

   Dim presentation As PowerPoint.Presentation = _ 
       Me.Application.Presentations.Add()

You may be wondering where the PowerPoint object comes from. The VSTO project template automatically adds an Imports alias to the namespace Microsoft.Office.Interop.PowerPoint. You can see the other references and aliases that are created by looking at the Imported namespaces section on the References project properties page.

Add a Title Slide

The title slide, which displays the title and subtitle of the presentation, is usually the first slide in a presentation. Creating a new slide is similar to creating a new presentation. You add a slide to the slides collection of the presentation by calling the AddSlide method. This method takes two parameters: the slide index (used to specify where in the presentation the slide should be inserted) and a customLayout object.

You can create a customLayout object from the SlideMaster. The SlideMaster contains all of the objects that you want to appear on your slides. As you can see in this code, you can select the type of layout from the PpSlideLayout enumeration:

Dim customLayout As PowerPoint.CustomLayout = _
    presentation.SlideMaster.CustomLayouts.Item( _ 
        PowerPoint.PpSlideLayout.ppLayoutTitle)

You can now create a new slide using the AddSlide method. Use a slide index of 1 to add the slide as the first slide in the presentation, and pass the customLayout object that you created from the SlideMaster:

Dim slide as PowerPoint.Slide = _
    presentation.Slides.AddSlide(1, customLayout)

The title slide is now created and you can set the title and subtitle with a single line of code. Using the slide object that you just created you can get the Title property of the Shapes collection to return a Shape object that is the title object for the slide. The Shape object has a TextFrame property that returns a TextFrame object, which exposes a TextRange object. You set the Text property of the TextRange object, like so:

slide.Shapes.Title.TextFrame.TextRange.Text = "VSTO 2005 SE Rocks"

Setting the subtitle is very similar except that there is no subtitle shape property. In this case, I know that the subtitle is the second shape on the slide so I can reference it by the shape index:

slide.Shapes(2).TextFrame.TextRange.Text = _
    "AN OFFICE DEVELOPMENT STORY"

Add a Bulleted Slide

Next, you will want to add another slide that, typically, has a title at the top and a bulleted list of items as the main content. This is the most commonly used slide type. To do this, create a new slide as you did in the previous section, but choose a different CustomLayout type: ppLayoutText. I used 1 as the slide index for the title slide since I want the title slide to appear as the first slide. To insert slides in order (after the last existing slide), you should count the number of existing slides:

Dim customlayout As PowerPoint.CustomLayout = _
    presentation.SlideMaster.CustomLayouts.Item( _ 
        PowerPoint.PpSlideLayout.ppLayoutText)
Dim slide as PowerPoint.Slide = _
    presentation.Slides.AddSlide( _
        presentation.Slides.Count + 1, customlayout)

Set the Presentation Theme

A new feature in the 2007 Office system, Office themes, lets you apply predefined styles to your documents. A theme will globally change the look of your presentation, including the fonts, graphics, colors, and effects. Themes are supported by Word, Excel, PowerPoint, and Outlook. They are defined in a Theme file with the .thmx extension and are shared across all of the supported applications. The 2007Office release ships with a few default themes located in the Document Themes 12 directory under the Office installation path.

You set the theme by calling a new method of the presentation object: ApplyTheme. This method takes one parameter-the path to the .thmx theme file:

presentation.ApplyTemplate( _
    "C:\Program Files\Microsoft Office\Document Themes 12\Civic.thmx")

Create a Ribbon

The Ribbon is central to the new Office UI. Replacing the menus and command bars of previous versions of Office, the Ribbon organizes features and functions into context sensitive tabs. The tabs contain groupings of controls, such as buttons, galleries, and dropdown lists. For this project, you'll create a simple Ribbon with a single button that creates a new presentation when clicked. VSTO 2005 SE supports Ribbon extensions and makes it easy to add new custom Ribbon tabs and controls to your applications.

First, add a Ribbon support item to your project from the Project | Add New Item menu. This creates two files in your project: one for the Ribbon definition and one for the Ribbon codebehind. The Ribbon definition file is an XML file that describes the Ribbon. The Ribbon codebehind handles the loading of and the events of the Ribbon. Figure 3 shows a simple Ribbon definition XML file that adds a Ribbon tab called My Tab, which contains a single group called My Group. The group contains only one button, called My Button. The button has a callback specified for the onAction called OnClick.

Figure 3 Simple Ribbon Definition XML File

<customUI xmlns="https://schemas.microsoft.com/office/2006/01/customui" 
     onLoad="OnLoad">
  <ribbon>
    <tabs>
      <tab id="MyTab" label="My Tab">
        <group id="MyGroup" label="My Group">
          <button id="Button1" size="large" label="My Button"
                  screentip="My Button Screentip" onAction="OnClick" 
                  imageMso="HappyFace" />
        </group>
      </tab>
    </tabs>
  </ribbon>
</customUI>

In the Ribbon definition that is automatically created, a callback is defined for the onLoad of the Ribbon and the onAction for the button. You must edit the methods generated in the Ribbon1 class to handle these callbacks. The Ribbon1 class was created when you added the Ribbon support item. The Ribbon1 class implements the IRibbonExtensibility interface that is passed to Office when requested.

The Office Ribbon uses a service request model, meaning Office calls the RequestService method and asks whether you have a class that implements the IRibbonExtensibility interface. After you pass back an instance of the Ribbon1 class, Office uses this instance for the callbacks.

The code to handle the RequestService method is already written when you added the Ribbon support item-simply uncomment the partial class code at the top of the Ribbon1 file. Then write the methods to handle the callbacks; you can find the callback signature documentation for all of the Ribbon callbacks on MSDN®. In the OnLoad callback, Office passes a reference to the Ribbon instance. You can save this reference for when you need to invalidate the Ribbon.

Invalidating the Ribbon is the only way to refresh it. When you invalidate the Ribbon, Office refires all of the callbacks for the Ribbon needed for rendering. You can also invalidate a single control for more granular handling:

Private ribbon As Office.IRibbonUI
Public Sub OnLoad(ByVal ribbonUI As Office.IRibbonUI)
    Me.ribbon = ribbonUI
End Sub

In the OnClick callback for the button, use the Globals class to get a reference to the ThisAddIn class. And call the CreateNewPresentation subroutine to create a new presentation and perform all steps:

Public Sub OnClick(ByVal control As Office.IRibbonControl)
    Globals.ThisAddIn.CreateNewPresentation()
End Sub

Running the solution by pressing F5 registers the add-in and starts PowerPoint. The new Ribbon then appears as the last Ribbon tab on the right, called My Tab.

For more information on developing with the Ribbon, see Eric Faller's article on the subject in this issue of MSDN Magazine.

Visio 2007

Visio has long supported custom development, with support for Visual Basic for Applications and the availability of its own SDK. VSTO 2005 SE extends this capability with the ability to create managed VSTO add-ins.

Visio solutions help you visualize your data. For example, you could diagram a timeline of your schedule using data from a database, or you could create an organization chart with live data from Active Directory overlaid with sales data for each employee. Let's look at some basic tasks in Visio that can lay the foundation for larger applications.

As with all VSTO add-ins, you begin by creating a new VSTO add-in project. Again, you can choose to target either Visio 2003 or Visio 2007; I will be using Visio 2007. VSTO creates an add-in with the ThisAddIn_Startup and ThisAddIn_Shutdown event handlers, just like when creating the PowerPoint add-in.

Visio 2007 Object Model

The object model in Visio, which is quite different from the other Office applications, can be challenging to understand. Fortunately, you don't need to understand the entire object model for this project-a few basic concepts will get you started.

As with all Office applications, the root of the object model is the Application object, which contains a collection of Document objects. The Document is the object that represents the drawing, and it contains a collection of Page objects. Each Page object, in turn, contains a collection of Shape objects. These Shape objects are the key to creating Visio applications.

Shapes are the objects that you drop on the page from stencils. Stencils (the collections of Visio shapes that you can add to your drawings) are contained in a .vss file and are visible in a container on the left side of your Visio drawing.

Create New Document

Create a new document by calling the Add method on the Document collection:

Dim newDocument As Visio.Document = Application.Documents.Add("")

This will return an instance of a Visio.Document object.

You may also want to set some other properties when you create the document. For instance, you can set the layout to portrait or landscape, as well as set the height and width of the document. This is common for Visio documents since they can be very large and are often printed on plotters or across many letter size pages.

The page has a special shape called a PageSheet, which is a collection of properties for the page. This is an important concept to understand because this is how all Visio properties are set. Properties are stored in a Cell object. Once you have a reference to the Cell, you can set the Formula, which is evaluated by Visio to obtain the final value:

Dim page As Visio.Shape = newDocument.Pages(1).PageSheet
' Set the layout.
page.Cells("PrintPageOrientation").Formula = _
    Visio.VisCellVals.visPPOPortrait
' Set the paper size.
page.Cells("PageWidth").Formula = "8.5 in"
page.Cells("PageHeight").Formula = "11.0 in"

Adding Shapes

Before adding shapes to the document, you need to open a stencil. In this case, you'll open the basic stencil. Pass the name of the stencil file and flags-for example, open read-only and docked to the application window:

Stencil = Application.Documents.OpenEx( "BASIC_M.VSS", _
    Visio.VisOpenSaveArgs.visOpenRO + _
    Visio.VisOpenSaveArgs.visOpenDocked)

Now call the Drop method of Page object to add a shape to the page, passing a Master object (which comes from the Masters collection of the stencil) and an X and Y position of where you want the shape placed:

Dim AddedShape As Visio.Shape = _
    Application.ActiveWindow.Page.Drop( _
        Stencil.Masters.ItemU("Square"), 2, 9)

You can then customize the shape, adding text, for example, that is displayed in the shape. Just as you did with the properties of the document, you set the properties of the shape by getting a reference to the Cell object that contains the property. The Text property, however, is so common that it was added directly to the Shape object, and therefore you don't need to use the Cell object to set the text:

AddedShape.Text = "Shape 1"

You will add shapes many times, so I highly recommend refactoring this code into a separate method:

Public Function AddShape(ByVal ShapeName As String, _
    ByVal X As Double, ByVal Y As Double) As Visio.Shape

    ' Add a new shape to the document from the stencil.
    Dim AddedShape As Visio.Shape = _
        Application.ActiveWindow.Page.Drop( _
            Stencil.Masters.ItemU(ShapeName), X, Y)

    Return AddedShape
End Function

Now it is easy to add multiple shapes. Here's a sample for adding a square and a triangle, and setting the text of each shape:

' Add a square.
shape1 = AddShape("Square", 2, 9)
shape1.Text = "Shape 1"
' Add a Triangle.
shape2 = AddShape("Triangle", 2, 6)
shape2.Text = "Shape 2"

For Visio drawings, 0,0 represents the bottom-left of the page. Therefore, in this sample, the square is placed two inches from the left and nine inches from the bottom.

Connecting Shapes

In Visio, you can visualize relationships and data flow by connecting shapes. The lines connecting shapes are actually shapes themselves. Thus, you add these connecting lines using the same pattern you use to add shapes:

Dim connector As Visio.Shape = AddShape("Dynamic Connector", 4, 4)
connector.Text = "Shape1 to Shape2"

To connect the triangle to the square (which is located above the triangle), first define two Cell objects to hold a reference to the properties of the connection points. You use ShapeConnectionPoint (the point on the shape) and ConnectorEndPoint (the point on the connection line):

Dim ShapeConnectionPoint As Visio.Cell
Dim ConnectorEndPoint As Visio.Cell

Shape2 is the triangle you created earlier and the property for the top point on the triangle is called Connections.X4. Connector is the dynamic connector shape and EndX is the property name for the bottom end of the line:

ShapeConnectionPoint = shape2.Cells("Connections.X4")
ConnectorEndPoint = connector.Cells("EndX")

Then you glue the cells together to connect the line to the shape:

ConnectorEndPoint.GlueTo(ShapeConnectionPoint)

The triangle is easy to connect since it has three connection points. The square has four connection points (one on each corner). You can see these points when you drop a shape onto the page-they appear as little blue Xs. You can only glue to connection points. Thus, if you want to connect to a different part of the shape (say, the bottom line of the square), you must add a new connection point. Figure 4 shows a helper method to assist with this.

Figure 4 AddConnectionPoint Helper Method

Public Function AddConnectionPoint( _ 
        ByVal shape As Visio.Shape) As Visio.Cell

    Dim newConnectionPointIndex As Integer
    Dim newConnectionPoint As Visio.Row
    newConnectionPointIndex = shape.AddRow( _
        Visio.VisSectionIndices.visSectionConnectionPts, _
        Visio.VisRowIndices.visRowLast, _
        Visio.VisRowTags.visTagCnnctPt)
    'Get a reference to the new connection point.
    newConnectionPoint = shape.Section( _
        Visio.VisSectionIndices.visSectionConnectionPts) _
        .Row(newConnectionPointIndex)
    'Create the connection point in the middle on the bottom of the shape.
    With newConnectionPoint
        .Cell(Visio.tagVisCellIndices.visCnnctX).FormulaU = "Width*0.5"
        .Cell(Visio.tagVisCellIndices.visCnnctY).FormulaU = "Height*0"
        .Cell(Visio.tagVisCellIndices.visCnnctDirX).FormulaU = 0.0#
        .Cell(Visio.tagVisCellIndices.visCnnctDirY).FormulaU = 1.0#
        .Cell(Visio.tagVisCellIndices.visCnnctType).FormulaU = _
            Visio.tagVisCellVals.visCnnctTypeInward
    End With

    Return shape1.Cells("Connections.X" & newConnectionPointIndex + 1)
End Function

Now, to connect a straight line down from the square to the top of the triangle (as shown in Figure 5), you add a new connection point to the bottom center line of the square with the following:

ShapeConnectionPoint = AddConnectionPoint(shape1)
ConnectorEndPoint = connector.Cells("BeginX")
ConnectorEndPoint.GlueTo(ShapeConnectionPoint)

Figure 5 Creating a Document in Visio 2007

Figure 5** Creating a Document in Visio 2007 **(Click the image for a larger view)

The AddConnectionPoint helper method adds a new connection point and returns the Cell object. You add a new connection point by adding a new property, or row, as Visio stores the properties internally as a list. Once you have added the row, you can set the formula values. So far, most of the formulas have consisted of simple values. In this case, the formula dynamically calculates the center of the bottom line with Width*0.5. Finally the method returns the Cell instance for the newly created connection point.

Adding a Background Page

In Visio, the background page lets you add text or shapes (a title and legend, for instance) that you want to appear behind multiple pages. The background page is a normal page that has the Background property set to 1 for true. You associate the background page with another page by setting the BackPage property:

Dim backgroundPage As Visio.Page = _
    Application.ActiveDocument.Pages.Add()
backgroundPage.Name = "TheBackground"

backgroundPage.Background = 1 'True

Application.ActiveDocument.Pages(1).BackPage = backgroundPage.Name

To add text to the background page, you create a shape object from a rectangle, set the font property of the shape by passing the font index number, and set the text of the Characters object to set the text that will appear in the shape. This is shown in Figure 6.

Figure 6 Adding Text to a Background Page

' Create a textbox shape.
Dim textBox As Visio.Shape
textBox = Application.ActiveWindow.Page.DrawRectangle( _
    1.0, 10.0, 3.0, 10.5)
textBox.TextStyle = "Normal"
textBox.LineStyle = "Text Only"
textBox.FillStyle = "Text Only"
' Set the font.
fontIndex = Application.ActiveDocument.Fonts("Arial Black").ID
textBox.Cells("Char.Font").Formula = fontIndex
' Set the text.
Dim textBoxText As Visio.Characters
textBoxText = textBox.Characters
textBoxText.Begin = 0
textBoxText.End = 0
textBoxText.Text = "VSTO 2005 SE Rocks"

Set the Document Theme

You can set predefined themes in Visio just as you can in PowerPoint. In fact, you can set the same theme across most of the Office applications. One difference in Visio, though, is that you can specify the theme using the VisThemeColors enumeration. There are multiple ways to specify the value. You can, for example, specify the value as a string or as an integer. Another difference with Visio, is that you specify the theme colors and theme effects separately. From the ActivePage, you can control these with the Theme Colors and Theme Effects properties, respectively:

Application.ActivePage.ThemeColors = _
    Visio.VisThemeColors.visThemeColorsCivic

Application.ActivePage.ThemeEffects = _
    Visio.VisThemeEffects.visThemeEffectsPillow

Create a Commandbar

Obviously, you need a way to launch the subroutine that will create the drawing. Visio doesn't support Ribbons, so for this add-in you use a Commandbar. (This code has not changed from Visio 2003 and other Office 2003 applications.) Figure 7 shows the code used to create a Commandbar and add a button control with a smiley face icon. You can see this button in Figure 5. The final result is a square connected to a triangle with a theme applied, as shown in Figure 5.

Figure 7 Creating a Commandbar

Dim commandBars As Office.CommandBars
Dim commandBar As Office.CommandBar

commandBars = Application.CommandBars
commandBar = commandBars.Add("Demo Toolbar", _
    Office.MsoBarPosition.msoBarTop, , True)
' Set the context when the toolbar is visible.
commandBar.Context = Visio.VisUIObjSets.visUIObjSetDrawing & "*"

' Add a button with a smiley face icon.
DemoButton = _ 
    commandBar.Controls.Add(Office.MsoControlType.msoControlButton)
DemoButton.Tag = "Demo Button"
DemoButton.FaceId = 2950 
DemoButton.TooltipText = "Run Demo"

Summary

Available as a free add-on to Visual Studio Professional or above, VSTO 2005 SE lets you build applications for the six most common Office applications. It also lets you ensure that your existing VSTO 2005 applications continue working as you move to the 2007 Office system. Whether you are using Office 2003 or the 2007 Office system, VSTO 2005 SE provides an easy way to create great Office add-ins.n

Paul Stubbs is a Program Manager with the Visual Studio Tools for Office and Visual Studio Tools for Applications team. He coauthored VSTO for Mere Mortals with Kathleen McGrath (Addison-Wesley, 2006). He has spoken at TechEd and TechReady and participates in the developer community on the Microsoft forums. Read Paul's blog at blogs.msdn.com/pstubbs.