Microsoft Office 2000/Visual Basic Programmer's Guide   

Creating an Object Variable to Automate Another Office Application

Working with the objects in another Office application through VBA code is very similar to using code to work with the objects within the code's host application. In most cases, you begin by creating an object variable that points to the Application object representing the Office application that contains the objects you want to work with. In general, you create an early-bound object variable by using the New keyword. However, there are limited circumstances where you may choose to use the CreateObject or GetObject function to create an object variable. For more information, see "Using the CreateObject and GetObject Functions" later in this chapter.

When you write VBA code in an application that manipulates objects within that same application, the reference to the Application object is implicit. When you are automating another application, the reference to the Application object generally must be explicit. The following two examples illustrate this difference. The first example contains VBA code intended to be run in Word. The second example contains VBA code intended to be run from another Office application (or any application that supports Automation through VBA). For the second example to work, a reference must be set to the Microsoft Word 9.0 object library in the application the code is run from.

Sub CodeRunningInsideWord()
   Dim docNew As Word.Document

   ' Add new document to Documents collection.
   Set docNew = Documents.Add
   ' Type text into document.
   Selection.TypeText "Four score and seven years ago"
   ' Display document name and count of words, and then close document without
   ' saving changes.
   With docNew
      MsgBox "'" & .Name & "' contains " & .Words.Count & " words."
      .Close wdDoNotSaveChanges
   End With
   Set docNew = Nothing
End Sub

The CodeRunningInsideWord procedure is available in the modSetObjVariable module in Automating&IDE.doc in the ODETools\V9\Samples\OPG\Samples\CH04 subfolder on the Office 2000 Developer CD-ROM.

Sub CodeRunningOutsideWord()
   Dim wdApp      As Word.Application
   Dim docNew   As Word.Document
   
   ' Create new hidden instance of Word.
   Set wdApp = New Word.Application
   ' Create a new document.
   Set docNew = wdApp.Documents.Add
   ' Add text to document.
   wdApp.Selection.TypeText "Four score and seven years ago"
   ' Display document name and count of words, and then close
   ' document without saving changes.
   With docNew
      MsgBox "'" & .Name & "' contains " & .Words.Count & " words."
      .Close wdDoNotSaveChanges
   End With
   wdApp.Quit
   Set wdApp = Nothing
End Sub

The CodeRunningOutsideWord procedure is available in the modGetRecords module in AutomatingWord.xls in the ODETools\V9\Samples\OPG\Samples\CH04 subfolder on the Office 2000 Developer CD-ROM.

In most cases, you will create an object variable that refers to the top-level object representing the application you want to access through Automation, the Application object. Once you have the reference to the Application object, you use additional references to that object's child objects to navigate to the object or method you want to manipulate. You assign object variables to child objects by using a method of a higher-level object with the Set statement.

However, Excel and Word also allow you to create a top-level reference to certain child objects of the Application object. For this reason, it is possible to rewrite the previous CodeRunningOutsideWord procedure to start from a reference to a Word Document object, like this:

Sub CodeRunningOutsideWord2()
   Dim docNew As Word.Document
   
   Set docNew = New Word.Document
   Set docNew = Documents.Add
   ' The following line uses the Application property to access the
   ' implicit instance of the Word Application object.
   docNew.Application.Selection.TypeText "Four score and seven years ago"
   With docNew
      MsgBox "'" & .Name & "' contains " & .Words.Count & " words."
      .Close wdDoNotSaveChanges
   End With
   docNew.Application.Quit
   Set docNew = Nothing
End Sub

The CodeRunningOutsideWord2 procedure is available in the modGetRecords module in AutomatingWord.xls in the ODETools\V9\Samples\OPG\Samples\CH04 subfolder on the Office 2000 Developer CD-ROM.

Similarly, Excel allows you to create a top-level reference starting from the Workbook object. You can do this in either of two ways:

 -or- 

To create a Workbook object either way, you must use the CreateObject function, because the Excel.Sheet and Excel.Chart class names don't support the New keyword. For example, to automate Excel starting with a top-level reference to a Workbook object that contains a single worksheet, use code like this:

Dim wbkSheet As Excel.Workbook
Set wbkSheet = CreateObject("Excel.Sheet")

To automate Excel starting with a top-level reference to a Workbook object that contains a worksheet with a chart and another worksheet containing a default data set for the chart, use code like this:

Dim wbkChart As Excel.Workbook
Set wbkChart = CreateObject("Excel.Chart")

When you are automating Word starting from a Document object or automating Excel starting from a Workbook object, an implicit reference is created to the Application object. If you need to access properties and methods of the Application object, you can use the Application accessor property of the Document or Workbook objects. While using the Document or Workbook objects as top-level objects may reduce the amount of code you have to write somewhat, in most cases your code will be easier to understand and more consistent if you start from a reference to the Application object.

The following table shows all the top-level Office objects you can reference and their class names.

Object type Class name
Access Application Access.Application
Office Binder OfficeBinder.Binder
Excel Application Excel.Application
Excel Workbook Excel.Sheet

Excel.Chart

FrontPage Application FrontPage.Application
Outlook Application Outlook.Application
PowerPoint Application PowerPoint.Application
Word Application Word.Application
Word Document Word.Document

You can see the complete object models for each Office application in the Microsoft Office 2000 Object Model Guide.

Automating the Visual Basic Editor

In addition to using code to work with other Office applications, you can also use Automation code to work with the objects exposed by the Visual Basic Editor's object model. You can use the Visual Basic Editor's object model to work with the objects in its user interface, such as its windows and command bars, which allows you to develop add-ins to customize and extend the Visual Basic Editor's user interface. Additionally, you can use the Visual Basic Editor's object model to work with your VBA project itself to add and delete references, to set and read project properties, and to work with the components that make up your project, such as standard modules, class modules, and UserForms. This feature allows you to write code to maintain references, to document and set properties for projects, and to work with existing components and add new ones.

To work with the Visual Basic Editor's objects, first you must establish a reference to its type library, which is named Microsoft Visual Basic for Applications Extensibility 5.3. To write code to work with the Visual Basic Editor, you must initialize a variable to work with the Visual Basic Editor's top-level object, the VBE object. However, you can't reference the VBE object directly. This is because the Visual Basic Editor isn't an independent application or service; it's running as part of the host application's process. To initialize an object variable to work with the Visual Basic Editor, you must use the VBE accessor property of the host application's Application object. The VBE property is available in all Office applications except Outlook. The following example shows how to initialize an object variable to work with the Visual Basic Editor:

Dim objVBE As VBIDE.VBE
Set objVBE = Application.VBE

To see code samples that use the Visual Basic Editor's object model to display VBA project property and component information, see modProjectInfo in Automating&IDE.doc in the ODETools\V9\Samples\OPG\Samples\CH04 subfolder on the Office 2000 Developer CD-ROM. For information about creating COM add-ins for the Visual Basic Editor, see Chapter 11, "Add-ins, Templates, Wizards, and Libraries." For an overview of working with the Visual Basic Editor's object model, see the Visual Basic Language Developer's Handbook by Ken Getz and Mike Gilbert (Sybex, 1999).

Note   The Access Application object provides a References collection and Reference object that allow you to work with references in an Access VBA project without requiring you to establish a reference to the Microsoft Visual Basic for Applications Extensibility 5.3 type library. To view a code sample, see the ReferenceInfo procedure in the modReferences module in Startup.mdb in the ODETools\V9\Samples\OPG\Samples\CH04 subfolder on the Office 2000 Developer CD-ROM. For more information about the Access References collection, search the Microsoft Access Visual Basic Reference Help index for "References collection."

Using the Set Statement and the New Keyword

You start Automation code by declaring object variables with a specific object type that represents the top-level object and then declaring any child objects you want to reference. You then create an instance of the top-level object by using the Set statement and the New keyword. However, the New keyword can't be used to create a new instance of a child object. To create an instance of a child object, use the appropriate method of the parent object along with the Set statement.

In the following example, the top-level Excel Application object variable is assigned by using the Set statement and the New keyword. The object variable representing the Workbook child object is assigned by using the parent object's Add method and the Set statement.

Sub CreateExcelObjects()
   Dim xlApp            As Excel.Application
   Dim wkbNewBook       As Excel.Workbook
   Dim wksSheet         As Excel.Worksheet
   Dim strBookName      As String
   
   ' Create new hidden instance of Excel.
   Set xlApp = New Excel.Application
   ' Add new workbook to Workbooks collection.
   Set wkbNewBook = xlApp.Workbooks.Add
   ' Specify path to save workbook.
   strBookName = "c:\my documents\xlautomation.xls"
   ' Loop through each worksheet and append " - By Automation" to the
   ' name of each sheet. Close and save workbook to specified path.
   With wkbNewBook
      For Each wksSheet In .Worksheets
         wksSheet.Name = wksSheet.Name & " - By Automation"
      Next wksSheet
      .Close SaveChanges:=True, FileName:=strBookName
   End With

   Set wkbNewBook = Nothing
   XlApp.Quit
   Set xlApp = Nothing
End Sub

The CreateExcelObjects procedure uses three Excel object variables, but only the first two are instantiated by using the Set statement. You do not need to use the Set statement to create an object variable that will be used only inside a For…Each loop. The CreateExcelObjects procedure is available in the modSetObjVariable module in Automating&IDE.doc in the ODETools\V9\Samples\OPG\Samples\CH04 subfolder on the Office 2000 Developer CD-ROM.

In the next example, the top-level Outlook Application object is created by using the Set statement and the New keyword. The MailItem child object variable is created by using the Application object's CreateItem method. The Recipient child object is created by using the Add method of the MailItem object's Recipients collection.

Sub CreateOutlookMail()
   Dim olApp                  As Outlook.Application
   Dim olMailMessage          As Outlook.MailItem
   Dim olRecipient            As Outlook.Recipient
   Dim blnKnownRecipient      As Boolean
   
   ' Create new instance of Outlook or open current instance.
   Set olApp = New Outlook.Application
   ' Create new message.
   Set olMailMessage = olApp.CreateItem(olMailItem)
   ' Prompt for message recipient, attempt to resolve address, and
   ' then send or display.
   With olMailMessage
      Set olRecipient = .Recipients.Add(InputBox("Enter name of message recipient", _
         "Recipient Name"))
      blnKnownRecipient = olRecipient.Resolve
      .Subject = "Testing mail by Automation"
      .Body = "This message was created by VBA code running " _
         & "Outlook through Automation."
      If blnKnownRecipient = True Then
         .Send
      Else
         .Display
      End If
   End With
   Set olMailMessage = Nothing
   olApp.Quit
   Set olApp = Nothing
End Sub

The CreateOutlookMail procedure is available in the modSetObjVariable module in Automating&IDE.doc in the ODETools\V9\Samples\OPG\Samples\CH04 subfolder on the Office 2000 Developer CD-ROM. Note that at the end of this procedure, each object variable is destroyed by explicitly setting it equal to the Nothing keyword. For more information about destroying object variables, see "Shutting Down an Object Created by Using Automation" later in this chapter.

Tip   You can also use the New keyword to create a new instance of the object at the same time you declare its object variable. For example:

Dim olApp As New Outlook.Application

If you do this, there is no need to use a Set statement to instantiate the object. However, this technique is not recommended because you have no control over when the object variable is created. For example, if your code needs to test to see if an object exists by using a statement such as If olApp Is Nothing Then, this test will return True if you have created an instance of the object in the Dim statement. Additionally, you may not need to use an object except at the user's request. If you create an instance of the object by using New in the Dim statement, the object will be created even if it isn't used. To maintain control over when an object is created, don't use the New keyword in the Dim statement, and instantiate the object by using a Set statement at the point in your code where you need to use the object.

Single-Use vs. Multi-Use Applications

Whether you return a reference to a new instance of the Application object or an existing instance depends on whether the application's default behavior is as a single-use or a multi-use application. A single-use application causes a new instance of that application to be created whenever an object variable is instantiated in any host application. For example, Microsoft Word is a single-use application, so the following code creates a new instance of Microsoft Word regardless of how many instances of Word may already be running:

Dim wdApp aAs Word.Application
Set wdApp = New Word.Application

A multi-use application allows host applications to share the same instance of the application. The next example creates a new instance of Microsoft Outlook only if Outlook is not running when the code is executed. Since Outlook is a multi-use application, if Outlook is already running when this code is run, the object variable points to the currently running instance.

Dim olApp As Outlook.Application
Set olApp = New Outlook.Application

The following table shows the default behavior for each Office application.

Application Application type
Access Single-use
Binder Single-use
Excel Single-use
FrontPage Single-use
Outlook Multi-use
PowerPoint Multi-use
Word Single-use

You can use the GetObject function to create an object variable that references a currently running instance of a single-use application.

If you create an object variable that points to a multi-use application (Outlook or PowerPoint) and an instance of the application is already running, any method you use to create the object variable will return a reference to the running instance. For example, if Outlook is already running, the following lines of code all return a reference to the same instance of Outlook:

Dim olApp1 As Outlook.Application
Dim olApp2 As Outlook.Application
Dim olApp3 As Outlook.Application

Set olApp1 = New Outlook.Application
Set olApp2 = CreateObject("Outlook.Application")
Set olApp3 = GetObject(, "Outlook.Application")

Using the CreateObject and GetObject Functions

You can use the Set statement with the CreateObject and GetObject functions to create a top-level object variable that represents an Office application. These functions should be used only in those situations where the New keyword does not provide the functionality you need.

You use the CreateObject function to create a top-level object variable that represents an Office application in the following two situations:

You can use the GetObject function in these situations:

Working with Documents That Contain Startup Code

Using Automation to open a document does not prevent a document's startup code from running. Startup code can be defined in various ways in Office applications, as explained in the following table.

Application Startup code location
Word Startup code is contained in the event procedures for the Open or New events in the ThisDocument module of a document or template.
Excel Startup code is contained in the event procedure for the Open event in the ThisWorkbook module of a workbook or template.
Outlook Startup code is contained in the event procedures for the Startup event in the ThisOutlookSession of the local Outlook VBA project.
Access If you create an Access macro named AutoExec, this macro's actions will run on startup.

You can also place startup code in the event procedure for the startup form's Open event. To specify a form to be opened on startup, use the Startup command on the Tools menu.


Note   PowerPoint and FrontPage documents don't have a way to define startup code.

Because startup code may display message boxes or modal forms that act as dialog boxes, these message or dialog boxes may prevent your code from proceeding until a user closes or responds to them. If you have startup code in an Excel workbook or Access database that you don't want to run if the document is opened programmatically from another application, you can often use the UserControl property of the Application object to determine how a document is being opened and then act accordingly. If you can't use the UserControl property, you may need to use a SendKeys statement to send keystrokes to close the message or dialog box.

In Excel, the UserControl property will return False only when the document or workbook is opened from Automation by using a hidden instance of the Excel Application object (Application.Visible = False). For example, the following code defined in an Excel workbook's Open event procedure will run only if the workbook is opened by a user or a visible instance of the Excel Application object. If you open the workbook by using a hidden instance of the Excel Application object from code running in another application, the message box won't be displayed.

Private Sub Workbook_Open()
   Dim strMsg As String
   
   strMsg = "This message was triggered by this workbook's " & _
          "Open event." & vbCrLf & _
          "It won't be displayed if this workbook " & _
          "is opened by using a hidden" & vbCrLf & _
          "instance of the Excel Application object " & _
          "from Automation code."
   
   ' If opened through Automation by using a hidden instance,
   ' the UserControl property will be False.
   If Application.UserControl = True Then
      MsgBox strMsg
   End If
End Sub

The Workbook_Open procedure is available in the ThisWorkbook module in AutomatingWord.xls in the ODETools\V9\Samples\OPG\Samples\CH04 subfolder on the Office 2000 Developer CD-ROM.

Note   In Word 2000 and Word 97, there is no way to prevent Open event code from running with the UserControl property. If Word is visible to the user, or if you call the UserControl property of a Word Application or Document object from within a Word code module, this property will always return True. However, you can still use the Word UserControl property from Automation code (that creates a hidden instance of Word) running from another application to determine if a document was opened programmatically or by the user.

In Access, you don't have to check or keep track of whether the instance of the Application object is hidden or visible because the UserControl property is False whenever the application is started from code. To control whether code in the startup form's Open event is executed, Access provides a Cancel argument for the Open event. As shown in the following example, you can set the Cancel argument to True to keep a startup form from opening if you open the database by using Automation code:

Private Sub Form_Open (Cancel As Integer)
   ' If database is opened from Automation, 
   ' cancel the Open event of the form.
   If Application.UserControl = False Then
      Cancel = True
   Else
   ' Any startup code that needs to run when the
   ' database is opened by a user goes here.
   End If
End Sub

The Form_Open procedure is available in the Form_frmStartup module in Startup.mdb in the ODETools\V9\Samples\OPG\Samples\CH04 subfolder on the Office 2000 Developer CD-ROM.

You can also use the UserControl property of the Access Application object to control whether actions in a database's AutoExec macro will run when the database is opened from another program by using Automation. To do this, you must enter Application.UserControl = True in the Condition column for each action you want to cancel. (To display the Condition column, click Conditions on the View menu.) To see an example of an AutoExec macro that cancels an action when the database is opened through Automation, open Startup.mdb in the ODETools\V9\Samples\OPG\Samples\CH04 subfolder on the Office 2000 Developer CD-ROM and then open the AutoExec macro in Design view.

Tip   You can also use COM add-ins to implement a startup form or code. COM add-ins support events that you can use to determine how an application was loaded before connecting the add-in. For more information about COM add-ins, see Chapter 11, "Add-ins, Templates, Wizards, and Libraries."