Hack 84 Automate Word from Other ApplicationsMany 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. 9.6.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 [Hack #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
Tools Figure 9-8. Setting a reference to the Word object model from Excel's Visual Basic EditorBy 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.
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 9-9. To determine an error number, you often need to let the error occur and then make a note of its number. Figure 9-9. The same error is generated when VBA can't create a COM objectSetting 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. 9.6.2 Controlling Word from a Scripting Language
Upcoming hacks in this chapter cover the specifics for controlling Word from three popular scripting languages: Perl [Hack #86], Python [Hack #85], and Ruby [Hack #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. |