Automation Error - Qualifying my code

B

Beeawwb

Hi there everybody,

I've been trying to solve this problem for weeks now, I keep getting an
intermittent error when running some code in Word 2003. I'm getting a
run-time error in Word when I run some of my code, and I can't determine why.
Every artcile I've read on the internet says that I have some "unqualified"
code somewhere, which is creating a reference to Word which then doesn't get
released.

The problem is, as far as I can tell, my code is all properly qualified.

I guess I have 2 questions. The first is, when qualfying code, how does one
refer to the "currently active document", eg, the one which has the button
being pushed. The examples I've seen all use "oWord.Documents.Add" which
isn't what I'm looking to do.

Secondly, would anybody be willing to look over my code and see if I've
missed anything? I've been staring at the code for so long that I'm apt to
miss something somewhere, and a second pair of eyes would really help.

Thanks in advance for reading and any assistance you can provide.

-Bob
 
J

Jonathan West

Beeawwb said:
Hi there everybody,

I've been trying to solve this problem for weeks now, I keep getting an
intermittent error when running some code in Word 2003. I'm getting a
run-time error in Word when I run some of my code, and I can't determine
why.

Show us the bit of code that causes the error, and tell us the precise
wording of the error. The information you have provided so far is too vague
for a diagnosis.
Every artcile I've read on the internet says that I have some
"unqualified"
code somewhere, which is creating a reference to Word which then doesn't
get
released.

The problem is, as far as I can tell, my code is all properly qualified.

I guess I have 2 questions. The first is, when qualfying code, how does
one
refer to the "currently active document", eg, the one which has the button
being pushed. The examples I've seen all use "oWord.Documents.Add" which
isn't what I'm looking to do.

oWord.ActiveDocument is the currently active document., assuming oWord is
the name of the object variable you have set up for the Word Application
object. Are you trying to automate Word from an outside program? If you are
not, and are just running VBA from within Word, you don't need to set an
object variable for this.
Secondly, would anybody be willing to look over my code and see if I've
missed anything? I've been staring at the code for so long that I'm apt to
miss something somewhere, and a second pair of eyes would really help.

If you post a small snippet or two here, then I'm sure people will be happy
to comment. If you want someone to do a full code review of your entire
project, that is a rather larger task, and those who are expert enough to do
it would probably expect to be paid.
 
D

Doug Robbins - Word MVP

Copy and paste your code into a message that you post back here, with an
explanation of what you are trying to get it to do, would be the best way to
try and get help with it. Also if the error message gives you the
opportunity to click on Debug, what line of code is highlighted at that
time.

--
Hope this helps.

Please reply to the newsgroup unless you wish to avail yourself of my
services on a paid consulting basis.

Doug Robbins - Word MVP
 
B

Beeawwb

Hi all, and thanks for the responses. I didn't want to crowd the first post
with my code, so I'll go through a bit more detail now.

A quick bit about what the code does. I've got a form with 4 buttons. The
code gets the active printer name, and based on the name assigns text to the
4 buttons saying which type of paper is in which tray. You click on a button,
the code then ensures the page height is A4 (a lot of our templates seem to
be in Letter size), checks how many pages are in the document. If there are
more than 2 pages, it asks if you want all pages on letterhead, or just page
1. Once that is answered, it prints the document.

Now as for the problem itself, I used to be getting an actual error. Now,
Word just crashes without any error at all, saying "Word has encountered an
error and must shut down." with a tick box for "Restart". There is a debug
button, but clicking this brings another error "The memory could not be
read", with yet another debug button, which gives the same error and crashes
Word fully. As such, I can't tie the error down to a specific line of code
(which is making this all the harder).

I guess one of the biggest issues is, because I can't reproduce the error on
a regular basis, I can't watch my immediates window to check how far the code
has gone (debug.print). Is there a way to write my Immediates window to a log
file automatically?

What I can do, is work out how much has happened before it crashes. The
crash always occurs after pushing 1 of the 4 buttons on my form. So it has to
be in the section of code that formats the document. As such, I'll post my
declarations at the beginnging of my code, and the section that does the
printing, as I'm sure this is where the error lies.

Thanks again for your assistance, it is greatly appreciated.

-Bob

'Define Word Application as per Microsoft KB319832
Set oWord = Word.Application
With oWord
.Visible = True
.Activate
.WindowState = wdWindowStateMaximize
End With
Set oDoc = oWord.ActiveDocument

.......

Debug.Print "Button Pressed"
If ButtonPressed(0) = "" Then GoTo CancelOut

'Assign Default Settings
AssignBins = GetBinNumbers
For Each Sec In oDoc.Sections
With Sec.PageSetup
.FirstPageTray = AssignBins(ButtonPressed(0))
.OtherPagesTray = AssignBins(ButtonPressed(0))
End With
With Options
.DefaultTray = "Drawer 2"
End With
Next Sec

....... It doesn't get this far, but I've included it anyway.

PrintOut:
Debug.Print "Confirmed"
oDoc.PrintOut
GoTo EndMe:
 
R

Russ

B,
Since your running of the code gets worse, as far as errors, each time you
run it, you may have corrupted Normal.dot.
I would try to find and rename Normal.dot.
Restart Word and it will create a new Normal.dot.
Put a breakpoint just before you think you would get an error, then single
step through the code with the F8 function key to see which line produces
the error.
Report you findings and surrounding code to this message thread.
 
B

Beeawwb

Russ said:
B,
Since your running of the code gets worse, as far as errors, each time you
run it, you may have corrupted Normal.dot.
I would try to find and rename Normal.dot.
Restart Word and it will create a new Normal.dot.
Put a breakpoint just before you think you would get an error, then single
step through the code with the F8 function key to see which line produces
the error.
Report you findings and surrounding code to this message thread.

It's not that the running of the code gets worse as far as errors go. It's
always consistnently been the same error, just the error is not popping up as
a message box, probably due to the error handling code I have to catch other
(known) errors (E.g. document is protected with an unknown password) and I
don't trap for this particular error. Also, the code is being run from
"PrintOnLetterhead.dot" from a shared location as our "Nomal.dot" is on the C
Drive of our computers, which is unaccessable by normal users.

The other problem is, I can usually run the code fine. I spent 10 minutes
today playing with various settings changes, changing printers, opening and
closing multiple documents, without a single crash. Yesterday afternoon, I
did the same thing and made it crash after 2 tries. I do try and step through
the code as much as possible, which ironically, rarely crashes.

-Bob
 
B

Beeawwb

I've followed the steps in the template, and while it did reduce my project
size by 10Kb, I still received the error. I seem to have hit upon a way to
reproduce the error though.

I open 2 documents from our intranet, and print 1 to any printer. Then, I
change the default printer, and print document 2. The program crashes.

I have been testing this morning with the Immediate window open, and
Debug.Print every line of code from the 'Assign Default Settings comment. It
seems that I've narrowed it down to the exact line of code causing the crash
now.
(from my original posted code)

With Options
.DefaultTray = "Drawer 2" <---- This line causes the crash
End With

Looking at this line, it looks unqualified (Which document Options am I
modifying). I don't even remember writing these lines (Why would I want to
set every DefaultTray to Drawer 2, regardless of which letterhead I'm using?)
so I'm going to take these lines out and release it into the wild.

If anybody can see a problem with these 3 lines however, please let me know.

Here's hoping this is all resolved...

-Bob
 
R

Russ

I guess one of the biggest issues is, because I can't reproduce the error on
a regular basis, I can't watch my immediates window to check how far the code
has gone (debug.print). Is there a way to write my Immediates window to a log
file automatically?

Bob,
I tried playing around with the immediate window and sendkeys to control it
while using the extension reference for the interface. It just seemed to be
too quirky.

But while researching I found this cool piece of code to create a LogIt
class: (Peter Hewett)
<http://www.tech-archive.net/Archive/Word/microsoft.public.word.vba.general/
2004-04/0495.html>

With this code it is easy to emulate the debug.print functionality.
Multiple logs can be created.
[object].TimeStamp = True or False between output lines for timestamping or
not.
 
R

Russ

Here is the aforementioned code amended to work on both MacWord and WinWord.
I used Application.PathSeparator and changed the Kill() function to
KillLog() to avoid an endless loop in the class.

Insert a new class and name it LogIt then paste this Class code into it.
Peter Hewett's amended code:

****** Start of LogIt Class code *******

Private mstrFile As String
Private mstrPath As String
Private mboolEnabled As Boolean
Private mboolTimeStamp As Boolean

Public Sub Output(ByVal strText As String)
Const cProcedureName As String = "Log::Output"

Dim hFile As Long

On Error GoTo OutputError

' Everything must be right for us to log the passed text
If CanOutput Then

' Prefix log text with timestamp
If TimeStamp Then strText = Now & vbTab & strText

' Open log file for append
hFile = FreeFile
Open mstrPath & mstrFile For Append Access Write As hFile

' Write the output and tidy up
Print #hFile, strText
Close hFile
End If

OutputExit:
Exit Sub

OutputError:
mboolEnabled = False
Err.Raise Err.Number, cProcedureName, Err.Description
End Sub ' Output

Public Sub KillLog()
On Error GoTo HandleError

' Delete the current log file if it exists
If Len(Dir$(mstrPath & mstrFile)) > 0 Then
Kill mstrPath & mstrFile
End If

ExitHere:
Exit Sub

HandleError:
mboolEnabled = False
Err.Raise vbObjectError + 8001, "Log::Kill", _
Err.Description
Resume ExitHere
End Sub ' Reset

Public Property Get Path() As String
Path = mstrPath
End Property
Public Property Let Path(ByVal strPath As String)
strPath = Trim$(strPath)
If Right$(strPath, 1) <> Application.PathSeparator _
Then strPath = strPath & Application.PathSeparator
mstrPath = Trim$(strPath)
End Property

Public Property Get File() As String
File = mstrFile
End Property
Public Property Let File(ByVal FileName As String)
mstrFile = FileName
End Property

Public Property Get Enabled() As Boolean
Enabled = mboolEnabled
End Property
Public Property Let Enabled(ByVal EnableLogFile As Boolean)
mboolEnabled = EnableLogFile
End Property

Public Property Get TimeStamp() As Boolean
TimeStamp = mboolTimeStamp
End Property
Public Property Let TimeStamp(ByVal TimeStampOutput As Boolean)
mboolTimeStamp = TimeStampOutput
End Property

Public Property Get CanOutput() As Boolean
CanOutput = LenB(Path) > 0 And LenB(File) > 0 And Enabled
End Property

Private Sub Class_Initialize()
Me.Enabled = True
End Sub

****** End of LogIt Class code *******

Public Sub LogItTest()
Dim logFile As LogIt

' Create log file
Set logFile = New LogIt
logFile.Path = "Macintosh HD:Users:UserName:Desktop:"
logFile.File = "DEBUG LogItTest.txt"

' Use it....
'logFile.KillLog 'To in effect, clear log, if desired.
logFile.TimeStamp = True
logFile.Output "This is the first log entry"
logFile.TimeStamp = False
logFile.Output "This is the second log entry "
Set logFile = Nothing
End Sub

Multiple logfiles could be going at the same time to log only certain parts
of code. You just need to create multiple instances of each Logit class.

Windows users could also use environmental variables:
logFile.Path = Environ("HOMEDRIVE") & Environ("HOMEPATH") & "\My Documents\"

Bob,
I tried playing around with the immediate window and sendkeys to control it
while using the extension reference for the interface. It just seemed to be
too quirky.

But while researching I found this cool piece of code to create a LogIt
class: (Peter Hewett)
<http://www.tech-archive.net/Archive/Word/microsoft.public.word.vba.general/
2004-04/0495.html>

With this code it is easy to emulate the debug.print functionality.
Multiple logs can be created.
[object].TimeStamp = True or False between output lines for timestamping or
not.
I guess one of the biggest issues is, because I can't reproduce the error on
a regular basis, I can't watch my immediates window to check how far the code
has gone (debug.print). Is there a way to write my Immediates window to a log
file automatically?
 
B

Beeawwb

Russ, my sincere thanks for this code! It's exactly what I needed. By
grabbing the username of the person running the macro I can tell who is
running the macro, and by outputting exactly what stage they're up to I can
isolate any errors! Thank you VERY much, this will make life so much easier
around the office, for this and any future projects.

-Bob

(For those interested, I use the following to get the username)
Global Username
Sub GetDetails()
Dim objNet
Set objNet = CreateObject("WScript.NetWork")
Username = objNet.Username
Set objNet = Nothing
End Sub

Russ said:
Here is the aforementioned code amended to work on both MacWord and WinWord.
I used Application.PathSeparator and changed the Kill() function to
KillLog() to avoid an endless loop in the class.

Insert a new class and name it LogIt then paste this Class code into it.
Peter Hewett's amended code:

****** Start of LogIt Class code *******

Private mstrFile As String
Private mstrPath As String
Private mboolEnabled As Boolean
Private mboolTimeStamp As Boolean

Public Sub Output(ByVal strText As String)
Const cProcedureName As String = "Log::Output"

Dim hFile As Long

On Error GoTo OutputError

' Everything must be right for us to log the passed text
If CanOutput Then

' Prefix log text with timestamp
If TimeStamp Then strText = Now & vbTab & strText

' Open log file for append
hFile = FreeFile
Open mstrPath & mstrFile For Append Access Write As hFile

' Write the output and tidy up
Print #hFile, strText
Close hFile
End If

OutputExit:
Exit Sub

OutputError:
mboolEnabled = False
Err.Raise Err.Number, cProcedureName, Err.Description
End Sub ' Output

Public Sub KillLog()
On Error GoTo HandleError

' Delete the current log file if it exists
If Len(Dir$(mstrPath & mstrFile)) > 0 Then
Kill mstrPath & mstrFile
End If

ExitHere:
Exit Sub

HandleError:
mboolEnabled = False
Err.Raise vbObjectError + 8001, "Log::Kill", _
Err.Description
Resume ExitHere
End Sub ' Reset

Public Property Get Path() As String
Path = mstrPath
End Property
Public Property Let Path(ByVal strPath As String)
strPath = Trim$(strPath)
If Right$(strPath, 1) <> Application.PathSeparator _
Then strPath = strPath & Application.PathSeparator
mstrPath = Trim$(strPath)
End Property

Public Property Get File() As String
File = mstrFile
End Property
Public Property Let File(ByVal FileName As String)
mstrFile = FileName
End Property

Public Property Get Enabled() As Boolean
Enabled = mboolEnabled
End Property
Public Property Let Enabled(ByVal EnableLogFile As Boolean)
mboolEnabled = EnableLogFile
End Property

Public Property Get TimeStamp() As Boolean
TimeStamp = mboolTimeStamp
End Property
Public Property Let TimeStamp(ByVal TimeStampOutput As Boolean)
mboolTimeStamp = TimeStampOutput
End Property

Public Property Get CanOutput() As Boolean
CanOutput = LenB(Path) > 0 And LenB(File) > 0 And Enabled
End Property

Private Sub Class_Initialize()
Me.Enabled = True
End Sub

****** End of LogIt Class code *******

Public Sub LogItTest()
Dim logFile As LogIt

' Create log file
Set logFile = New LogIt
logFile.Path = "Macintosh HD:Users:UserName:Desktop:"
logFile.File = "DEBUG LogItTest.txt"

' Use it....
'logFile.KillLog 'To in effect, clear log, if desired.
logFile.TimeStamp = True
logFile.Output "This is the first log entry"
logFile.TimeStamp = False
logFile.Output "This is the second log entry "
Set logFile = Nothing
End Sub

Multiple logfiles could be going at the same time to log only certain parts
of code. You just need to create multiple instances of each Logit class.

Windows users could also use environmental variables:
logFile.Path = Environ("HOMEDRIVE") & Environ("HOMEPATH") & "\My Documents\"

Bob,
I tried playing around with the immediate window and sendkeys to control it
while using the extension reference for the interface. It just seemed to be
too quirky.

But while researching I found this cool piece of code to create a LogIt
class: (Peter Hewett)
<http://www.tech-archive.net/Archive/Word/microsoft.public.word.vba.general/
2004-04/0495.html>

With this code it is easy to emulate the debug.print functionality.
Multiple logs can be created.
[object].TimeStamp = True or False between output lines for timestamping or
not.
I guess one of the biggest issues is, because I can't reproduce the error on
a regular basis, I can't watch my immediates window to check how far the code
has gone (debug.print). Is there a way to write my Immediates window to a log
file automatically?
 
R

Russ

Bob,
You're welcome. I thought Peter Hewett did a good job creating the class
object for a very useful function. He lives in New Zealand and it looks like
he spends a lot of his time, now, with helping people who use Linux.
Russ, my sincere thanks for this code! It's exactly what I needed. By
grabbing the username of the person running the macro I can tell who is
running the macro, and by outputting exactly what stage they're up to I can
isolate any errors! Thank you VERY much, this will make life so much easier
around the office, for this and any future projects.

-Bob

(For those interested, I use the following to get the username)
Global Username
Sub GetDetails()
Dim objNet
Set objNet = CreateObject("WScript.NetWork")
Username = objNet.Username
Set objNet = Nothing
End Sub

Russ said:
Here is the aforementioned code amended to work on both MacWord and WinWord.
I used Application.PathSeparator and changed the Kill() function to
KillLog() to avoid an endless loop in the class.

Insert a new class and name it LogIt then paste this Class code into it.
Peter Hewett's amended code:

****** Start of LogIt Class code *******

Private mstrFile As String
Private mstrPath As String
Private mboolEnabled As Boolean
Private mboolTimeStamp As Boolean

Public Sub Output(ByVal strText As String)
Const cProcedureName As String = "Log::Output"

Dim hFile As Long

On Error GoTo OutputError

' Everything must be right for us to log the passed text
If CanOutput Then

' Prefix log text with timestamp
If TimeStamp Then strText = Now & vbTab & strText

' Open log file for append
hFile = FreeFile
Open mstrPath & mstrFile For Append Access Write As hFile

' Write the output and tidy up
Print #hFile, strText
Close hFile
End If

OutputExit:
Exit Sub

OutputError:
mboolEnabled = False
Err.Raise Err.Number, cProcedureName, Err.Description
End Sub ' Output

Public Sub KillLog()
On Error GoTo HandleError

' Delete the current log file if it exists
If Len(Dir$(mstrPath & mstrFile)) > 0 Then
Kill mstrPath & mstrFile
End If

ExitHere:
Exit Sub

HandleError:
mboolEnabled = False
Err.Raise vbObjectError + 8001, "Log::Kill", _
Err.Description
Resume ExitHere
End Sub ' Reset

Public Property Get Path() As String
Path = mstrPath
End Property
Public Property Let Path(ByVal strPath As String)
strPath = Trim$(strPath)
If Right$(strPath, 1) <> Application.PathSeparator _
Then strPath = strPath & Application.PathSeparator
mstrPath = Trim$(strPath)
End Property

Public Property Get File() As String
File = mstrFile
End Property
Public Property Let File(ByVal FileName As String)
mstrFile = FileName
End Property

Public Property Get Enabled() As Boolean
Enabled = mboolEnabled
End Property
Public Property Let Enabled(ByVal EnableLogFile As Boolean)
mboolEnabled = EnableLogFile
End Property

Public Property Get TimeStamp() As Boolean
TimeStamp = mboolTimeStamp
End Property
Public Property Let TimeStamp(ByVal TimeStampOutput As Boolean)
mboolTimeStamp = TimeStampOutput
End Property

Public Property Get CanOutput() As Boolean
CanOutput = LenB(Path) > 0 And LenB(File) > 0 And Enabled
End Property

Private Sub Class_Initialize()
Me.Enabled = True
End Sub

****** End of LogIt Class code *******

Public Sub LogItTest()
Dim logFile As LogIt

' Create log file
Set logFile = New LogIt
logFile.Path = "Macintosh HD:Users:UserName:Desktop:"
logFile.File = "DEBUG LogItTest.txt"

' Use it....
'logFile.KillLog 'To in effect, clear log, if desired.
logFile.TimeStamp = True
logFile.Output "This is the first log entry"
logFile.TimeStamp = False
logFile.Output "This is the second log entry "
Set logFile = Nothing
End Sub

Multiple logfiles could be going at the same time to log only certain parts
of code. You just need to create multiple instances of each Logit class.

Windows users could also use environmental variables:
logFile.Path = Environ("HOMEDRIVE") & Environ("HOMEPATH") & "\My Documents\"

Bob,
I tried playing around with the immediate window and sendkeys to control it
while using the extension reference for the interface. It just seemed to be
too quirky.

But while researching I found this cool piece of code to create a LogIt
class: (Peter Hewett)
<http://www.tech-archive.net/Archive/Word/microsoft.public.word.vba.general/
2004-04/0495.html>

With this code it is easy to emulate the debug.print functionality.
Multiple logs can be created.
[object].TimeStamp = True or False between output lines for timestamping or
not.

I guess one of the biggest issues is, because I can't reproduce the error
on
a regular basis, I can't watch my immediates window to check how far the
code
has gone (debug.print). Is there a way to write my Immediates window to a
log
file automatically?
 

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