Word Automation, Part I

Accessing Word From Inside Access

 

By Bryan Carbonnell

Demo File

 

Have you ever wanted to use the formatting control in Word on one of your Access reports? Using Word Automation, you can, and in this article, we’ll show you how. First, we’ll discuss the pros and cons of Early and Late Binding. Then, you’ll be ready to take on the Automation code necessary to create an instance of Word, create a new document, add text to that document, save the document, and then close Word.

Early Binding Versus Late Binding

First you need to decide whether to use Early Binding or Late Binding. Early Binding allows you to dimension variables by their specific data type. For example, the following declarations refer to the Word Application and Document objects rather than declaring both as generic objects:

 

Dim objWord as Word.Application

Dim doc as Word.Document

 

Early Binding also enables a few built-in Intelli-sense features: Auto Complete, Auto List Members, and Auto Quick Info. In addition, using early binding allows you to view Word’s object model in the Object Browser.

 

The downside to Early Binding is that you have to set a reference to a specific version of Word. Sometimes Access is smart enough to change the reference to the specific version of Word that is installed on the PC you are deploying your application; often it isn’t, and you could end up with problems relating to the references.

 

If you decide to use Late Binding, you will have to dimension all of your variables as Objects as follows:

 

Dim objWord as Object

Dim doc as Object

 

Consequently, you cannot access any of your variables until you set them to a specific object as shown below:

 

Set objWord = CreateObject(“Word.Application”)

Set doc = objWord.Documents.Open(“C:\Path\To\file.doc”)

 

In addition, the Intelli-sense features, Auto Complete, Auto List Members, Auto Quick Info and disables viewing of Word’s object model in the Object Browser. However, Late Binding doesn’t require that you set a reference to any Word Object Library, which can be advantageous if you are deploying run-time versions of your application to mixed OS/Office Version platforms.

 

Instead of choosing one or the other, we suggest you compromise and use both. During the development phase use Early Binding. Once you release the application, remove all specific references and change each to Object—the best of both worlds!

 

Now that the binding issue is resolved, let’s roll up our sleeves and dive into writing some code.

Create the Word instance

The next step is to create an instance of Word. Throughout this article, I will be using Early Binding. It is my preferred method, since I work in a fairly controlled environment, and I know which version of Word my end user will have. First set a reference to the Word Object Library. To set the reference:

 

1.       Create and open a new module. This will open the Visual Basic Editor (VBA) or code window if you are using Access 97.

2.       Select References from the Tools menu.

3.       Scroll down until you see Microsoft Word x.0 Object Library. The value of x will depend on which version of Word you have installed: 8.0 is Word 97, 9.0 is Word 2000, and 10.0 is Word XP. Place a check in the box, and then click OK. (It’s not enough to just select the item, you must check the box.)

 

Now that you have set a reference to the Word Object Library, it is time to create the following procedure called sWordTesting:

 

Sub sWordTesting()

'Dimension variables to hold pointers to the Word Application and

' Word Document we will be working with.

'Early Binding Dimensioning

' To use these declarations, reference the Word Object Library

Dim objWord As Word.Application

Dim doc As Word.Document

'Late Binding Dimensioning

' To use these declarations, un-reference the Word Object Library

'Dim objWord As Object

'Dim doc As Object

'Flag to indicate We Opened Word

Dim bolOpenedWord As Boolean

 

'Get pointer to Word Object

' Handle Error In-Line

On Error Resume Next

Set objWord = GetObject(, "Word.Application")

If Err.Number = 429 Then

    'If we got an error, that means there was no Word Instance

    Set objWord = CreateObject("Word.Application")

    'Set Flag to let us know we opened Word

    bolOpenedWord = True

End If

'Make Word Instance visible

objWord.Visible = True

'Reset Error Handler

On Error GoTo 0

 

'Create New Blank Document

Set doc = objWord.Documents.Add

 

'Insert Text

objWord.Selection.TypeText "Text to Insert in the Word Document." & vbCrLf

'Insert Paragraph

objWord.Selection.TypeParagraph

'Insert More text and Paragraphs

objWord.Selection.TypeText "AccessD is the BEST Access Mailing list."

objWord.Selection.TypeParagraph

objWord.Selection.TypeText "Database Advisors is the best Access resource."

objWord.Selection.TypeParagraph

objWord.Selection.TypeText "We are now done with our gratuitous sucking up! :)"

objWord.Selection.TypeParagraph

'This will shift the focus to Word

objWord.Activate

'Save New Document

On Error Resume Next

doc.Save

'If the cancel button in the SaveAs dialog was presses

' You will receinve and error

' .Number - 4198

' .Description - Command Failed

On Error GoTo 0

'Close and release pointers

doc.Close False

Set doc = Nothing

'Did we create the Word instance we are using

' or did we reuse an open instance?

If bolOpenedWord = True Then

    'We created an instance, so now we need to close it.

    objWord.Quit

End If

Set objWord = Nothing

End Sub

 

We need to create a couple of variables to hold our pointer to Word and a pointer to the Document object we will be working in. To do that, dim the application variable as Word.Application and the document variable as Word.Document (for early binding; don’t forget, you have to use Object for late binding)

 

Dim objWord as Word.Application

Dim doc as Word.Document

 

Okay, now how do we use these two variables? First you have to initialize objWord by setting a pointer to an already running instance of Word as follows:

 

Set objWord = GetObject(, "Word.Application")

 

If you’d rather not force users to open Word before they run your application, you must create an instance of Word as follows:

 

Set objWord = CreateObject("Word.Application")

 

So which should you use? It depends on the type of system your users have. Creating a new instance of Word isn’t a big deal on a high-end system so you can probably use CreateObject with wild abandon. If you have low-end workstations, then you should use GetObject to reuse the running instance of Word, but then your user will have to make sure he or she opens Word first. Again, the best solution is to use both. We recommend you try GetObject first, and if that fails, use CreateObject. The following code reuses any existing instance of Word. If there is none, the code creates one.

 

' Handle Error In-Line

On Error Resume Next

Set objWord = GetObject(, "Word.Application")

If Err.Number = 429 Then

    'If we got an error, that means there was no Word Instance

    Set objWord = CreateObject("Word.Application")

End If

'Reset Error Handler

On Error GoTo 0

 

If you create an instance of Word with CreateObject, that new instance doesn’t appear on your task bar. An Automation server, which is what we created, is typically hidden. This behaviour is fine in a production environment, but can be difficult to troubleshoot in a development environment. For this reason, we want to make objWord visible. To do so, add the following statement just after the End If above:

 

ObjWord.Visible = True

 

We now have a visible instance of Word in which to work.

 

Once you are happy with the way everything works, you can comment the Visible statement. I leave it in, even in the production environment. By doing so, the user can easily close Word themselves, if our Access application crashes. Otherwise, the user is left with a hidden instance of Word running.

Get the document

Now we need a document.

 

Like most computing tasks, there are several ways to get a document:

 

·          You can create a new blank document.

·          You can create a new document based on a specific template.

·          You can open an existing document.

Creating a blank document

We will start by adding a new blank document to Word’s Documents Collection using the following statement:

 

Set doc = objWord.Documents.Add

 

(Word’s default is to base the new document on Normal.dot.) That’s all there is to creating a blank document.

Using a template

If you want to create a new document based on a specific template, pass the Add method the template name complete with full path as follows:

 

Set doc = objWord.Documents.Add(“C:\Full\Path\To\Specific\template.dot”)

Opening a specific document

Finally, if you want to open a specific document, use the Open method of the Documents Collection as shown below:

 

Set doc = objWord.Documents.Open(“C:\Full\Path\To\Specific\document.doc”)

 

Okay, where are we? We have a visible Word instance. We have a blank document to work in. the next step is to add text to the document. Before we do that, we should talk about how to close the document and Word instance.

Closing stuff

At this point, we have an instance of Word and a document. To close and release the pointers to these objects, we need to do the reverse. So first we will close the document using the simple statement:

 

doc.Close

 

Now just to make sure Access completely releases the object reference, set it to Nothing as follows:

 

Set doc = Nothing

 

Now, on to closing the Word instance. You might think that you could use objWord.Close to close Word, but that would be wrong. There is no Close method for the Word object. You have to use Quit instead:

 

ObjWord.Quit

 

The above statement will close Word, but doing so so abruptly could be an issue if the user has an unsaved document.

 

One way to deal with unsaved documents is to set a flag when we create the Word instance, and check to see if the flag is set when we close it. To do so, add the following dim statement:

 

Dim bolOpenedWord as Boolean

 

And inside the If Err.Number structure add the following statement because our application opened Word.

 

bolOpenedWord = True

 

When the application is done with Word, the following If statement will check this flag and quit Word only if Access actually created the instance:

 

If bolOpenedWord = True then

    ObjWord.Quit

End if

 

If we are reusing an instance of Word, the flag is not set, and the Quit statement will not be executed. So now we have happy users again, and no support calls asking “Where did Word go?”.

 

To recap, the closing and releasing pointers portion of the code should look like:

 

doc.Close

Set doc = Nothing

If bolOpenedWord = True Then

    objWord.Quit

End If

 

The last thing we need to do is set the Word object variable to Nothing

 

Set objWord = Nothing

 

Now you can run this code to see what it does. Since right now we are just Opening Word, creating a blank document, closing the document and then closing Word, I would recommend you step through the code, instead of actually running it—if you want to see what’s happening.

Inserting text

Now on to the good stuff—actually putting text into the Document. There are several ways to insert text into the document:

 

·          Use the InsertBefore and InsertAfter methods of the Selection or Range objects.

·          Use the TypeText method of the Selection object.

 

Let’s start by quickly reviewing the Selection object. In a nutshell, this object is the currently selected text in the Active Word Document. There can only be one Selection object in Word at any given time. The active document will hold the Selection. You have to be careful using the Selection Object because you could inadvertently insert text into the wrong document if the user changes documents while you’re code is executing. The process is particularly vulnerable if it’s lengthy.

 

On the other hand, the Range object can reference any open document, even if that document is not the active document. You can even have more than one Range object per document. Because of this allowance, the Range object is a bit more flexible than the Selection object.

 

Having said that, the downside to the Range object is that you cannot see what your code is actually doing. The Selection object actively changes the selection in the Word document, so you can see where you are inserting, what text you are inserting, and what is replaced.

 

Since we are working with just a single document at the moment, we will use the Selection object. The Range object gets coded similarly, so when you are feeling confident, try adding some text using it. To insert Text, with the Selection object, just use the following statement:

 

objWord.Selection.TypeText “Text to Insert in the Word Document.”

 

If you have text selected when you use the TypeText method, the selected text may be replaced, depending on the Typing Replaces Selection setting (Tools|Options|Edit Tab) in Word. If this setting is checked, the text will be replaced; if not selected, the text will be inserted before the selected text.

 

If you want to add a new paragraph now, use the TypeParagraph method.

 

ObjWord.Selection.TypeParagraph

 

That’s all there is to inserting a paragraph.

 

Now you can add more text and paragraphs just by using the TypeText and TypeParagraph methods as follows:

 

objWord.Selection.TypeText “AccessD is the BEST Access Mailing list.”

objWord.Selection.TypeParagraph

objWord.Selection.TypeText “Database Advisors is the best Access resource.”

objWord.Selection.TypeParagraph

objWord.Selection.TypeText “We are now done with our gratuitous sucking up!”

objWord.Selection.TypeParagraph

 

The TypeText method closely emulates manually typing the text into a Word document. The InsertBefore and InsertAfter methods will insert the text before or after the Selection, respectively, and expand the Selection to include the inserted text.

Saving the document

The last step in this process is saving your newly created document. To do so, you use the Save or SaveAs method of the Document Object. The Save method will save the document (or template). If it hasn’t been saved before, it will open the Save As Dialog box, just as if you had used File|Save from the menu. SaveAs saves the document with a new file name or file format. This acts the same as File|SaveAs… from the menu. For now we will use the Save method:

 

doc.Save

 

Since this is a new document, you should be presented with the SaveAs Dialog box when this line runs. Give the file a name and click Save.

 

You will want to add appropriate error handling, which we left out for the sake of simplicity. Specifically, watch for error 4198 – Command Cancelled, which occurs if the user presses the Cancel button in the SaveAs dialog box.

The demo file

The database that is included with this article contains the complete procedure that we just wrote. It was developed and tested with Word 2000/Access 2000. It should work similarly in any other combination of Word and Access, but you may need to change the Word reference to the appropriate version installed on your system.

Summing it up

You have now created and saved your first Word document with automation. Feels pretty darn good, doesn’t it? J We’ve reviewed the basics of Word Automation from within Access. If you have any questions, please feel free to e-mail me at carbonnb@sympatico.ca and I will do my best to give you a coherent answer. In Part II, we will look at inserting text into a previously-created document by using Word bookmarks to provide specific places to insert the text.

 

If you want to have a look at Word’s Object model, you can look at these pages on Microsoft’s MSDN site.

Word 2000:

http://msdn.microsoft.com/library/default.asp?url=/library/enus/modcore/html/deovrMicrosoftWord2000.asp

Word XP: http://msdn.microsoft.com/library/default.asp?url=/library/enus/modcore/html/deovrMicrosoftWord2000.asp?frame=true

 

Please contact the author at listmaster@databaseadvisors.com  to ask questions or report errors.

Bryan Carbonnell ©2002
May be distributed as long as the copyright remains.
Bryan Carbonnell Bio