Creating Add-ins in Microsoft PowerPoint 97

John Clarkson
Microsoft Corporation

April 1999

Summary: Shows how to create a Microsoft® PowerPoint® add-in that builds a presentation from scratch by displaying data from a Microsoft Access database query. (11 printed pages) Covers:

Introduction
Creating Add-ins in PowerPoint
Running Add-ins in PowerPoint
The Code in the Sample
Creating a Sample Add-in
Conclusion

Introduction

This article demonstrates how to create a PowerPoint add-in that adds a Sales Report command to the Tools menu when it's loaded. When the Sales Report command is selected, the add-in uses Microsoft Visual Basic® for Applications (VBA) and Data Access Objects (DAO) code to build from scratch a presentation that displays data from the Northwind sample database. The presentation lists the two top-selling products, with sales figures, for each product category in Northwind.

Creating Add-ins in PowerPoint

Add-ins are supplemental programs that extend the capabilities of an application by adding custom commands and specialized features. One example might be an add-in that prompts a salesperson to enter last-minute or customer-specific data into a form just before a sales call, and then uses this data to update a presentation. Another example is an add-in that allows a financial manager to automatically build a presentation summarizing the firm's monthly results.

You can buy add-ins from independent software vendors, you can download them from the Microsoft Office Update Web site (http://officeupdate.microsoft.com/), or you can create your own add-ins. To create a PowerPoint add-in, you create a new presentation and save it as a PowerPoint add-in (.ppa) file.

To create a PowerPoint add-in

  1. Create a new presentation, and add your Visual Basic for Applications code and any other custom elements, such as toolbars or menu items.

  2. Test and debug the code.

  3. If you want, you can compile the project as described later in this article.

  4. Save the presentation as a PowerPoint presentation to your working folder, and then save it as a PowerPoint add-in to the \Program Files\Microsoft Office\Office folder.

Running Add-ins in PowerPoint

Loading Add-ins

You can load an add-in manually or programmatically.

Loading add-ins manually

Use this procedure to load PowerPoint add-ins manually.

To load an add-in manually

  1. On the Tools menu, click Add-Ins.

  2. If the add-in you want isn't in the Available add-ins list, click Add New, locate the add-in, and then click Open.

  3. In the Available add-ins list, click the add-in you want to load, and then click Load.

The add-in is registered, and a check mark appears next to its name. (Note that using Windows Explorer to open a PowerPoint add-in file will also load the add-in.)

Loading add-ins programmatically

To load an add-in programmatically, first add it to the AddIns collection, and then set the Loaded property of the corresponding AddIn object to True. You can perform these two actions in a single step, as shown in the following example. (Note that you use the file name of the add-in, not its title, with the Add method.)

AddIns.Add _
    ("C:\Program Files\Microsoft " _
    & "Office\Office\YourAddIn.ppa") _
    .Loaded = True

Compiling Add-in Code

Select Compile VBA Project on the Tools menu to compile your Visual Basic for Applications code. This detects run-time errors at design time, which you may prefer to waiting until run time.

Hiding Add-in Code

You can set a password for your PowerPoint add-in project in order to prevent unwanted viewing and editing, but it should not be necessary. Once your PowerPoint project is saved as an add-in and closed, the code is no longer visible.

Running Add-in Code

Loading an add-in won't by itself trigger your code. To automatically run code when your add-in is loaded, create a subprocedure named Auto_Open in a standard module in the add-in project. In the example described later in this article, I use an Auto_Open procedure to add a menu item that the user can use to actually start the add-in itself. (Of course, once an add-in is loaded, you can also use the Macro command on the Tools menu to start add-in code.)

To run code when your add-in is unloaded, create a subprocedure named Auto_Close in a standard module in the add-in project. In the example to follow, I used the Auto_Close procedure to remove the menu item that launches the add-in. This kind of cleanup work is a courtesy to users. Don't leave items hanging around in the environment after your add-in is removed.

The Code in the Sample

The code in the sample add-in is pretty simple. This is what it does:

Adding a Menu Item

The code in the Auto_Open and Auto_Close procedures is basically the same code as used in several of the other articles about add-ins in Office 97. For details, "Creating Add-ins in Excel 97" or "Creating Add-ins in Word 97."

Creating a New Presentation

Use the Add method of the PowerPoint Presentations collection to open a new presentation.

    Set pptPresentation = Presentations.Add(True)
    pptPresentation.ApplyTemplate FileName:=strTemplate

In this case, we're basing the presentation on a PowerPoint template (.pot file) that ships with Office 97. We use the ApplyTemplate method to apply the template.

You could also base the presentation on the template by opening it directly. However, if slides are added to the template, you won't get a clean presentation. Also, if the design template doesn't exist on the user's system, or is moved, users will get a "PowerPoint could not open the file" error. Using the ApplyTemplate method avoids the error -- you'll open with a blank presentation.

Adding a Title Slide

As you might guess, we'll use the Add method of the Slides collection to add a slide. The key line of code is this one, and it's definitely my favorite in this solution:

    .View.GotoSlide Index:=pptSlides.Add(Index:=1, _
         Layout:=ppLayoutText).SlideIndex

This statement breaks down into two parts: There's a call to the GotoSlide method, which wraps a call to the Add method. The core is really the Add method call itself, [Add(Index:=1, Layout:=ppLayoutText)], where we specify that the added slide goes first in the presentation sequence, and call for the slide to contain a text layout.

Next, note two things: First, the GotoSlide method requires an Index argument; and second, the Add method call ends by reading the SlideIndex property. These two pieces fit together in a very clever way: The value returned by the SlideIndex property (part of the Add method call!) is passed to the GotoSlide method's Index argument. We've managed to pack two method calls into a single statement! (I can't claim credit for this; it comes from an unnamed support engineer somewhere at Microsoft.)

The remaining code is pretty straightforward. Note that a slide with its layout set to ppLayoutText always starts its life containing two Shape objects with Name properties set to Rectangle 2 and Rectangle 3. Also note how dense the object hierarchy gets at this point—the full path is seven levels deep: "PowerPoint.ActivePresentation.Slides().Shapes().TextFrame.TextRange.Text."

    With pptSlides(1)
        .Shapes("Rectangle 2").TextFrame.TextRange = "Top Products"
        .Shapes("Rectangle 3").TextFrame.TextRange = _
             "Top two products in each category, with sales totals."
    End With

Open a Database and a Recordset Object

This is very basic DAO code. The OpenDatabase method points to a Jet database. The OpenRecordset method points to a query name associated with the database, and opens it as a snapshot-type Recordset object. Add a reference to the most current version of the DAO object library (Tools menu, References item) before running this code.

    Set dbsNorthwind = OpenDatabase(strDbPath)
    Set rsSales = dbsNorthwind.OpenRecordset _
        (strQueryName, dbOpenSnapshot)

In this case, the query is one that ships with the Northwind sample database in Office 97, modified to sort the results first by category, and then within category by sales.

Add a Slide with Data for Each Product Category

The master procedure contains an outer Do...Loop statement that ends when it finds an end of file in the set of records. The loop contains an error handler that checks for a Jet database "no current record" error, which would be triggered by a MoveNext statement occurring at the bottom of the set of records.

We step through the loop once for each product category. At the top of the loop we call the MakeSlide procedure. This procedure contains code very similar to the code that creates the title slide, discussed earlier in the section "Adding a Title Slide." In MakeSlide we read the product category, create a slide, and set the Text property of the TextRange object to add the product category to Rectangle 2 on the slide.

    pptSlides(pptSlides.Count). _
        Shapes("Rectangle 2").TextFrame.TextRange = strProductCategory

Note that the Text property is the default property of the TextRange object, so it is not necessary to specify it in code.

Next in the Do...Loop structure, a For...Next loop executes twice, calling the GetData procedure, which reads product data and calls the InsertAfter method to add the product data to Rectangle 3 on the slide created in the MakeSlide procedure.

    pptSlides(pptSlides.Count).Shapes("Rectangle 3"). _
        TextFrame.TextRange.InsertAfter _
        (vbCrLf & strProductName & vbTab & strSales)

The final step in the outer Do...Loop is to use an inner Do...Loop to call the MoveNext statement repeatedly until we find a new product category.

    Do While strProductCategory = rsSales!categoryName
        .
        .
        .
        rsSales.MoveNext
    Loop

Cleanup and End

Once the outer Do...Loop exits, the final step in the master procedure is to release the memory used by the two object variables.

    Set dbsNorthwind = Nothing
    Set rsSales = Nothing

Creating a Sample Add-in

This section explains how to re-create the Sales Report add-in, providing code and procedures.

Modify a Northwind query

  1. In Access, open the sample database, Northwind.mdb. The default location for this database in a typical installation of Microsoft Office 97 is C:\Program Files\Microsoft Office\Office\Samples.

  2. On the Database dialog box, click the Queries tab.

  3. Select "Sales by Category" and click Design.

  4. The default for this query is that the ProductName field is the only field sorted. Modify the query so that the ProductName field is not sorted; and the CategoryID and ProductSales fields are sorted, in descending order. To change the sort settings, toggle the values entered on the sort line for the appropriate field in the query design window.

  5. On the File menu, click Save As/Export and enter "New Sales by Category" as the query name. Click OK.

Create the Sales Report add-in

  1. Open the Visual Basic Editor (VBE). On the Tools menu, click References.

  2. In the References dialog box, select Microsoft DAO 3.5 Object Library, and then click OK.

  3. On the Insert menu select Module.

  4. Press F4 to open the Properties window, and set the module's Name property to AddInCode.

  5. Copy the statements and procedures in the code to follow to the AddInCode module.

  6. Switch out of VBE to PowerPoint. On the File menu, click Properties. Feel free to add your own text in this dialog box, but a good choice for title is "Sales Report," and "Sample Add-In" for comments. The title identifies an add-in in the Add-In Manager. The comment is displayed when an add-in is selected in the Add-In Manager. Click OK.

  7. Save your project to a working folder as Report.ppt.

  8. Save your project as a PowerPoint add-in to the \Program Files\Microsoft Office\Office folder.
Option Explicit
Sub Auto_Open()
' Adds an item to the Tools menu.
' This procedure runs automatically when the add-in loads.
    
    Dim offCmdBrPp As CommandBarPopup
    Dim offCmdBtn  As CommandBarButton
    
    ' Create an object variable referring to the Tools menu.
    Set offCmdBrPp = _
        Application.CommandBars("Menu Bar").Controls("Tools")
    ' If the Address Book Report command already exists, delete it.
    On Error Resume Next
    offCmdBrPp.Controls("Products Slide Show").Delete
    ' Add a command in the fourth position on the Tools menu.
    Set offCmdBtn = _
        offCmdBrPp.Controls.Add(Type:=msoControlButton, Before:=4)
    ' Set properties on the new command.
    With offCmdBtn
        .Caption = "Products Slide Show"
        .OnAction = "PresentationMaster"
    End With
    
End Sub

Sub Auto_Close()
' Deletes an item on the Tools menu.
' This procedure runs automatically when the add-in unloads.
' If the Address Book Report command exists, delete it.
    
    On Error Resume Next
    Application.CommandBars _
        ("Menu Bar").Controls("Tools").Controls _
        ("Products Slide Show").Delete
        
End Sub

Sub PresentationMaster()
' Create a presentation and apply "Whirlpool" template.

    Dim rsSales            As Recordset
    Dim dbsNorthwind       As Database
    Dim strProductCategory As String
    Dim strProductName     As String
    Dim lngLoopCounter     As Long
    Dim strErrorMessage    As String
    Dim strTemplate        As String
    Dim strDbPath          As String
    Dim strQueryName       As String
    Dim bolTemplateExists  As Boolean
    Dim pptSlides          As Slides
    Dim pptPresentation    As Presentation
    
    On Error GoTo PresentationMaster_Err
    
    Set pptPresentation = Presentations.Add(True)
    Set pptSlides = pptPresentation.Slides
    
    strTemplate = "C:\Program Files\Microsoft " _
        & "Office\Templates\Presentation " _
        & "Designs\Whirlpool.pot"
        
    bolTemplateExists = FileExists(strTemplate)
    
    If bolTemplateExists = False Then
        strErrorMessage = "The template Whirlpool.pot"
        strErrorMessage = strErrorMessage & _
            "doesn't exist at 'C:\Program Files\Microsoft"
        strErrorMessage = strErrorMessage & _
            "Office\Templates\Presentation"
        strErrorMessage = strErrorMessage & _
            "Designs\Whirlpool.pot"
        MsgBox strErrorMessage
        Exit Sub
    End If

    pptPresentation.ApplyTemplate FileName:=strTemplate

    With ActiveWindow
        'Create a title slide.
        .ViewType = ppViewSlide
        'Add a new slide and switch to it.
        .View.GotoSlide Index:=pptSlides.Add _
             (Index:=1, Layout:=ppLayoutText).SlideIndex
    End With

    With pptSlides(1)
        .Shapes("Rectangle 2").TextFrame.TextRange = "Top Products"
        .Shapes("Rectangle 3").TextFrame.TextRange = _
             "Top two products in each category, with sales totals."
    End With

    strDbPath = "C:\Program Files\Microsoft " _
        & "Office\Office\Samples\Northwind.mdb"
    strQueryName = "New Sales by Category"

    Set rsSales = _
        GetRecordSet(dbsNorthwind, rsSales, strDbPath, strQueryName)

    ' This loop reads product data from the Northwind
    ' database and adds it to PowerPoint slides.
    rsSales.MoveFirst
    Do While Not rsSales.EOF

        ' MakeSlide creates a new slide.
        Call MakeSlide(rsSales, strProductCategory, pptSlides)

        ' Get two values if the product name is unchanged.
        For lngLoopCounter = 0 To 1
            If strProductCategory = rsSales!categoryName Then
                Call GetData(rsSales, strProductName, pptSlides)
            End If
        Next lngLoopCounter

        'Find the next product category.
        On Error Resume Next
        Do While strProductCategory = rsSales!categoryName
            If Err.Number = 3021 Then
                Exit Do
            ElseIf Err.Number > 0 Then
                On Error GoTo PresentationMaster_Err
            End If
            rsSales.MoveNext
        Loop
    Loop
    
PresentationMaster_End:
    Set dbsNorthwind = Nothing
    Set rsSales = Nothing
    Exit Sub

PresentationMaster_Err:
    strErrorMessage = "Error: " & Err.Number & _
        " " & Err.Description & vbCrLf
    strErrorMessage = strErrorMessage & _
        "Unrecognized error in the" & vbCrLf
    strErrorMessage = strErrorMessage & _
        "PresentationMaster procedure."
    MsgBox strErrorMessage

    Resume PresentationMaster_End
    
End Sub
Function GetRecordSet(dbsNorthwind As Database, _
                      rsSales As Recordset, _
                      strDbPath As String, _
                      strQueryName As String) As Recordset
' This procedure opens the database and
' creates the Recordset object that
' contains data for the presentation.
' Called by the ReportMaster procedure.

    Dim strErrMessage As String

    On Error GoTo GetRecordSet_Err

        Set dbsNorthwind = OpenDatabase(strDbPath)
        Set rsSales = _
            dbsNorthwind.OpenRecordset(strQueryName, dbOpenSnapshot)

        Set GetRecordSet = rsSales

GetRecordSet_End:
    Exit Function

GetRecordSet_Err:
    Select Case Err.Number
        Case 3078
          MsgBox "Query doesn't exist."
        Case 3024
          MsgBox "Northwind is not installed at the expected location."
        Case Else
          strErrMessage = "Error: " & Err.Number & _
              " " & Err.Description & vbCrLf
          strErrMessage = strErrMessage & _
              "Unrecognized error in the" & vbCrLf
          strErrMessage = strErrMessage & _
              "GetRecordSet procedure."
          MsgBox strErrMessage
    End Select

    Resume GetRecordSet_End

End Function
Function FileExists(strFile As String) As Boolean
    Dim strSuccess As String

    strSuccess = Dir(strFile)
    If Len(strFile) > 0 Then
        FileExists = True
    Else
        FileExists = False
    End If

End Function

Sub MakeSlide(rsSales As Recordset, _
              strProductCategory As String, _
              pptSlides As Slides)
' This procedure creates a new slide and
' adds Product Category as the slide title.
' Called from the PresentationMaster procedure.
' The rsSales parameter is the
' Recordset object created by the Access query.
' The strProductCategory parameter contains
' the current product category.

    ' Read the product category.
    strProductCategory = rsSales!categoryName
    ActiveWindow.View.GotoSlide ActivePresentation.Slides.Add _
        (Index:=ActivePresentation.Slides. _
        Count + 1, Layout:=ppLayoutText).SlideIndex
    pptSlides(pptSlides.Count). _
        Shapes("Rectangle 2").TextFrame.TextRange = strProductCategory
End Sub

Sub GetData(rsSales As Recordset, _
            strProductName As String, _
            pptSlides As Slides)
' This procedure reads product data and adds it to the slide.
' Called from PresentationMaster procedure.
' The rsSales parameter is the Recordset object
' created by the Access query.

    Dim strSales As String

    ' Read the product name.
    strProductName = rsSales!ProductName

    ' Read sales data and put it in currency format.
    strSales = Format(rsSales!ProductSales, "currency")
    pptSlides(pptSlides.Count). _
        Shapes("Rectangle 3").TextFrame.TextRange.InsertAfter _
        (vbCrLf & strProductName & vbTab & strSales)
    rsSales.MoveNext
End Sub

Conclusion

You'll find that PowerPoint add-ins are architecturally very similar to Microsoft Excel add-ins, and that using add-ins to programmatically build periodic reports in PowerPoint is a very effective combination of Visual Basic for Application's automation capabilities and PowerPoint's strengths as a presentation tool. This sample add-in could easily be modified to read data from other data sources and to use more of PowerPoint's formatting features.

This add-in could also be extended by exporting data to Excel for numerical analysis, and by using Microsoft Graph to display charts in the presentation. We'll actually do this in another article later in this add-in series, "Using Microsoft Excel and Microsoft Graph to Extend a PowerPoint Add-in."

See Also

"Creating Add-ins in Excel 97"

"Creating Add-ins in Word 97"