Automate Word from Other Applications





Automate Word from Other Applications

figs/moderate.gif figs/hack84.gif

Many of the same things VBA makes possible from within Word can be done from another application by using COM automation.

Word, like the rest of the Office suite, supports COM automation. COM (Component Object Model) is a technology developed by Microsoft that allows one application to control another without any regard to the differences in the programming languages used by either application. As long as both applications "speak" COM, they'll get along just fine.

Think about using an ATM. Each machine might be a different size, and sometimes the buttons are in different places, but you don't really care what the machine looks like, or how it works inside, as long as you can put in your card and get money. A COM server is like the ATM machine: as long as you (the application, or client) make a valid request for money (the service), the machine clicks and whirrs and spits out the cash. The client requesting the service cares only that the server respond in terms that it can use and understand.

Other applications that understand COM, such as Excel, or application development tools/languages such as C++, Visual Studio.NET, or even a scripting language like Perl, can use Word as a COM server and access its object model and control its behavior. And, conversely, if you create your own COM server application, you can use VBA to access it from within Word.

When controlling Word from another application, you can access familiar Word objects, such as paragraphs, comments, documents, and fields. These objects will, for the most part, behave the same way as they do in your Word macros. If you use another Office application to control Word, you will hardly notice a difference because the applications use the same objects and the same language (VBA) to control those objects. If you use a different language, you will need to determine how to best interact with Word's objects using that language. The following sections touch on each scenario.

1 Controlling Word from Another Office Application

The different parts of Microsoft Office play very well together. Controlling Word from within Excel, for example, isn't much different from working within Word. There's only one big difference: when you write a macro within Word, the parent Word.Application object is implicit. To display a dialog with the name of the active document from Word VBA, you can just use the following in your code (you can also type these statements directly into the Immediate window [Post #2]):

MsgBox ActiveDocument.Name

You could also explicitly specify that you want Word's ActiveDocument object, as in the following:

MsgBox Word.Application.ActiveDocument.Name

But that's unnecessary; because you're working in VBA within Word, it's assumed that unless you say otherwise, you're talking about Word's objects. And as long as Word is open, the parent Word object exists and is implicitly used in all your macros.

When you want to control Word from another Office application, such as Excel, you need to explicitly refer to the Word.Application object used from your Excel macro.

To incorporate Word into an Excel macro, first set a reference to Word from the Visual Basic Editor in Excel. Select ToolsReferences and choose the Microsoft Word Object Library, as shown in Figure.

Setting a reference to the Word object model from Excel's Visual Basic Editor
figs/wrdh_0908.gif


By setting this reference, you provide Excel with access to all the parts of Word you'd get from within Word itself, including object names and built-in Word constants.

The following Excel macro starts a new instance of Word and then inserts a single line of text.

Sub HelloFromExcel( )

Dim wd As Word.Application

Dim doc As Document



Set wd = New Word.Application

wd.Visible = True



Set doc = wd.Documents.Add

doc.Range.InsertAfter "Hello, Word"

doc.Range.Style = wdHeading1

End Sub

Since COM is designed as a means for two applications to communicate without an actual person involved, you need to use the Visible property to explicitly make Word visible on your screen. Otherwise, Word will still start and the macro will execute without your knowledge because it won't appear on your screen.

While experimenting with and developing macros that use Word as a COM server, you should always set the Visible property to True. Otherwise, you may end up with multiple instances of Word running in the background, which can really slow down a system. If you do choose to run Word invisibly, make sure you use the Quit method to close it. In the previous example, the penultimate line of code would read:

wd.Quit

You should also set the object references to Nothing. Just before the End Sub, add the following line:

Set wd = Nothing


The previous code created a new instance of Word, even if you already had the application open. To use the current instance of Word (or to open the application if no current instance is running), use the following version:

Sub HelloAlreadyOpenWordFromExcel( )

Dim wd As Word.Application

Dim doc As Document

On Error Resume Next

Set wd = Word.Application



If Err.Number = 429 Then

    Set wd = New Word.Application

    Err.Clear

ElseIf Err.Number <> 0 Then

    MsgBox Err.Number & vbCr & Err.Description

    Exit Sub

End If



wd.Visible = True

Set doc = wd.Documents.Add

doc.Range.InsertAfter "Hello, Word"

doc.Range.Style = wdStyleHeading1

End Sub

This version uses the knowledge that error number 429 occurs when a COM (also known as ActiveX) component can't be created, as shown in Figure. To determine an error number, you often need to let the error occur and then make a note of its number.

The same error is generated when VBA can't create a COM object
figs/wrdh_0909.gif


Setting a reference from within the Visual Basic Editor provides the best performance possible for automating Word from another application, because it takes advantage of early binding. In other words, much of the work that needs to be done for the two applications to communicate is done long before the macro runs. This preparation is similar to a cooking show where the host premeasures all the ingredients in little bowls before he "starts" cooking. Early binding is always preferable if possible.

If your macro needs to run on systems that might not have that reference to Word already set, you'll need to use late binding. With late binding, you use the generic Object variable type.

The following version of the HelloFromExcel macro can run even if no reference to Word has been set:

Sub HelloFromExcelLateBinding( )

Dim wd As Object

Dim doc As Object

On Error Resume Next

Set wd = GetObject(Class:="Word.Application")

If Err.Number = 429 Then

    Set wd = CreateObject(Class:="Word.Application")

    Err.Clear

ElseIf Err.Number <> 0 Then

    MsgBox Err.Number & vbCr & Err.Description

End If



wd.Visible = True

Set doc = wd.Documents.Add

doc.Range.InsertAfter "Hello, Word"

doc.Range.Style = doc.Styles("Heading 1")

End Sub

Notice that the code uses generic Object variables. Another important, but more subtle, difference is that without the reference set by early binding, you can't use Word's constants, like wdStyleHeading1, because those constants aren't defined in Excel. Instead, you must use the actual style names.

Without the reference set, you must do all of the prep work needed to get the two applications talking every time you run the macro. A macro that uses late binding will thus run more slowly than one using early binding.

2 Controlling Word from a Scripting Language

Upcoming hacks in this chapter cover the specifics for controlling Word from three popular scripting languages: Perl [Post #86], Python [Post #85], and Ruby [Post #87] . This section covers the similarities between the three.

Translating what you already know about automating Word with VBA for use in another language can present some challenges. The biggest challenge is extricating your knowledge of the Word object model from that of the VBA language. A Word object is a Word object whether you control it from VBA or Perl, but the way you control it may be very different.

For example, here's the HelloFromExcelLateBinding macro from the previous section, but this time the parts that are just Word objects, and not part of the VBA language, are shown in bold:

Sub HelloFromExcelLateBinding( )

Dim wd As Object

Dim doc As Object

On Error Resume Next

Set wd = GetObject(class:="Word.Application")

If Err.Number = 429 Then

    Set wd = CreateObject(class:="Word.Application")

    Err.Clear

ElseIf Err.Number <> 0 Then

    MsgBox Err.Number & vbCr & Err.Description

End If



wd.Visible = True

Set doc = wd.Documents.Add

doc.Range.InsertAfter "Hello, Word"

End Sub

You will be reusing the parts in bold when controlling Word from a scripting language with COM. The rest is specific to VBA and may not be the same in another language. Even the "dot" syntax (where properties and methods of an object are noted with a ".", as in Documents.Add) can't be taken for granted. The following Perl script does the same thing as the Excel macro shown above. Again, the Word-specific parts are shown in bold.

#!/usr/bin/perl



use Win32::OLE qw(in with);

use Win32::OLE::Variant;



my $word;

eval {$word = Win32::OLE->GetActiveObject('Word.Application')};

die "Word not installed" if $@;

unless (defined $word) {

    $word = Win32::OLE->new('Word.Application', sub { $_[0]->Quit; })

        or die "Cannot start Word";

}



Win32::OLE->Option(Warn => 3);



$word->{'Visible'} = 1;

my $doc = $word->{'Documents'}->Add;

$doc->{'Range'}->InsertAfter('Hello, Word');

To run this script, save it as HelloWord.pl and run it from a DOS command line as follows:

> perl HelloWord.pl

While you may see some similarities, especially if you've worked with Perl before, these two scripts use very different syntax.

Using Perl is an admittedly extreme example. The other two scripting languages discussed in this chapter, Python and Ruby, share the "dot" syntax, and those scripts often more closely resemble their VBA counterparts.


     Python   SQL   Java   php   Perl 
     game development   web development   internet   *nix   graphics   hardware 
     telecommunications   C++ 
     Flash   Active Directory   Windows