Microsoft Office 97 Cross-Application Automation Samples

Microsoft Corporation

June 27, 1998

Contents

Introduction
Exporting a Microsoft Access Table into an Outlook Contacts Folder
Creating Mailing Labels from an Outlook Contact List Using Word
Creating a Presentation from a Microsoft Excel Workbook
Personalizing a Presentation for a Contact List
Exporting Outlook Journal Entries to a Microsoft Access Table
Creating a Web Presentation from a Word Document Using PowerPoint
Inserting a URL List from a Microsoft Access Table into a Word Document
Inserting a Microsoft Excel Value into a Word Bookmark
Additional Resources

Click here to copy the Automation samples discussed in this article.

Introduction

This paper provides sample code for several cross-application solutions. It gives examples of using Automation to manipulate Microsoft® Outlook®, Microsoft Word, Microsoft Access, Microsoft PowerPoint®, and Microsoft Excel. It shows how to use data across applications and ways to convert one kind of document into another. By building from these examples, you can develop solutions that seamlessly use the full functionality of the Microsoft Office 97 suite of products.

The sample code in this paper uses early binding of object variables. This makes for more efficient and readable code. Early binding involves declaring object variables as specific objects rather than as just objects. For example, you declare an object variable used to point to a Word document as Document rather than as Object.

To use early binding, your project must reference the object libraries that contain the information needed about the objects you want to use. For example, to use early binding with a variable pointing to a Word document, your project must have a reference to the Microsoft Word 8.0 Object Library. You add this reference by opening the project in the Visual Basic® Editor (or, in Microsoft Access, opening a module in Design view), clicking References on the Tools menu, and selecting the appropriate object library.

To try the solutions described in this paper, download samp.exe, which contains the necessary sample files.

Exporting a Microsoft Access Table into an Outlook Contacts Folder

This section shows you how to add a list of contacts, stored in a Microsoft Access table, to your Outlook Contacts folder. It uses a subroutine, ExportContactsTable, and a function, boolCheckName.

The subroutine, ExportContactsTable, creates a new Outlook ContactItem object for each record in the table. It takes a table name as its only argument. The table should have these fields: ContactName, Address, City, Region, PostalCode, Country, Phone, Fax, CompanyName, ContactTitle, and CustomerId.

In the sample table there is a field, CustomId, which does not correspond to any of Outlook's built-in fields. The subroutine creates a custom field for an Outlook ContactItem. This custom field will be available as a User-defined field in Outlook through the Field Chooser.

The function boolCheckName is called by ExportContactsTable to do minimal checking of each contact name. It insures that the name is not a zero-length string and that it does not already exist in the Outlook Contacts list. It returns True if the contact should be added to the Contact List.

The sample code for this section, as well as a sample table of contacts, is in AccSamp.mdb. The code is in the modContacts module. To run this solution, open the database and click Export Contacts on the Samples form.

Note   Running the sample code adds thirteen contacts to your Outlook Contact List. However, each contact name added to your list is preceded with the word "test" for easy deletion.

Note   To use this code in your own project, you must reference the Microsoft Outlook 8.0 Object Library.

'Use a global constant for the message box caption.
Const MESSAGE_CAPTION = "Exporting Contacts to Microsoft Access"

Public Sub ExportContactsTable(strTableName As String)

    Dim oOutlook As New Outlook.Application
    Dim colItems As Items
    Dim tblContacts As Recordset
    Dim upContactId As UserProperty
    Dim strMessage as String
   
    Const ERR_TABLE_NOT_FOUND = 3078
    Const ERR_FIELD_NOT_FOUND = 3265
    Const ERR_ATTACHED_TABLE_NOT_FOUND = 3024
    Const ERR_INVALID_ATTACHED_TABLE_PATH = 3044
    
    On Error GoTo ERR_ExportContactsTable
    
    'Open the table.
    Set tblContacts = CurrentDb.OpenRecordset(strTableName)
    
    'Get a reference to the Items collection of the contacts folder.
    Set colItems = oOutlook.GetNamespace("MAPI"). _
                        GetDefaultFolder(olFolderContacts).Items
    
        Do Until tblContacts.EOF
            If boolCheckName(Nz(tblContacts!ContactName), colItems) Then
                'Use the Add method of Items collection to fill in the          
                'fields with the data from the table and then save the new 
                'item.
                With colItems.Add
                    .FullName = Nz(tblContacts!ContactName)
                    .BusinessAddressStreet = Nz(tblContacts!Address)
                    .BusinessAddressCity = Nz(tblContacts!City)
                    .BusinessAddressState = Nz(tblContacts!Region)
                    .BusinessAddressPostalCode = Nz(tblContacts!PostalCode)
                    .BusinessAddressCountry = Nz(tblContacts!Country)
                    .BusinessTelephoneNumber = Nz(tblContacts!Phone)
                    .BusinessFaxNumber = Nz(tblContacts!Fax)
                    .CompanyName = Nz(tblContacts!CompanyName)
                    .JobTitle = Nz(tblContacts!ContactTitle)
                    
                    'Create a custom field.
                    Set upContactId = .UserProperties. _ 
                            Add("ContactID", olText)

                    upContactId = Nz(tblContacts![CustomerID])
                    
                    .Save
                End With
            End If
            tblContacts.MoveNext
        Loop
        tblContacts.Close

        strMessage = "Your contacts have been successfully exported."
        MsgBox strMessage, vbOKOnly, MESSAGE_CAPTION
Exit_ExportContactsTable:
    On Error Resume Next
    
    Set tblContacts = Nothing
    Set oOutlook = Nothing
    
    Exit Sub    
ERR_ExportContactsTable:
    
    Select Case Err
        Case ERR_TABLE_NOT_FOUND
            strMessage = "Cannot find table!"
            MsgBox strMessage, vbCritical, MESSAGE_CAPTION
            Resume Exit_ExportContactsTable
        
        'These errors occur if an attached table is moved or deleted
        'or if the path to the table file is no longer valid.
        Case ERR_ATTACHED_TABLE_NOT_FOUND, ERR_INVALID_ATTACHED_TABLE_PATH
            strMessage = "Cannot find attached table!"
            MsgBox strMessage, vbCritical, MESSAGE_CAPTION
            Resume Exit_ExportContactsTable
            
        'If a field in the code does not match a field in the table,
        'then move on to the next field.
        Case ERR_FIELD_NOT_FOUND
            Resume Next
        Case Else
            strMessage = "An unexpected error has occured. Error#" _
                            & Err & ": " & Error
            MsgBox strMessage, vbCritical, MESSAGE_CAPTION
            Resume Exit_ExportContactsTable
    End Select

End Sub

Function boolCheckName(strName As String, colItems As Items) _
        As Boolean

    Dim varSearchItem As Variant
    Dim strMessage As String
    
    If Len(strName) = 0 Then
        strMessage = "This record is missing a full name. "
        strMessage = strMessage & "Do you want to add it anyway?"
        If MsgBox(strMessage, vbYesNo, MESSAGE_CAPTION) = vbYes Then
            boolCheckName = True
        Else
            boolCheckName = False
        End If
    Else
        'Find the first item that has a FullName equal to strName. If no
        'item is found, varSearchItem wil be equal to Nothing.
        Set varSearchItem = colItems.Find("[FullName] = """ & strName & """")
        If varSearchItem Is Nothing Then
            boolCheckName = True
        Else
            strMessage = "A contact named " & strName & " already exists. "
            strMessage = strMessage & _
                        "Do you want to add this contact anyway?"

            If MsgBox(strMessage, vbYesNo, MESSAGE_CAPTION) = vbYes Then
                boolCheckName = True
            Else
                boolCheckName = False
            End If
        End If
    End If
End Function

Creating Mailing Labels from an Outlook Contact List Using Word

This section shows you how to create mailing labels from an Outlook Contact list using the MailMerge object in Word. Word recognizes a wide variety of mailing labels. These label types are identified by string names. You can get a list of the label types available by clicking Envelopes and Labels on the Tools menu, clicking the Labels tab, clicking Options, then examining the Product number list box.

The CreateContactsLabels procedure, shown below, creates the mailing labels. It first inserts text and placeholder strings into a document. It calls the subroutine FormatRange to prepare a Range object with the fields needed for the mailing labels. FormatRange is sent a MailMergeFields collection object. It finds and replaces each placeholder string, phField, with the appropriate mail merge field. Using placeholders guarantees that the MailMerge fields are inserted exactly where you want them.

The CreateContactLabels procedure then stores the range as an AutoText entry. It uses the CreateNewDocument method of the MailingLabel object to create the mailing labels based on the AutoText entry.

The CreateContactLabels procedure also shows how the DataSource object can be used to filter or sort records. This object's QueryString property is filled with an SQL string before the MailMerge object is executed.

When you call the CreateContactLabels procedure, you need to supply a string that names the specific label type. For example, to create Avery 5160 labels, use the following code:

CreateContactsLabels "5160"

The sample code for this section is in the template WrdSamp.dot. To run the sample code, copy WrdSamp.dot to your Office Templates directory, create a new document based on the WrdSamp.dot template, and click Quick Labels on the Tools menu. Choose a label from the drop-down list box, and then click Create Labels.

Note   Because CreateContactsLabels works with the MailMerge object, it can create mailing labels from the Outlook Contacts folder without a reference to the Outlook object library.

Public Sub CreateContactsLabels(strLabelName As String)

    Dim docMergeDoc As Document
    Dim rngRange As Range
    Dim strSQL As String
    Dim intCurrentField As Integer
    Dim strMessage As String
    
    Const MESSAGE_CAPTION = "Creating Mailing Labels for Contacts"
    Const LABEL_NOT_FOUND = 5843

    On Error GoTo Err_CreateContactsLabels

    'Add a new document and set a reference to it.
    Set docMergeDoc = Documents.Add
    
    With docMergeDoc.MailMerge
        'Set values for mailing labels mail merge based on
        'Outlook Address Book (olk).
        .MainDocumentType = wdMailingLabels
        .UseAddressBook Type:="olk"
        
        'Prepare a range with string placeholders (phField) for MailMerge 
        'fields.
        Set rngRange = docMergeDoc.Range
        With rngRange
            .InsertAfter "phField phField"
            .InsertParagraphAfter
            .InsertAfter "phField"
            .InsertParagraphAfter
            .InsertAfter "phField, phField  phField"
        End With
        
        'Add the MailMerge fields calling FormatRange.
        FormatRange .Fields
                    
        'Copy the range to an AutoTextEntry.
        NormalTemplate.AutoTextEntries.Add "LabelText", rngRange
            
        'Create a mailing label template using AutoTextEntry.
        Application.MailingLabel.CreateNewDocument Name:=strLabelName, _
                                Address:="", AutoText:="LabelText"
               
        .Destination = wdSendToNewDocument
        .SuppressBlankLines = True
 
        With .DataSource
            strSQL = "SELECT * FROM " & .Name
            strSQL = strSQL & " ORDER BY Last_Name"
            .QueryString = strSQL
            .FirstRecord = wdDefaultFirstRecord
            .LastRecord = wdDefaultLastRecord
        End With
        .Execute
        
        'Close docMergeDoc without saving changes. 
        docMergeDoc.Close SaveChanges:=wdDoNotSaveChanges
    End With
    
    'The AutoTextEntry is no longer needed so delete it.
    NormalTemplate.AutoTextEntries("LabelText").Delete
    
    'Activate and save the labels. Microsoft Word adds the new
    'document to the beginning of the Documents collection. 
    Documents(1).Activate
        With Dialogs(wdDialogFileSaveAs)
            .Name = "ContactLabels.doc"
            .Show
        End With
    
Exit_CreateContactsLabels:
    On Error Resume Next
    
    Set rngRange = Nothing
    Set docMergeDoc = Nothing
        
    Exit Sub    
Err_CreateContactsLabels:
    If Err = LABEL_NOT_FOUND Then
        strMessage = "'" & strLabelName & "' is not a recognized label name!"
    Else
        strMessage = "An unexpected error, #" & Err & " : " & Error _
                        & " has occured."
    End If
    MsgBox strMessage, vbCritical, MESSAGE_CAPTION
    Resume Exit_CreateContactsLabels

End Sub

The FormatRange procedure is called by CreateContactLabels to replace the string placeholders with mail merge fields.

Private Sub FormatRange(mgfFields As MailMergeFields)

    Dim strFieldName As String
    Dim intCurrentField As Integer
    Dim rngRange As Range
    Dim docMergeDoc As Document
    
    Set docMergeDoc = mgfFields.Parent.Parent
  
    For intCurrentField = 0 To 5
        Set rngRange = docMergeDoc.Range
        
        'Look for phField.
        With rngRange.Find
            .MatchWholeWord = True
            .Execute FindText:="phField"
        
            'If phField is found, use intCurrentField to determine which      
            'field to insert, then add the field.
            If .Found Then
                Select Case intCurrentField
                    Case 0
                        strFieldName = "First_Name"
                    Case 1
                        strFieldName = "Last_Name"
                    Case 2
                        strFieldName = "Street_Address"
                    Case 3
                        strFieldName = "City"
                    Case 4
                        strFieldName = "State_or_Province"
                    Case 5
                        strFieldName = "Postal_Code"
                End Select
                mgfFields.Add Range:=rngRange, Name:=strFieldName
            End If
        End With
    Next intCurrentField
       
    Set rngRange = Nothing
    Set docMergeDoc = Nothing
End Sub

Creating a Presentation from a Microsoft Excel Workbook

This section shows how you can convert a Microsoft Excel workbook into a PowerPoint presentation. The following sample code creates a presentation that contains a title page and all the worksheets and charts in the workbook from which the code is run. The bulk of the code is found in the CreateXLPowerPointPresentation procedure. This procedure creates the PowerPoint presentation and applies a template.

Each worksheet or chart is added to a new slide in the following manner:

Note   The Copy method of a Worksheet object creates a new workbook when called without arguments.

The CreateXLPowerPointPresentation procedure calls a function, strTemplateGet, to get the full name and path of a template. This template is then applied to the presentation. Examining the code in this function goes beyond the scope of this article, but the code is included in the sample files.

The code for this sample is found in the modPPTPresentation module in XLSamp.xls. To run it, open XLSamp.xls, then click Convert To Presentation on the Tools menu.

Note   To use this code, you must reference the Microsoft PowerPoint 8.0 Object Library.

Public Sub CreateXLPowerPointPresentation()

    Dim oPowerPoint As New PowerPoint.Application
    Dim pptPresentation As Presentation
    Dim pptSlide As Slide
    Dim ws As Worksheet
    Dim ch As Chart
    Dim wkb As Workbook
    Dim strTempWKB As String
    Dim strMeadowTemplate As String
    Dim strMessage As String
    
    On Error GoTo Err_CreateXLPowerPointPresentation
    
    Const MESSAGE_CAPTION = "Creating a PowerPoint Presentation"
    
    'Build name of temporary Workbook.
    With Application
        strTempWKB = .Path & .PathSeparator & "TempWKB.xls"
    End With
    
    'Create a new Presentation and add a title slide.
    Set pptPresentation = oPowerPoint.Presentations.Add
    With pptPresentation.Slides
        Set pptSlide = .Add(.Count + 1, ppLayoutTitleOnly)
        pptSlide.Shapes.Title.TextFrame.TextRange.Text = "My Presentation"

        'Place each worksheet in a slide.
        For Each ws In ThisWorkbook.Worksheets

            'Copy sheet to temporary Workbook. Copy creates a new workbook
            'and makes it the active workbook.
            ws.Copy
            Set wkb = ActiveWorkbook
            wkb.SaveAs strTempWKB

            'The numbers used here are somewhat arbitrary.
            Set pptSlide = .Add(.Count + 1, ppLayoutBlank)
            pptSlide.Shapes.AddOLEObject Left:=120, Top:=110, _
                    Width:=480, Height:=320, _
                    FileName:=strTempWKB, _
                    Link:=msoFalse

            'Close temporary Workbook and delete it.
            wkb.Close SaveChanges:=msoFalse
            Kill strTempWKB

        Next ws

        'Place each chart in a slide.
        For Each ch In ThisWorkbook.Charts

            'Copy chart to temporary Workbook.
            ch.Copy
            Set wkb = ActiveWorkbook
            wkb.SaveAs strTempWKB
            Set pptSlide = .Add(.Count + 1, ppLayoutBlank)
            pptSlide.Shapes.AddOLEObject Left:=120, Top:=110, _
                    Width:=480, Height:=320, _
                    FileName:=strTempWKB, _
                    Link:=msoFalse

            'Close temporary Workbook and delete it.
            wkb.Close SaveChanges:=msoFalse
            Kill strTempWKB
        Next ch
    End With

    'Apply meadow template if successfully found.
    strMeadowTemplate = strTemplateGet("Meadow")
    If Len(Dir(strMeadowTemplate)) > 0 Then
        pptPresentation.ApplyTemplate strMeadowTemplate
    End If

    oPowerPoint.Visible = msoTrue
    
Exit_CreateXLPowerPointPresentation:
    On Error Resume Next
    
    Set oPowerPoint = Nothing
    Set pptPresentation = Nothing
    Set pptSlide = Nothing
    
    Exit Sub    
Err_CreateXLPowerPointPresentation:
    strMessage = "An unexpected error has occured. Error#" _
                    & Err & ": " & Error
    MsgBox strMessage, vbCritical, MESSAGE_CAPTION
    Resume Exit_CreateXLPowerPointPresentation
    
End Sub

Personalizing a Presentation for a Contact List

This section illustrates how you can personalize a PowerPoint presentation for your Outlook contacts, which can be an effective sales tool. The sample code below iterates through your Outlook Contacts folder and copies a PowerPoint presentation with a customized title slide for each contact. It then either e-mails the personalized presentation to the contact or saves the message in your Inbox so you can add text and send it later. This code can be run from a Microsoft Excel, Word, or Access module.

The procedure, PersonalizePresentation, takes two arguments: strFileName, which is the name of a presentation, and boolSendNow, a flag that indicates whether to send the presentations immediately or save them in the Inbox. The procedure opens the presentation and points a variable, txrRange, to the text of the title on the first slide. Next, it iterates through the Contacts folder and adds each Contact's full name to txrRange and saves each modified presentation as contact name.ppt. If the contact has an e-mail address, the procedure creates a MailItem and saves the personalized presentation as an attachment in your Inbox or sends it, depending on the option selected.

The code for this sample is in the modPersonalize module in XLSamp.xls. To run it, open XLSamp.xls and click Personalize Presentation on the Tools menu. When prompted for a presentation, browse to Sample.ppt.

Note   To use this code in your own Microsoft Excel project, you must reference both the both Microsoft PowerPoint 8.0 Object Library and the Microsoft Outlook 8.0 Object.

Note that txrRange is declared as PowerPoint.TextRange because the application running this code may also have a TextRange object.

Public Sub PersonalizePresentation(strFileName As String, _
            boolSendNow As Boolean)

    Dim oPowerPoint As New PowerPoint.Application
    Dim oOutlook As New Outlook.Application
    Dim pptPresentation As Presentation
    Dim txrRange As PowerPoint.TextRange
    Dim intCounter As Integer
    Dim mitMailItem As MailItem
    Dim strNewFile As String
    Dim strEMailName As String
    Dim strMessage As String
    Dim strPath As String
    Dim lngSendNow As Long
    
    Const ERR_INVALID_PRESENTATION = 245755
    Const MESSAGE_CAPTION = "Personalizing a PowerPoint Presentation"
    On Error GoTo Err_PersonalizePresentation
    
    'Check to see if the file exists.
    If Len(Dir(strFileName, vbNormal)) > 0 Then
        oPowerPoint.Visible = msoTrue
        Set pptPresentation = oPowerPoint.Presentations.Open(strFileName)
        strPath = pptPresentation.Path
        
        Set txrRange = pptPresentation.Slides(1).Shapes(1) _
                        .TextFrame.TextRange
        
        'Open the Contacts folder.
        With oOutlook.GetNamespace("MAPI"). _
            GetDefaultFolder(olFolderContacts).Items
    
            'Add Contact name to TextRange and save new Presentation.
            For intCounter = 1 To .Count
                txrRange.Text = .Item(intCounter).FullName _
                                    & "'s Presentation"

                strNewFile = strPath & _
                Application.PathSeparator & _
                        .Item(intCounter).FullName & ".ppt"
    
                pptPresentation.SaveAs strNewFile
    
                'Send Presentation as Attachment if Contact has e-mail
                'address.
                strEMailName = .Item(intCounter).Email1Address
                If Len(strEMailName) > 0 Then
                    Set mitMailItem = oOutlook.CreateItem(olMailItem)
                    With mitMailItem
                        .Attachments.Add strNewFile
                            .Recipients.Add strEMailName
                            .Subject = "Customized Presentation"
                            If boolSendNow Then
                                .Send
                             Else
                                .Save
                            End If
                    End With
                End If
            Next intCounter
        End With
    Else
        strMessage = "File not found!"
        MsgBox strMessage, vbCritical, MESSAGE_CAPTION
    End If
    
Exit_PersonalizePresentation:
    On Error Resume Next
    
    oPowerPoint.Quit
    Set oPowerPoint = Nothing
    Set pptPresentation = Nothing
    Set txrRange = Nothing
    Set oOutlook = Nothing
    
    Exit Sub
Err_PersonalizePresentation:
    If vbObjectError - Err = ERR_INVALID_PRESENTATION Then
        strMessage = "PowerPoint cannot open this file!"
    Else
        strMessage = "An unexpected error, #" & Err & " : " & _
                        Error & " has occured."
    End If
    
    MsgBox strMessage, vbCritical, MESSAGE_CAPTION
    Resume Exit_PersonalizePresentation

    
End Sub

Exporting Outlook Journal Entries to a Microsoft Access Table

This section shows how you can export information stored in an Outlook Journal folder into a Microsoft Access table. This can be useful if you are using the Journal folder in Outlook to keep a history of a project. You can store this information in Microsoft Access, where you can sort and view it in several ways.

The following code sample assumes that you have two tables, Projects and ProjectHistory, in a Microsoft Access database. The first table contains general information about a project and the second table contains details on the progress of a project. For the purposes of the code, the Project table has at least three fields: ProjectName, ProjectId, and LastUpdated. It also has an index called Subject on the ProjectName field. The ProjectName corresponds to the Subject field of an Outlook JournalItem. The ProjectHistory table requires the fields ProjectId (the foreign key), DetailDateTimeStamp, and DetailDuration.

The UpdateProjectHistory procedure is passed the name of a project. (Note that the name of a project must correspond to a subject in an Outlook JournalItem.) The procedure opens the Journal folder and retrieves only the items for that project, using the Restrict method of the JournalItems collection. The procedure then checks to see if the name passed to it is in the Projects table. If the project is new, the project name won't be found, so the procedure adds the project to the table.

Next, the procedure retrieves the date from the projects LastUpdated field and stores it in dteUpdated. If it does not find a date, the procedure assigns 1/1/95 to dteUpdated, which insures that all the JournalItems will be seen as new (assuming there are no JournalItems older than 1/1/95). Next, the procedure iterates through these items. If a JournalItem has a CreationTime greater than the project's LastUpdated date, then the information in this item is added as a new record in the ProjectHistory table.

AccSamp.mdb contains the sample code, as well as the two tables needed to run this solution. The code is found in the modProjectHistory module. To run the code, click Update Project in the Samples form. When prompted for project, use a name from the Subject field of your Journal.

Note   To use this code from a Microsoft Access module, you must reference the Microsoft Outlook 8.0 Object Library.

Sub UpdateProjectHistory(strSubject As String)

    Dim tblProjects As Recordset
    Dim tblDetails As Recordset
    Dim dbs As Database
    Dim lngProjectId As Long
    Dim oOutlook As New Outlook.Application
    Dim colItems As Items
    Dim intCtr As Integer
    Dim dteUpdated As Date
    Dim strMessage As String
    
    Const MESSAGE_CAPTION = "Updating Project History"

    On Error GoTo Err_UpdateProjectHistory
    
    'Get all JournalItems for project.
    Set colItems = oOutlook.GetNamespace("MAPI"). _
                GetDefaultFolder(olFolderJournal). _
                Items.Restrict("[Subject] = '" & strSubject & "'")
                
    'Check to see if there are any Journal items. If there
    'are no Journal items, then display a message and
    'exit.
    If colItems.Count > 0 Then

        Set dbs = CurrentDb
    
        'Open tables and search for subject in Projects.
        Set tblProjects = dbs.OpenRecordset("Projects")
        Set tblDetails = dbs.OpenRecordset("ProjectHistory")
        
        'Seek is used because it is fast. It has the disadvantage
        'that it will not work on an attached table.
        tblProjects.Index = "Subject"
        tblProjects.Seek "=", strSubject
    
        'If there is no match, add new record and set the
        'recordset's Bookmark property to LastModified to move to
        'that record.
        With tblProjects
            If .NoMatch Then
                .AddNew
                tblProjects!Subject = strSubject
                .Update
                .Bookmark = .LastModified
            End If
        End With
    
        'Get the ProjectId from the current record.
        lngProjectId = tblProjects!SubjectId
    
        'If the LastUpdated field is null, assign dteUpdated an early
        'date to use all records. Otherwise assign LastUpdated to
        'dteUpdated.
        If IsNull(tblProjects!LastUpdated) Then
            dteUpdated = #1/1/95#
        Else
            dteUpdated = tblProjects!LastUpdated
        End If
    
        'Add details if there are any that are dated later than dteUpdated.
        If colItems.Count > 0 Then
            With tblDetails
                For intCtr = 1 To colItems.Count
                    If CDate(colItems(intCtr).CreationTime) > dteUpdated Then
                        .AddNew
                        tblDetails!SubjectId = lngProjectId
                        tblDetails!DateTimeStamp = colItems(intCtr). _
                                                    CreationTime
    
                        tblDetails!Duration = colItems(intCtr).Duration
                        .Update
                    End If
                Next intCtr
                .Close
            End With
            'Update LastUpdated field.
            With tblProjects
                .Edit
                tblProjects!LastUpdated = Now
                .Update
                .Close
            End With
        End If

        strMessage = "Project successfully updated."
        MsgBox strMessage, vbOKOnly, MESSAGE_CAPTION

    Else
        strMessage = "Project not found!"
        MsgBox strMessage, vbCritical, MESSAGE_CAPTION
    End If
    
Exit_UpdateProjectHistory:
    On Error Resume Next
    
    Set oOutlook = Nothing
    Set tblProjects = Nothing
    Set tblDetails = Nothing
    Set dbs = Nothing
    
    Exit Sub    
Err_UpdateProjectHistory:
    strMessage = "An unexpected error, #" & Err & " : " & _
                        Error & " has occured."
   
    MsgBox strMessage, vbCritical, MESSAGE_CAPTION
    Resume Exit_UpdateProjectHistory
   
End Sub

Creating a Web Presentation from a Word Document Using PowerPoint

This section shows how you can use features in PowerPoint to convert a Word document into a Web site. You first convert the Word document into a PowerPoint presentation. Then PowerPoint creates a Web site that functions like a PowerPoint presentation.

It's easy to convert a Word document to a presentation if you have organized the document with headings, but what if your Word document is divided into sections? The following code, run from Word, places each section on a slide and then converts the presentation to a Web site using the PowerPoint Web Wizard. The procedure, ConvertToPPTWeb, uses the Save as HTML command (File menu) to launch the PowerPoint Web Wizard.

The ConvertToPPTWeb procedure calls a function, strTemplateGet, to get the full name and path of a template. This template is then applied to the presentation. Examining the code in this function goes beyond the scope of this article, but the code is included in the sample files.

The sample code is found in WrdSamp.dot and Sections.doc is a Word document that has been divided into sections. To run the sample code, copy WrdSamp.dot to your Office Templates directory, create a new document based on the WrdSamp.dot template, and click Convert to PPT Web on the Tools menu. Browse to Sections.doc and click Open.

The HTML files created by the wizard are saved in a subfolder named Presentationx under the location you specified. To see the Web presentation, look in this folder and open Index.htm with your browser.

Note   To run this example in your own project, you must reference the Microsoft PowerPoint 8.0 Object Library.

Public Sub ConvertToPPTWeb(strName As String)

    Dim docWebBase As Document
    Dim secSection As Section
    Dim rngRange As Range
    Dim docTemp As Document
    Dim oPowerpoint As New PowerPoint.Application
    Dim pptPresentation As Presentation
    Dim pptSlide As Slide
    Dim strTempDoc As String
    Dim strMessage As String
    Dim rngHeading As Range
    Dim strHeading As String
    Dim strTemplate As String
    
    Const MESSAGE_CAPTION = "Converting Word Document to Web Presentation"
    Const FILE_MENU = 1
    Const SAVE_AS_HTML = 6
    
    'On Error GoTo Err_ConvertToPPTWeb
    
    With Application
        strTempDoc = .Path & .PathSeparator & "TempDoc.doc"
    End With

    'Open the Word document.
    Set docWebBase = Documents.Open(strName)
    With oPowerpoint
        Set pptPresentation = .Presentations.Add

        'Iterate through sections.
        With pptPresentation.Slides
            For Each secSection In docWebBase.Sections
                Set rngRange = secSection.Range
                rngRange.Copy

                'Create a temporary document for each section.
                Set docTemp = Documents.Add
                Set rngRange = docTemp.Range
                rngRange.Paste
                
                'Go to the first heading.
                Set rngHeading = docTemp.GoTo(What:=wdGoToHeading, _
                                    Which:=wdGoToFirst)
                
                'Expand the range to include the whole heading.
                rngHeading.Expand wdParagraph
                
                'Make sure heading is Heading 1. If it is not,
                'create a heading.
                If rngHeading.Style = "Heading 1" Then
                    strHeading = rngHeading.Text
                    rngHeading.Delete
                Else
                    strHeading = "Slide " & (.Count + 1)
                End If
                    
                docTemp.SaveAs strTempDoc

                Set pptSlide = .Add(.Count + 1, ppLayoutTitleOnly)
                
                'Fill title with the heading.
                pptSlide.Shapes(1).TextFrame.TextRange = strHeading
                
                'The numbers here are arbitrary and should be based
                'on the dimensions of the document sections.
                pptSlide.Shapes.AddOLEObject Left:=30, Top:=80, _
                            Width:=640, Height:=420, _
                            FileName:=strTempDoc, _
                            Link:=msoFalse

                'Close and delete temporary file.
                docTemp.Close wdDoNotSaveChanges
                Kill strTempDoc
            Next secSection
        End With
        
        'Apply Contemporary template if successfully found.
        strTemplate = strTemplateGet("Contemporary")
        If Len(Dir(strTemplate)) > 0 Then
            pptPresentation.ApplyTemplate strTemplate
        End If
        
        docWebBase.Close
        .Visible = msoTrue
        
        'Execute File, Save as HTML.
        .CommandBars("Menu Bar").Controls(FILE_MENU). _
                        Controls(SAVE_AS_HTML).Execute

    End With
    
Exit_ConvertToPPTWeb:
    On Error Resume Next
    
    Set docWebBase = Nothing
    Set secSection = Nothing
    Set rngRange = Nothing
    Set docTemp = Nothing
    Set rngHeading = Nothing
    Set oPowerpoint = Nothing
    Set pptPresentation = Nothing
    Set pptSlide = Nothing
    
    Exit Sub
Err_ConvertToPPTWeb:
    If Err = 5174 Or Err = 5273 Then
        strMessage = "Unable to locate file!"
    Else
        strMessage = "An unexpected error, #" & Err & " : " & _
                        Error & " has occured."
    End If
    MsgBox strMessage, vbCritical, MESSAGE_CAPTION
    Resume Exit_ConvertToPPTWeb

End Sub

Inserting a URL list from a Microsoft Access Table into a Word Document

This section offers an example of inserting a URL list, stored in Microsoft Access, into a Word document. Managing URLs can be difficult. If you have stored URLs in a Microsoft Access table in such a way that they can be easily grouped, you may want to be able to fetch one of these groups and insert them into your Word document.

The following sample procedure, InsertURLs, inserts URLs into a range. It takes three arguments: the full name of a database, the category of URLs to be fetched, and a Range object. It is assumed that the database contains a table named URL with a URL field and a Category field. The URL field stores its data using the Microsoft Access Hyperlink data type. Microsoft Access stores a hyperlink as text followed by an address enclosed in pound signs. For example, www.microsoft.com is stored as

 www.microsoft.com#http://www.microsoft.com#.

The InsertURLs procedure parses this string obtaining the anchor text and the address. It then adds the hyperlink to the range's Hyperlink collection. You can insert the hyperlinks at the current selection by setting a Range variable to Selection and calling InsertURLs with the proper arguments.

The following sample can be run from a Word module. The code is in WrdSamp.dot and the table of URLs is in AccSamp.mdb. To run the sample code, copy WrdSamp.dot to your Office Templates directory, create a new document based on the WrdSamp.dot template, and click Insert URLs on the Tools menu. Browse to AccSamp.mdb and enter Office 97 in the Category text box, then click OK.

Note   To run this example, you must reference the Microsoft DAO 3.5 Object Library.

Public Sub InsertURLs(strDatabase As String, strCategory As String, _
                        rngRange As Word.Range)

    Dim dbs As Database
    Dim dynURLs As Recordset
    Dim strSQL As String
    Dim varURLs As Variant
    Dim strAddress As String
    Dim strAnchor As String
    Dim strMessage As String
    
    Const MESSAGE_CAPTION = "Inserting URLs in a Word Document"
    
    On Error GoTo Err_InsertURLs
    
    'Fetch hyperlinks.
    Set dbs = DBEngine.Workspaces(0).OpenDatabase(strDatabase)

    'Build SQL.
    strSQL = "SELECT URL FROM URLs "
    strSQL = strSQL & "WHERE Category=""" & strCategory & """;"

    Set dynURLs = dbs.OpenRecordset(strSQL, dbOpenDynaset)

    'Iterate through and parse URLs.
    Do Until dynURLs.EOF
        varURLs = dynURLs!URL
        strAddress = Mid(varURLs, InStr(1, varURLs, "#") + 1, _
                    Len(varURLs) - 1)

        strAnchor = Left(varURLs, InStr(1, varURLs, "#") - 1)

        'Add URL to range.
        With rngRange
            .InsertAfter strAnchor
            .Hyperlinks.Add Anchor:=rngRange, Address:=strAddress
            .Collapse wdCollapseEnd
            .InsertParagraph
            .Collapse wdCollapseEnd
            dynURLs.MoveNext
        End With
    Loop

    dynURLs.Close
    dbs.Close
    
Exit_InsertURLs:
    On Error Resume Next
    
    Set dynURLs = Nothing
    Set dbs = Nothing
    
    Exit Sub
Err_InsertURLs:
    strMessage = "An unexpected error, #" & Err & " : " & _
                        Error & " has occured."
    
    MsgBox strMessage, vbCritical, MESSAGE_CAPTION
    Resume Exit_InsertURLs

End Sub

Inserting a Microsoft Excel Value into a Word Bookmark

This section shows how you can read values from a Microsoft Excel worksheet and insert them as Word bookmarks. The following sample procedure, FillBookmarks, iterates through the Cells in a Range and inserts their values into bookmarks in a Word document. The FillBookmarks procedure opens a Word document and then iterates through the cells in the range passed to it. It increments the bookmark index, lCurrentIndex, and, as long as it does not run out of bookmarks, it inserts the value of the cell at the bookmark.

The code for this sample is found in the modBookmarks module in XLSamp.xls. To run it, open XLSamp.xls, then click Insert Range into Bookmarks on the Tools menu. When prompted for a document, browse to BkMks.doc.

Note   To run this example, you must reference the Microsoft Word 8.0 Object Library.

Public Sub FillBookMarks(rngRange As Excel.Range, strFileName As String)

    Dim docDocument As Document
    Dim celCell As Variant
    Dim oWord As New Word.Application
    Dim lCurrentIndex As Long
    Dim strInsert
    Dim strMessage As String

    Const MESSAGE_CAPTION = "Inserting Bookmarks"
    
    On Error GoTo Err_FillBookMarks

    'Initialize index.
    lCurrentIndex = 1

    'Open Document.
    With oWord
        Set docDocument = .Documents.Open(FileName:=strFileName)
    
        'Show changes.
        .Visible = True
        .Activate
        .WindowState = wdWindowStateMaximize
    End With
    

    'Iterate through Range cells adding values to Bookmarks.
    With docDocument.Bookmarks
        For Each celCell In rngRange.Cells
            'Make sure you have not run out of Bookmarks.
            If lCurrentIndex <= .Count Then
                strInsert = celCell.Value
                .Item(lCurrentIndex).Range.InsertAfter strInsert
            End If
            lCurrentIndex = lCurrentIndex + 1
        Next celCell
    End With
    
Exit_FillBookMarks:
    On Error Resume Next
    
    Set docDocument = Nothing
    Set oWord = Nothing
    
    Exit Sub
Err_FillBookMarks:
    strMessage = "An unexpected error, #" & Err & " : " & _
                        Error & " has occured."
    
    MsgBox strMessage, vbCritical, MESSAGE_CAPTION
    Resume Exit_FillBookMarks


    
End Sub

Additional Resources

To learn more about cross-application automation, see the Microsoft Office 97/Visual Basic Programmer's Guide (Microsoft Press), or the online version at http://msdn.microsoft.com/library/officedev/office/web/toc/fulltoc.htm, and the VBA Developer's Handbook by Ken Getz and Mike Gilbert (Sybex Inc., 1997).