Sunteți pe pagina 1din 9

Automating Microsoft Word

Contents

Sources of information Samples and components to download How do I ... ? Common problems

Sources of information
Web sites Delphi sites Allan Harkness's Word automation page Borland's papers Chapter 17 of C. Calvert's D4 Unleashed Graham Marshall's Delphi 3 and Word Joel Milne's Word FAQ For catching Word events, or general COM concepts, see also Binh Ly's tutorials Non-Delphi sites Cindy Meister's Word FAQ Jonathan West's WordFAQ MS Visual Basic Programmer's Guide Microsoft Developer's Network Books Charlie Calvert's Delphi 4 Unleashed
Back to top

How do I ... ?

Start Word Close Word Create a new document Open an existing document Close a document Insert text Format text Create and access tables Get document properties Get the cursor position

Code examples are given for Word 97+ first, but Word Basic examples are given in boxes for those using earlier versions of Word.

Back to top

>>>>>How to start Word<<<<<


Using the D5 components Using the type library (early binding) Without using the type library (late binding)

Using the D5 components to start Word Starting up Word with the new D5 components is a piece of cake. Here's an example:
WordApplication1.Connect; WordApplication1.Visible := True;

After you've connected, you can use the ConnectTo method of the other Word components to associate them with other Word elements, such as a Word document:
WordDocument1.ConnectTo(WordApplication1.ActiveDocument);

Using the type library (early binding) Before you can use this method, you must have imported the type library (MSWord8.olb for Word 97). One way of starting Word is to try the GetActiveObject call, to get a running instance of Word, but put a call to CoApplication.Create in an except clause. But except clauses are slow, and can cause problems within the IDE for people who like Break On Exceptions set to True. The following code removes the need for a try...except clause, by avoiding using OleCheck on GetActiveObject in the case when Word is not running.
uses ComObj, ActiveX, Word_TLB; // or Word97; or Word2000; for D5 users var Word: _Application; AppWasRunning: boolean; // tells you if you can close Word when you've finished Unknown: IUnknown; Result: HResult; begin AppWasRunning := False; {$IFDEF VER120} // Delphi 4 Result := GetActiveObject(CLASS_Application_, nil, Unknown); if (Result = MK_E_UNAVAILABLE) then Word := CoApplication_.Create {$ELSE} // Delphi 5

Result := GetActiveObject(CLASS_WordApplication, nil, Unknown); if (Result = MK_E_UNAVAILABLE) then Word := CoWordApplication.Create {$ENDIF} else begin { make sure no other error occurred during GetActiveObject } OleCheck(Result); OleCheck(Unknown.QueryInterface(_Application, Word)); AppWasRunning := True; end; Word.Visible := True; ...

Thanks to Allan Harkness for this tip. He has written a comprehensive TWordApp class that uses this method, which you can download from his site.

Without using the type library Automation is so much easier and faster using type libraries (early binding) that you should avoid managing without if at all possible. But if you really can't, here's how to get started:
var Word: Variant; begin try Word := GetActiveOleObject('Word.Application'); except Word := CreateOleObject('Word.Application'); end; Word.Visible := True;

Or, with earlier versions of Word:


var Word: Variant; begin try Word := GetActiveOleObject('Word.Basic'); except Word := CreateOleObject('Word.Basic'); end; Word.Visible := True;

By using GetActiveOleObject, you use an instance of Word that's already running, if there is one.
Back to 'HowDoI..?'

>>>>>How to close Word<<<<< Here's the quick version:

var SaveChanges: OleVariant; begin SaveChanges := wdDoNotSaveChanges; Word.Quit(SaveChanges, EmptyParam, EmptyParam);

Other possible values for the SaveChanges parameter are wdSaveChanges and wdPromptToSaveChanges - pretty self-explanatory, but if you're using late binding you'll need to define them in your own code like this:
const wdDoNotSaveChanges = $00000000; wdSaveChanges = $FFFFFFFF; wdPromptToSaveChanges = $FFFFFFFE;

The second parameter is used for documents not in Word format. The possible values are wdOriginalDocumentFormat, or wdPromptUser, or wdWordDocument. Again, in late binding, you can declare these yourself:
const wdWordDocument = $00000000; wdOriginalDocumentFormat = $00000001; wdPromptUser = $00000002;

The last parameter should be set to True if you want the document to be routed to the next recipient in line. Word Basic command
Word.FileExit(1);

quits Word, saving any modified file. If you pass 2 as the parameter, files are not saved; if the parameter is 0 or omitted, the user is prompted.

Back to 'HowDoI..?'

>>>>>How to create a new document<<<<< In Word 97:


Word.Documents.Add(EmptyParam, EmptyParam);

If you want the new document to be based on a template other than the Normal template, pass the name (and path) of the template as the first parameter. If you want to open the new document as a template, pass True for the second parameter. In Word 2000, the Documents.Add method has two extra parameters, for the document type, and for specifying whether the document should be visible on screen. But using this method on a Word 97 machine will cause an exception, so if you need your code to

be compatible with Word 97, use Word 2000's Documents.AddOld method. This takes the same parameters as the Word 97 Add method.

Word Basic command - optional parameters in square brackets []


Word.FileNew[Template = text] [, NewTemplate = number];

If you want the new document to be based on a template other than the Normal template, pass the name (and path) of the template as the first parameter. If you want to open the new document as a template, pass 1 for the second parameter.
Back to 'HowDoI..?'

>>>>>How to open an existing document<<<<< In word 97:


var FileName: OleVariant; begin FileName := 'C:\My Documents\The file I want to open.doc'; Word.Documents.Open(FileName, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam);

The optional parameters here include ReadOnly (the third parameter, default False), PasswordDocument (the fifth parameter, pass the password string for the document), and Format (the last parameter, lets you specify the file converter to be used). In Word 2000, the Documents.Open method has two extra parameters, for encoding, and for specifying whether the document should be visible on screen. But using this method on a Word 97 machine will cause an exception, so if you need your code to be compatible with Word 97, use Word 2000's Documents.OpenOld method. This takes the same parameters as the Word 97 Open method.

Word Basic command


Word.FileOpen{'C:\Docs\The file I want to open.doc');

Look in the WordBasic help file for information on the (numerous) optional parameters for FileOpen.
Back to 'HowDoI..?'

>>>>>How to close a document<<<<<


var SaveChs: olevariant;

begin SaveChs := wdSaveChanges; Word.ActiveDocument.Close(SaveChs, EmptyParam, EmptyParam);

The parameters are the same as for the Word.Close method, but with one unfortunate exception: there's a bug which stops the wdPromptToSaveChanges value working in this method. So if you want the user to be asked whether to save changes, use the ActiveWindow.Close method instead (see Example). Word Basic command
Word.FileClose(1);

To save the file, pass 1 as the first parameter; to close without saving, pass 2; to ask the user whether to save it first you can pass 0, or omit the parameter altogether.
Back to 'HowDoI..?'

>>>>>How to insert text<<<<<


var S: Selection; ... S :=Word.Selection; S.TypeText('Here is some text'); S.TypeParagraph; S.TypeParagraph; S.TypeText('And there was a blank line.');

If the Application.Options.ReplaceSelection property is True, any text selected will be overwritten by the new text. Word Basic command
Word.Insert('Here is some text');

Back to 'HowDoI..?'

>>>>>How to format text<<<<<


var S: Selection; ... S := Word.Selection; {Write the next sentence in bold type} S.Font.Bold := integer(True); S.TypeText('Be bold!'); S.Font.Bold := integer(False);

S.TypeParagraph; {Write the next sentence in italic type} S.Font.Italic := integer(True); S.TypeText('Be daring!'); S.Font.Italic := integer(False);

When using the selection object, remember that if the Application.Options.ReplaceSelection property is True, any text selected will be overwritten by the new text.

Back to 'HowDoI..?'

>>>>>How to create and access tables<<<<< You can create tables like this (tested on Word97):
var Doc: _Document; T: Table; begin Doc := Word.ActiveDocument; T := Doc.Tables.Add(Word.Selection.Range, 5, 3); T.Cell(1, 1).Range.Text := 'January'; T.Cell(1, 2).Range.Text := 'February'; T.Cell(1, 3).Range.Text := 'March'; T.Columns.Width := 72; // in points

You can read the data in the same way:


Caption := T.Cell(1, 3).Range.Text;

But using tables is very slow in Word (even worse with Word 2000). If you can you should put the text in first and then convert it to a table at the last possible moment, like this for example:
const Line1 = 'January,February,March'; Line2 = '31,28,31'; Line3 = '31,59,90'; var R: Range; Direction, Separator, Format: OleVariant; begin Doc := Word.ActiveDocument; R := Word.Selection.Range; Direction := wdCollapseEnd; R.Collapse(Direction); R.InsertAfter(Line1); R.InsertParagraphAfter; R.InsertAfter(Line2); R.InsertParagraphAfter; R.InsertAfter(Line3); R.InsertParagraphAfter; Separator := ','; Format := wdTableFormatGrid1;

R.ConvertToTable(Separator, EmptyParam, EmptyParam, EmptyParam, Format, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam); Back to 'HowDoI..?'

>>>>>How to get document properties<<<<< Use variants for this. (So many of the DocumentProperties calls return IDispatch interfaces, rather than the specific interface you want, that trying to do this through early binding is far too complicated to be worth the effort.)
uses Word97; // or Word2000, or Word_TLB for Delphi 4 var Doc: OleVariant; ... Doc := Word.ActiveDocument; Caption := Doc.BuiltInDocumentProperties['Template'].Value; ShowMessage(Doc.BuiltInDocumentProperties[wdPropertyTitle].Value); ShowMessage(Doc.BuiltInDocumentProperties[wdPropertyAuthor].Value);

As you see, properties can be accessed either by name or by one of the wdProperty constants. You can also loop through the BuiltInDocumentProperties collection - but don't do this unless you really have to, because it will cause the word/page count of the document to be recalculated. If the document is of any length, users won't thank you for this. :)

Back to 'HowDoI..?'

>>>>>How to get the current position of the cursor<<<<< The Selection object's information property can tell you this. Here's an example:
VertPos := Word.Selection.Information[wdVerticalPositionRelativeToPage]; HorizPos := Word.Selection.Information[wdHorizontalPositionRelativeToPage];

This code will tell you the vertical position of the selection - which is the cursor (insertion point) if no text is selected. The answer will be in twips, or 1/1440ths of an inch. To get the line number the cursor is on, you'd use
Word.Selection.Information[wdFirstCharacterLineNumber];

instead. Look up the Information property in the VBAWrd help to see all the other things you can find out this way - it's quite a long list.

Back to 'HowDoI..?'

Sample projects to download


Using the D5 components - a sample showing basic text entry, formatting, and searching Using Word's mailmerge facility - uses Word's built-in mailmerge to create letters for every company in the 'customer.db' table that comes with Delphi. You must have Delphi 4 (any version) or D5 (Pro version or better) to run this, with the demos installed.. Using bookmarks and properties - a very simple example of using bookmarks and custom document properties to create a report. You must have Delphi 4 (any version) or D5 (Pro version or better) to run this, with the demos installed. Example project by Wayne Herbert - many thanks to Wayne for this larger example project. Please note you must keep the watermark files and the data file in the same directory as the executable.

Brian Lowe's WordContainer component


Brian Lowe has written a component, descending from TOleContainer, that encapsulates a lot of Word functionality. Download it here!

S-ar putea să vă placă și