Why Doesn't this Code Error?

G

Greg Maxey

Insert a 4 or more empty table in a document and run this code:

Sub Demo()
Dim oTbl As Word.Table
Dim i As Long
Set oTbl = ActiveDocument.Tables(1)
Set oTbl = Nothing
With oTbl
For i = .Rows.Count To 1 Step -1
If i = 3 Then Set oTbl = Nothing
.Rows(i).Delete
Next i
End With
End Sub

Why doesn't this code throw a RTE 91 when it reaches the point where it
tries to delete a row after the oTbl object has been set to Nothing?
 
J

Janine_ribbonspace

Greg I can't answer but this works:

Sub Demo1()
Dim aTbl As Table
Dim i As Long
Set aTbl = Nothing

If Selection.Information(wdWithInTable) Then
Set aTbl = ActiveDocument.Tables(1)

End If

With aTbl

For i = .Rows.Count To 1 Step -1
If i = 3 Then Set aTbl = Nothing
.Rows(i).Delete
Next i

End With
End Sub
 
J

Janine_ribbonspace

This works but not sure if it helps you.

Sub Demo1()
Dim aTbl As Table
Dim i As Long


'If Selection.Information(wdWithInTable) Then
Set aTbl = ActiveDocument.Tables(1)

With aTbl

For i = .Rows.Count To 1 Step -1
If i = 3 Then Set aTbl = Nothing

aTbl.Rows(i).Delete

Exit For 'Exit for added

Next i

End With

End Sub
 
G

Graham Mayor

If you
Set oTbl = ActiveDocument.Tables(1)
then immediately
Set oTbl = Nothing
as in your example, then the for/next loop will not find oTbl
If you remove that line, the for/next loop will act on the whole of oTbl
already configured, though at i = 3 oTbl has been set to Nothing as can be
established by adding a message box
If i = 2 Then MsgBox oTbl
Whether that is errant behaviour or by design I hesitate to guess. I suspect
the latter.
However if the plan is to leave three rows you need to quit the loop

Dim oTbl As Word.Table
Dim i As Long
Set oTbl = ActiveDocument.Tables(1)
With oTbl
For i = .Rows.Count To 1 Step -1
If i = 3 Then
Set oTbl = Nothing
Exit For
End If
.Rows(i).Delete
Next i
End With


--
<>>< ><<> ><<> <>>< ><<> <>>< <>><<>
Graham Mayor - Word MVP


<>>< ><<> ><<> <>>< ><<> <>>< <>><<>
 
P

Pesach Shelnitz

Hi Greg,

Setting a variable to Nothing does not immediately make it non-existent. It
does set the values of its properties to their default values and more.
According to MSDN (http://msdn.microsoft.com/en-us/library/0x9tb07z.aspx),
"When you assign Nothing to an object variable, it no longer refers to any
object instance. If the variable had previously referred to an instance,
setting it to Nothing does not terminate the instance itself. The instance is
terminated, and the memory and system resources associated with it are
released, only after the garbage collector (GC) detects that there are no
active references remaining."

The observed behavior is expected. In your macro, the line containing
Nothing before the For loop makes the content of the Rows.Count property
meaningless, and RTE 91 is raised when the loop is reached. If the line
containing Nothing before the loop is commented out, the loop can be
executed. When the third row of the table is reached, setting oTbl to Nothing
does nothing to the Delete method of its Rows subcollection, which can
continue to Delete rows using data about the referenced table that the
macro-executing code can still access.

I don't know enough to predict with certainty what a "nothinged" object can
still do, but this excercise has been a good reminder that our macros should
set the objects that they create to Nothing when they are no longer needed so
that the garbage collector can do its job and free up memory and resources.
 
G

Greg Maxey

Janine,

Yes, like mine, it works. Why? Why doesn't it throw an error after oTbl is
set = Nothing?
 
G

Greg Maxey

Graham,

The whole plan was to see what would happen if the oTbl object was set to
nothing. I am puzzled by an error that a client is getting (described in
the RTE 4605 thread). I thought the cause might be related to something to
do with the table object. Still puzzled as to why when oTBL is set to
nothing the code doesn't crash and burn on the next .Rows(i).Delete line.
 
J

Jonathan West

Greg Maxey said:
Insert a 4 or more empty table in a document and run this code:

Sub Demo()
Dim oTbl As Word.Table
Dim i As Long
Set oTbl = ActiveDocument.Tables(1)
Set oTbl = Nothing
With oTbl
For i = .Rows.Count To 1 Step -1
If i = 3 Then Set oTbl = Nothing
.Rows(i).Delete
Next i
End With
End Sub

Why doesn't this code throw a RTE 91 when it reaches the point where it
tries to delete a row after the oTbl object has been set to Nothing?


You need to understand what the With-End With statement block does.

In practice, what it does is create a new (unnamed) object variable which
references the contents of the With statement.

So the expressions within the With-End With block that start with a period
are referencing the unnamed variable. What you have written is functionally
equivalent to the following

Sub Demo2()
Dim oTbl As Word.Table
Dim i As Long
Set oTbl = ActiveDocument.Tables(1)
Dim oTbl2 as Table
Set oTbl2 = oTbl
For i = oTbl2 .Rows.Count To 1 Step -1
If i = 3 Then Set oTbl = Nothing
oTbl2.Rows(i).Delete
Next i
End Sub

Now it is hopefully clearer what is happening within the loop. You've set
oTbl to Nothing, but oTbl2 still exists and so the command
oTbl2.Rows(i).Delete does not error.
 
G

Greg Maxey

Jonathan,

Yes that makes sense. I am in the dark here as to why a client's client is
getting an error 4605 "The Height method or property is not available
because some or all of the object does not refer to a table" on a line of
code that uses:

Set recTable = ActiveDocument.Tables(1)
With RecTable
....
....
.Rows(3).Height = 1
....
....
End With

I can't duplicate it, she can't duplicate it, but sees it occuring on the
clients PC.

So I was just trying to see how I might force that error to occur.

Thanks.
 
G

Greg Maxey

Jonathan,

Yes that makes sense. I am in the dark here as to why a client's client is
getting an error 4605 "The Height method or property is not available
because some or all of the object does not refer to a table" on a line of
code that uses:

Set recTable = ActiveDocument.Tables(1)
With RecTable
....
....
.Rows(3).Height = 1
....
....
End With

I can't duplicate it, she can't duplicate it, but sees it occuring on the
clients PC.

So I was just trying to see how I might force that error to occur.

Thanks.
 
T

Tony Jollans

What version of Word are you running? It throws an error 91 for me in 2003
and 2007 - on the "For i = .Rows.Count ..." statement, as expected. And,
FWIW, I think all the explanations you have received so far are tosh.
 
T

Tony Jollans

Having looked a bit closer I see that the first "Set oTbl = Nothing" should
not be there and that you are really asking about the second (inside the
loop) - and I agree with Jonathan about the reason for that.
 
G

Greg Maxey

Tony,

In my typcial sometimes careless way if forgot to take out the first Set
oTbl = Nothing statement
in the macro I posted.

I added it in when I was puzzling over the If i = 3 Then Set oTbl = Nothing
line.

Like with you, that line does throw an error as I expected. With it gone
the:

If i = 3 Then Set oTbl = Nothing

line doesn't throw an error like I expected.

Without a good dictionary handy I will leave "tosh" alone.

Sorry for the confusion and with that cleared up, what Pesach and Jonathan
have offered is the best I've got.






Sub Demo()
Dim oTbl As Word.Table
Dim i As Long
Set oTbl = ActiveDocument.Tables(1)
With oTbl
For i = .Rows.Count To 1 Step -1
If i = 3 Then Set oTbl = Nothing
.Rows(i).Delete
Next i
End With
End Sub
 
J

Jonathan West

Greg Maxey said:
Jonathan,

Yes that makes sense. I am in the dark here as to why a client's client
is getting an error 4605 "The Height method or property is not available
because some or all of the object does not refer to a table" on a line of
code that uses:

Set recTable = ActiveDocument.Tables(1)
With RecTable
....
....
.Rows(3).Height = 1
....
....
End With

I can't duplicate it, she can't duplicate it, but sees it occuring on the
clients PC.

So I was just trying to see how I might force that error to occur.

Sometimes apparently random errors can come up if the template has become
bloated. try using the VBA COde cleaner on it and see if the problem goes
away.
 
K

Karl E. Peterson

Jonathan said:
You need to understand what the With-End With statement block does.

In practice, what it does is create a new (unnamed) object variable which
references the contents of the With statement.

So the expressions within the With-End With block that start with a period
are referencing the unnamed variable. What you have written is functionally
equivalent to the following

Hmmmm, the unnamed variable would be assigned the reference contained by the
original variable at the time the With block is entered, though, and not before.
This ought to be fairly easily demonstrated. When I create a brand new document,
add four empty tables, and put this code in a new clean module:

Public Sub Demo()
Dim oTbl As Word.Table
Dim i As Long
Set oTbl = ActiveDocument.Tables(1)
Set oTbl = Nothing
With oTbl
Debug.Print oTbl Is Nothing
For i = .Rows.Count To 1 Step -1
If i = 3 Then Set oTbl = Nothing
.Rows(i).Delete
Next i
End With
End Sub

I see "True" appear in the Immediate window, followed by a run-time error 91 --
"Object variable or With block variable not set" -- on the following (For i =) line
of code.

Greg, I think your document's just a bit hosed, and would concur with Jonathan's
suggestion to run it through a code cleaner. I'm seeing almost exactly the behavior
you expected, here.
 
K

Karl E. Peterson

Tony said:
Having looked a bit closer I see that the first "Set oTbl = Nothing" should
not be there and that you are really asking about the second (inside the
loop) - and I agree with Jonathan about the reason for that.

Ahhhhh! I didn't even *see* the second attempt to clear that variable.

Yes, Jonathan's and Pesach's explanations were (of course!) spot on, in that case.
 
K

Karl E. Peterson

Karl said:
Hmmmm, the unnamed variable would be assigned the reference contained by the
original variable at the time the With block is entered, though, and not before.
This ought to be fairly easily demonstrated. When I create a brand new document,
add four empty tables, and put this code in a new clean module:

Public Sub Demo()
Dim oTbl As Word.Table
Dim i As Long
Set oTbl = ActiveDocument.Tables(1)
Set oTbl = Nothing
With oTbl
Debug.Print oTbl Is Nothing
For i = .Rows.Count To 1 Step -1
If i = 3 Then Set oTbl = Nothing
.Rows(i).Delete
Next i
End With
End Sub

I see "True" appear in the Immediate window, followed by a run-time error 91 --
"Object variable or With block variable not set" -- on the following (For i =)
line
of code.

Greg, I think your document's just a bit hosed, and would concur with Jonathan's
suggestion to run it through a code cleaner. I'm seeing almost exactly the
behavior you expected, here.

Ignore. I was thrown by the first "Set oTbl = Nothing" call...
 
G

Greg Maxey

Karl,

Thanks.


Hmmmm, the unnamed variable would be assigned the reference contained
by the original variable at the time the With block is entered,
though, and not before. This ought to be fairly easily demonstrated. When
I create a brand new document, add four empty tables, and put
this code in a new clean module:
Public Sub Demo()
Dim oTbl As Word.Table
Dim i As Long
Set oTbl = ActiveDocument.Tables(1)
Set oTbl = Nothing
With oTbl
Debug.Print oTbl Is Nothing
For i = .Rows.Count To 1 Step -1
If i = 3 Then Set oTbl = Nothing
.Rows(i).Delete
Next i
End With
End Sub

I see "True" appear in the Immediate window, followed by a run-time
error 91 -- "Object variable or With block variable not set" -- on
the following (For i =) line of code.

Greg, I think your document's just a bit hosed, and would concur with
Jonathan's suggestion to run it through a code cleaner. I'm seeing
almost exactly the behavior you expected, here.
 

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