My VB6 MS Word VBA code crashes Word - Word97

A

Angus Comber

Hello

My Visual Basic application writes some text to a Word document. It usually
works but on two computers on a site it crashes my application.

Anyone got any ideas on where to start looking. Is removing Word, cleaning
up and re-installing the only option?

I am going on site to run the same VBA code from Excel to see if that works.
I can then check line for line what happens.



The basic code is here:

Private Sub cmdTestWord_Click()


Dim iSequence As Integer 'used to locate correct contact
Dim sDear As String 'Salutation on letter
Dim sTemp As String 'temp string to create address

Dim sLetter1 As String
Dim sLetter2 As String
Dim sLetter3 As String
Dim sSalute1 As String
Dim sSalute2 As String
Dim sSalute3 As String

Dim Title As String
Dim Firstname As String
Dim Initials As String
Dim Surname As String
Dim strPosition As String
Dim Familiar As String
Dim Ind As Integer
Dim ret As Long
Dim strToWord As String

'On Error GoTo WordErr
'Time bootup
'Dim dblSTime As Double
'dblSTime = Timer

'dblSTime = (Timer - dblSTime)
'MsgBox "Time taken: " & dblSTime
'Debug.Print "Time taken: " & dblSTime

Dim objWord As Word.Application
Dim objWordDoc As Word.Document '''''''''''''''''****
Dim docspath As String


'Time loading of Word
'Dim dblSTime As Double
'dblSTime = Timer '''''''''''''''''''''''''''

On Error Resume Next 'WordStart
LogError 0, "Just before Set objWord = GetObject(, Word.Application)",
"TestWord"
Set objWord = GetObject(, "Word.Application")
LogError 0, "After Set objWord = GetObject(, Word.Application)", "TestWord"
If Err.Number = 429 Then
Set objWord = New Word.Application '
CreateObject("Word.Application")
LogError 0, "After Set objWord = New Word.Application", "TestWord"
End If
If objWord Is Nothing Then
LogError Err.Number, "Unable to load Word object. Word is Nothing",
"Letter in frmContacts"

Exit Sub
End If

'' REMOVE THIS
objWord.Visible = True
LogError 0, "After objWord.Visible = True", "TestWord"
'On Error GoTo WordErr

Dim strLetter As String
strLetter = "letter.dot"

docspath = "C:\"

docspath = docspath & strLetter


If FileExists(docspath) = False Then
MsgBox "File: " & docspath & " does not exist check your document
template path and check that the selected template document exists"

Exit Sub
End If

Title = "Mr"
Firstname = "Angus"
Initials = "R"
Surname = "Comber"
Familiar = "Angus"
strPosition = "Director"

'sDear stuff
sDear = Familiar 'Dear

'Now need to address AddressLine
strToWord = Firstname & " " & Surname

strToWord = strToWord & VBA.Chr(13) & "5 Enmore Gardens"

strToWord = strToWord & VBA.Chr(13) & "East Sheen"

strToWord = strToWord & VBA.Chr(13) & "London, SW14 8RF"

LogError Err.Number, "Just before Set objWordDoc =
objWord.Documents.Add(docspath, False)", "TestWord"

Set objWordDoc = objWord.Documents.Add(docspath, False)
' Sometime get a valid objWord object but problem creating document based on
template.
' So still need to check a valid objWordDoc created
If objWordDoc Is Nothing Then
MsgBox "Unable to create Word Document object based on template: " &
docspath & " Unable to proceed with Word creation", vbCritical, "Word Error"
LogError Err.Number, "Unable to create objWordDoc object. 'Set
objWordDoc = objWord.Documents.Add(docspath, Fales)'", "Letter in
frmContacts"
objWord.Visible = True

Exit Sub
End If

objWord.Application.ScreenUpdating = False
'objWord.Visible = True

Dim bRet As Boolean

'Find <Address> & replace with strToWord
'objWord.Selection.Find.Execute findtext:="<Address>",
replacewith:=strToWord ', Replace:=wdReplaceAll
' Just in case named arguements can cause a problem - remove them!
'objWord.Selection.Find.Execute "<Address>", , , , , , , , , strToWord, True
'objWord.ActiveDocument.Range.WholeStory

'bRet = objWordDoc.Range.Find.Execute("<Address>", , , , , , , , ,
strToWord, Word.wdReplaceAll)
LogError 0, "Just before first LateBindingReplace objWordDoc, < Address >,
strToWord", "TestWord"
LateBindingReplace objWordDoc, "<Address>", strToWord

'Find <Dear> & replace with sDear
'objWord.Selection.WholeStory
'objWord.Selection.Find.Execute findtext:="<Dear>", replacewith:=sDear ',
Replace:=wdReplaceAll
'objWord.Selection.Find.Execute "<Dear>", , , , , , , , , sDear, True
'objWordDoc.Range.Find.Execute "<Dear>", False, False, , , , , , , sDear,
True
LateBindingReplace objWordDoc, "<Dear>", sDear

LogError 0, "After last LateBindingReplace objWordDoc, < Dear >, strToWord",
"TestWord"

'objWordDoc.Range.Find.Execute
'Find <Start> & place cursor for user to start typing
'objWord.Selection.WholeStory
'objWord.Selection.Find.Execute findtext:="<Start>", replacewith:="" ',
Replace:=wdReplaceAll

'objWordDoc.Range.WholeStory ' select all text
'objWordDoc.Range.Find.Execute "<Address>", False, False, False, False,
False, True, Word.wdFindContinue, False, "Abba", Word.wdReplaceAll
'If Err.Number <> 0 Then
' LateBindingReplace objWordDoc, "<Address>", strToWord
'End If
'objWordDoc.Range.Find.text = "<Address>"
'objWordDoc.Range.Find.Replacement.text = "Abba"

'objWordDoc.Range.Find.Execute
LogError 0, "Just before objWord.ActiveDocument.Variables(SiteID).Value =",
"TestWord"


objWord.ActiveDocument.Variables("SiteID").Value = 3
objWord.ActiveDocument.Variables("HType").Value = "Letter"
objWord.ActiveDocument.Variables("HComputer").Value = "MyComputername"

LogError 0, "After last objWord.ActiveDocument.Variables(HComputer).Value
=", "TestWord"

LogError 0, "Just before objWord.Application.ScreenUpdating = True",
"TestWord"
objWord.Application.ScreenUpdating = True
LogError 0, "Just after objWord.Application.ScreenUpdating = True",
"TestWord"
objWord.Visible = True
LogError 0, "Just after objWord.Visible = True", "TestWord"
objWord.Application.WindowState = Word.wdWindowStateMaximize
LogError 0, "Just after objWord.Application.WindowState = ", "TestWord"

LogError 0, "Just before bjWord.Application.Activate", "TestWord"
objWord.Application.Activate
LogError 0, "Just after bjWord.Application.Activate", "TestWord"


'dblSTime = (Timer - dblSTime)
'MsgBox "Time taken: " & dblSTime


End Sub


Public Sub LogError(ByVal errnum As Integer, ByVal ErrDescription As String,
Optional ByVal ProcName As String)
On Error Resume Next
Dim msg As String
Dim iFilenum As Integer 'To get a free filenumber
msg = Date & vbTab & Time & vbTab & ProcName & vbTab & errnum & vbTab &
ErrDescription
iFilenum = FreeFile
Open "C:\Errors.log" For Append As #iFilenum
'Write new value
Print #iFilenum, msg
Close #iFilenum
' MsgBox msg
'Debug.Print msg
End Sub


' Due to http://support.microsoft.com/default.aspx?scid=kb;EN-US;292744
' which is a COM problem with Word's Find object clashing with an old
version of Excel
' sometimes Find method will NOT work. So have to use Late binding to
accomplish
' Find replace. Requires a Word Document object plus search and replace
strings
Public Function LateBindingReplace(oWordDoc As Word.Document, strFind,
strReplace) As Long
On Error Resume Next
Dim oFind As Object ' Word.Find
'MsgBox "we are in latebindingreplace now!"
Set oFind = oWordDoc.Content.Find

If oFind Is Nothing Then
LogError Err.Number, "Unable to create oFind object. '",
"LateBindingReplace in modMisc"
LateBindingReplace = -1
Exit Function
End If
oFind.Execute strFind, False, False, False, _
False, False, True, Word.wdFindContinue, False, strReplace, _
Word.wdReplaceAll

LateBindingReplace = Err.Number

End Function


Private Function FileExists(strFile As String) As Boolean
Dim MyFile As String
' Returns filename if it exists.
MyFile = Dir(strFile)

If MyFile <> "" Then
FileExists = True
Else
FileExists = False
End If
End Function
 
J

Jonathan West

Hi angus,

I suspect the problem is that you have a mix of early and late binding. You
have set a reference to the Word object library in the project, but are
using either GetObject (late binding) or New Word.Application (early
binding) in the code depending or the execution path.

This is a recipe for problems.

Because you are presumably designing for compatibility with multiple
versions of Word, you should stick to late binding exclusively.

Remove the reference to Word in the References list, declare the objWord and
objWordDoc variables as Object, and use CreateObject("Word.Application") to
create a new instance of Word if there is not an already running instance
 
A

Angus Comber

Some interesting feedback on this now. I recently upgraded my development
machine to Office 2003. So in Visual Basic my reference was to the Word
2003 object library. My compiled VB6 application works on my Word2003
version fine. But I tested on another Word 97 computer and it crashed. So
I recompiled my VB app using my old laptop which still runs Word 97 and
everything works fine.

The version comiled on my Word 97 machine works OK on my Word 2003 machine.

Has anyone come across this behaviour before?

So is the the moral of the tale is to compile using Word 97 so you can
deploy on Word97 onwards?

Angus Comber
(e-mail address removed)
 
A

Angus Comber

That's interesting. I was not aware that late binding would be the best
approach here.

I also found this out:

Some interesting feedback on this now. I recently upgraded my development
machine to Office 2003. So in Visual Basic my reference was to the Word
2003 object library. My compiled VB6 application works on my Word2003
version fine. But I tested on another Word 97 computer and it crashed. So
I recompiled my VB app using my old laptop which still runs Word 97 and
everything works fine.

The version comiled on my Word 97 machine works OK on my Word 2003 machine.

So is the the moral of the tale is to compile using Word 97 so you can
deploy on Word97 onwards?


As early binding is more 'efficient' then should this latter approach be
prefereable to using late binding throughout?

Angus Comber
(e-mail address removed)
 
T

Tom Winter

The moral is good, assuming you are only using features of Word that are
present in Word 97. If you need features of Word that are only available in
later versions, then you run in to a problem.

For my major project, I target Word 2000 and later. I compile using a
reference to Word 2000, use early binding, and everything works fine.

The reason you can't go backwards (that is, compile with a reference to Word
2003 and then expect things to work under earlier versions of Word) is that
some of the methods in Word have changed over time. For example,
Documents.Open has changed over the different versions of Word, each version
adding new parameters. The rules of COM don't allow you to do that, so Word
actually cheats. If you use OLEVIEW to look at Word 2003's type library,
you'll see methods called Documents.OpenOld, Documents.Open2000 and
Documents.Open2002. Those methods are now hidden in Word 2003. When you
compile with 2003, your app will be using the latest greatest Open method
that 2003 supplies. But older versions of Word do not have that method, so
when you try to call it, your application will crash. (Hope that makes
sense. I can explain more if you need.)

Here's some stuff I wrote up for an earlier post. Hope it helps:

----

So what strategy should I use for working with multiple versions of Office
applications? Well, first, pick a good base version that contains most of
the functionality you want. For my project, I picked 9.0/2000, even though I
wanted to work with 8.0/97 all the way through 11.0/2003. You can then
reference the type library by selecting it from the PROJECT | REFERENCES
list in VB (assuming VB6 here!). If the version you want is not there (only
ONE version will be ever listed), you can BROWSE to the appropriate OLB
file. You don't need to have the whole application installed on your system.
VB only cares about the information in the OLB file. The OLB file doesn't
need to be registered for VB6 to use it, so you can copy it to a common
network location and have all the developers reference it there.

Then you need to remember what version you are using while programming and
be careful about what objects and methods you use. You'll only be able to
early bind to objects that exist in the version you've chosen (or older
version). Newer objects you'll have to Dim As Object. There's no way around
that.

Now what if you want to call a method using parameters that are only
available in a newer version that what you've referenced? Well, that's
tricky. You can't just add the extra parameters on the end of the method
call, even if you late bind it. You'll get an error when you're on a system
with an older version. You have to check the version first. Here's what you
do (it's from actual production code):

' Assume we are referencing the Word 2000 type library...
' Word 2000's Open method supports the Visible parameter, but Word 97 does
not.

Dim oWord As Word.Application ' Note early bound is OK here!

Dim oDocuments As Object ' Late bound reference to the Documents object for
Word 97

Set oWord = ..... ' Get Word from somewhere

If IsWord97(oWord) Then

Set oDocuments = oApplication.Documents ' Note this is an early bound
call, which is OK. The Documents property of the Application object is the
same for all versions.

oDocuments.Open FileName:="Something.doc" ' Note this is a late bound
call.

Else

oWord.Documents.Open FileName:="Something.doc", Visible:=True ' Note
this is an early bound call.

End If

OK, now what if you want to call a method that only exists in a newer
version than what you've referenced (or a method that has new parameters)?
Here's our above example, a little different. Now we are referencing the
Word 97 type library and want to worry about newer versions. (This example
is NOT from production code, but you get the idea.)

' Assume we are referencing the Word 97 type library...
' Word 2000's Open method supports the Visible parameter, but Word 97 does
not.

Dim oWord As Word.Application ' Note early bound is OK here!

Dim oDocuments As Object ' Late bound reference to the Documents object for
Word 2000 or newer

Set oWord = ..... ' Get Word from somewhere

If IsWord2000orLater(oWord) Then

Set oDocuments = oApplication.Documents ' Note this is an early bound
call, which is OK. The Documents property of the Application object is the
same for all versions.

oDocuments.Open FileName:="Something.doc", Visible:=True ' Note this
is a late bound call.

Else

oWord.Documents.Open FileName:="Something.doc" ' Note this is an
early bound call.

End If

----

Also, Jonathan was not really correct in stating that GetObject gives you
late binding. How you get the object doesn't matter. An OBJECT is not late
bound or early bound. An object is just an object. It's METHOD CALLS that
are early or late bound. When you are calling methods (or properties) on an
object that has been DIM'ed as some specific object type, the method calls
are early bound. When the object has been DIM'ed AS OBJECT, the method calls
are late bound. Take a look at this:

Dim oDocumentsEarly As Word.Documents

Dim oDocumentsLate As Object

Set oDocumentsEarly = oWord.Documents ' Doesn't matter where we got oWord
from....

oDocumentsEarly.Open "Something.doc" ' This call is early bound.

Set oDocumentsLate = oDocumentsEarly

oDocumentsLate.Open "SomethingElse.doc" ' This call is late bound.
 
A

Angus Comber

Thanks that was very helpful. I think Word VBA syntax prior to Word 97 was
very different and I am not bothering to support that. But I do want to
support Word97 up. So I have installed Word97 to a custom location and in
my VB projects I will use the Word 8.0 reference from now on.

Thanks again.

Angus
 
J

Jonathan West

Angus Comber said:
Thanks that was very helpful. I think Word VBA syntax prior to Word 97
was
very different and I am not bothering to support that. But I do want to
support Word97 up. So I have installed Word97 to a custom location and in
my VB projects I will use the Word 8.0 reference from now on.

If you want to be able to support and test compatibility with multiple
versions of Word, then this is not a very good arrangement, since all
versions of Office write files to common areas. and it may well be that Word
97 has no overwritten newer versions of files that Word 2003 needs.

If you must have multiple versions of Office available on the same machine
for testing, then I strongly recommend you get a copy of Microsoft
VirtualPC, and create a number of virtual machines, each of which can be
totally separate from the others.

In order to run VirtualPC, your machine will need to be fairly powerful, and
you will need lots of memory and spare disk space. But this is probably
cheaper than having multiple test machines.
 
T

Tom Winter

I agree with Jonathan that VirtualPC is probably the best way to go. If you
don't have the resources for that though, installing multiple versions of
Word on the same machine has never been a problem for me. I've always
started with the oldest version first and always installed them in different
locations. I've had Word 6.0, Word 95, Word 97, Word 2000 and Word 2003
(sorry, no XP!) all on the same machine and I've never had any problems with
them all working correctly.
 
J

Jonathan West

Tom Winter said:
I agree with Jonathan that VirtualPC is probably the best way to go. If you
don't have the resources for that though, installing multiple versions of
Word on the same machine has never been a problem for me. I've always
started with the oldest version first and always installed them in
different
locations. I've had Word 6.0, Word 95, Word 97, Word 2000 and Word 2003
(sorry, no XP!) all on the same machine and I've never had any problems
with
them all working correctly.

I agree that if you're a competent developer and experienced user of Office,
you can get different versions of Word to coexist. And you are right in
saying that the trick is to install the oldest first.

But it is not a representative test platform, and if you want to assure
yourself that the code will work on other machines, then at some point it is
necessary to carry out testing on a PC that has a single version of Office
installed.
 
T

Tom Winter

I definitly agree with you on the testing. -Tom

Jonathan West said:
I agree that if you're a competent developer and experienced user of Office,
you can get different versions of Word to coexist. And you are right in
saying that the trick is to install the oldest first.

But it is not a representative test platform, and if you want to assure
yourself that the code will work on other machines, then at some point it is
necessary to carry out testing on a PC that has a single version of Office
installed.


--
Regards
Jonathan West - Word MVP
www.intelligentdocuments.co.uk
Please reply to the newsgroup
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top