Art  Delphi  Automation  History  Home  Politics  Email me Default Colours  Printable Colours

Word - common problems

{work in progress}
see also the Word main page

 

Starting Word Closing a document - can't prompt user
Coding for different versions of Word
'XxxToPoints' conversion routines don't work

 


Starting Word - common problems


I get an EOleSysError exception when I try to start Word!

If you are using Word 2000 and you have Norton Systemworks installed, you will get an exception when you try to start Word by automation: 'the message filter shows that the application is busy'. Uninstall Norton Systemworks to solve this problem.

Otherwise, you probably have 'Break on exceptions' set to true in the Delphi IDE. You can change this (using the Tools|Debugging|Language Exceptions menu in D4), or you can use code that avoids throwing an exception if Word is not open - see How to avoid using exceptions when opening Word.


My program always creates a separate instance of Word. How can I use the running instance?

Use GetActiveObject or GetActiveOleObject - see How to start Word for examples.


Starting different versions of Word

How to know which version will start


My program starts Word 97 on my machine, but Word 95 on someone else's, even though they have Word 97 installed

This problem usually arises with late binding. On some machines, a different version of Word 97 will start, depending on whether you call

MSWord := CreateOleObject('Word.Application'); 

or

MSWord := CreateOleObject('Word.Basic'); 

If Word97 was installed afterWord 95, both these calls will start Word 97. But if Word95 is installed later, it overrides the Word.Basic registry settings, and then CreateOleObject('Word.Basic') will start Word 95.

You can check which version of Word will start by looking into the registry settings. Under HKCR\Word.Basic I have a key called CurVer, with a value of Word.Basic.8. There's also a CLSID with a value of 000209FE-000[...] If you look this up under HKCR\CLSID - which is what the CreateOleObject call does - you'll see that it refers to Word Basic, and the program that will be activated is found in the LocalServer32 subkey.

So to make sure Word 97 is used, call CreateOleObject('Word.Application'). If some of your users have only earlier versions of Word, check the registry to see whether the HKCR\Word.Application subkey exists and that its CLSID points to a valid file; if it doesn't, call CreateOleObject('Word.Basic') .


My program starts Word 97 with CreateOleObject, but Word 95 when using the OleContainer.DoVerb method

The OleContainer opens the kind of file indicated by its object type. E.g., if you've assigned its object like this:

OleContainer1.CreateObject('Word.Document',False); 

it should open the program specified in the HKCR\Word.Document registry key. (Incidentally, there's a really useful freeware program for tracking registry accesses called Regmon, downloadable from http://www.sysinternals.com.)

So if you need your program to open the same version of Word as the OleContainer does, you could Word like this:

var 
  Word, Doc: variant; 
begin 
  Doc:= CreateOleObject('Word.Document'); 
  Word := Doc.Application;
  Word.Visible := True; 
Back to top

Closing a document

I tell Word to prompt the user to save changes when I close a document - but it doesn't!

According to the Word VBA helpfile, to prompt a user to save changes, you should use the wdPromptToSaveChanges constant, like this:

var
  SaveChs: olevariant;
begin
  SaveChs := wdPromptToSaveChanges;
  Word.ActiveDocument.Close(SaveChs, EmptyParam, EmptyParam);

Unfortunately, this doesn't work. The call behaves exactly as if you'd put wdSaveChanges for the first parameter - probably not what you want! To make Word prompt the user properly, use the document's ActiveWindow.Close method:

var
  SaveChs: olevariant;
begin
  SaveChs := wdPromptToSaveChanges;
  Word.ActiveDocument.ActiveWindow.Close(SaveChs, EmptyParam);

If you're not using the type library, the value of wdPromptToSaveChanges is $FFFFFFFE, or -2.

Back to top

Coding for different versions of word

I don't know which version of Word my users will have - can I write Word code that will work with any version?

Not very well.

If your users could have versions earlier than Office 97, then I'm afraid you'll have big problems, because Microsoft drastically changed the language between the 95 and 97 versions: from WordBasic to Visual Basic for Applications. This was not a small change. WordBasic typically mirrored the menu commands of Word, with commands such as EditCopy, FileNew, FileQuit, et cetera. In VBA all these commands are gone, and an object model centred around the Application, Document and Selection objects was brought in instead. EditCopy became Selection.Range.Copy, for example.

There is a WordBasic object in the new model, which accepts the old syntax: so if you can't persuade your users to update their software, you'll have to use this. But it is quite limited, and will not always have quite the same effect in different versions of Word.

Unfortunately, even using VBA does not make everything simple, since there has been a major change in Word between the 97 and 2000 releases: the shift to an SDI interface. If you use the Word 2000 type library (or component) you'll find there are methods with names like AddOld, OpenOld, PrintOutOld, and so on, which can be used for compatibility - if you use Word 2000's Add, Open and PrintOut methods instead, your code will crash on Office 97 machines. If you use the Word 97 type library, your code may crash on Office 2000 machines, and even if it doesn't some things will behave differently because of the new interface.

In conclusion: if any of your users have pre-97 versions, use WordBasic; otherwise use the latest version you've got, but use the methods ending with 'Old' for compatibility and test your code with all relevant Word versions!

Back to top

'SomethingToPoints' conversion routines

When I try to use the InchesToPoints, CentimetersToPoints (etc.) routines, I get an 'Unspecified error' message.

For some reason these routines don't seem to work with late binding. There is no problem if you call them with an early-bound _Application-type variable.

Back to top