Boolean variable being changed, but not by code

J

JimO

The problem is that a global boolean variable is being changed from true to
false, sometimes. We saw it happen three out of 11 tests. It is not being
reset by code. How can this happen?

The biggest fears is that if the value of one variable can be changed by the
"system" then any variable can be changed by the system.


Facts.
The database references the boolean variable only five times and never in
either code library.
Once to declare: Public gbooUseCDO as Boolean
Once when intializing and the initialization routine is executed only
once per run.
If conditions = true
gbooUseCDO = true <====== Set to true here
else
gbooUseCDO = false
end if

Twice at various points.
if gbooUseCDO then <====== three out of ten times the
value was False at this point.
code
else
code
endif

Additional information.
The database was originally coded in Access 2000, ported to 2002, and now
2003. "Track name AutoCorrect Info" was enabled on until recently, although
this variable was added after disabling the option.

References
Visual Basic for Applications
Microsoft Access 11.0 Object Library
OLE Automation
Microsoft ActiveX Data Objects 2.7 Library
Microsoft Excel 11.0 Object Library
and the two .mda code librarys

System configuration
MS Windows Server 2003 Standard Edition SP 1
Access 2003 SP2 (MS Office Professional Edition)
The server is being accessed by remote desktop via a VPN connection .
 
J

JimO

I noticed that this group is not being looked at, so another thread was
opened in modulesdaovba.

Sorry.
 
J

John Nurick

Some suggestions:

-Run with the VBE options set to "Break on All Errors"

-Set a watch to break when the value of gbooUseCDO changes.

-Use Debug.Assert.
 
J

JimO

We did not use the break on all errrors, I will try that and run the jub
multiple times to see if anything strange happens.

A watch was set but once set the variable never changed except when set in
the initialization routine at the beginning of the code.
 
J

John Nurick

The value of gbooUseCDO is changing, so there is *something* that is
changing it (even if it's a passing magnetic monopole).

Are you saying that you had a watch set to break when gbooUseCDO
changes, but that the values changed without triggering the watch? That
surprises me, but I don't know what bugs there are in the watch system.

I'd try inserting
Debug.Assert gbooUseCDO = True
very liberally, not just in the obvious places in the execution paths
you think are involved but across all modules (code, form and class) in
the project.

Ordinarily I'd use
If gbooDebugging Then
Debug.Assert...
End If
but since the problem is with a global I feel that might not be such a
good idea<g>.

We did not use the break on all errrors, I will try that and run the jub
multiple times to see if anything strange happens.

A watch was set but once set the variable never changed except when set in
the initialization routine at the beginning of the code.
 
J

JimO

I agree that something is changing the value, even if it is access losing
the value.
Are you saying that you had a watch set to break when gbooUseCDO...
No. The problem was noticed during one run. We ran again to test and sure
enough, the variable had been changed. A third test was made with a watch
set, but the variable was misnamed. In each of these cases a breakpoint was
set at the point the variable was set and tested and the variable had
reverted from True to False. Of course, False is the default for a boolean
so given the code it is likely that the set value was lost and the boolean
reverted to the default. It has been suggested that an unhandled error
condition caused the value to be reset.

The fourth through tenth test was made with a Watch set up. The variable
was always correct at the point that it was tested. Of course, this program
had been run many times before without the problem showing up and, since a
dialog box is displayed when the value is false, the problem would have been
noticed.

Break on all errors was enabled and a test found that in some cases an exit
routine was trying to close a closed recordset. The error was being
"handled" by an "On Error goto Next" but now the close only happens if the
recordset was opened. (A flag is set and tested.).

The only error that still exists is where the code is checking to see if an
object exists. Since the object being checked is a table then the slimmed
down code used is.
Function fnDoesObjectExist(dstrObjectName as String, dintObjectType As
Integer) As Boolean
On Error GoTo ErrorRoutine
Const cintObjectDoesNotExist As Integer = 0
Dim cat As ADOX.Catalog

Set cat = New ADOX.Catalog
cat.ActiveConnection = CurrentProject.Connection

'Generates an error if the table does not exist
If Len(cat.Tables.Item(dstrObjectName).Name) > 0 Then
jmofn_DoesObjectExist = True
End If
ExitRoutine:
On Error Resume Next
Set cat = Nothing
Exit Function
ErrorRoutine:
Resume ExitRoutine
end function

I will change the code to loop throught the catalong and check for a match
rather than allowing the "unhandled" error. Perhaps that will fix the
problem, although, since the code would have failed in all tests the value
should have been reset in all tests, which indicates an unhandled error does
not always cause the problem making testing more difficult.

Thanks for your help.


John Nurick said:
The value of gbooUseCDO is changing, so there is *something* that is
changing it (even if it's a passing magnetic monopole).

Are you saying that you had a watch set to break when gbooUseCDO
changes, but that the values changed without triggering the watch? That
surprises me, but I don't know what bugs there are in the watch system.

I'd try inserting
Debug.Assert gbooUseCDO = True
very liberally, not just in the obvious places in the execution paths
you think are involved but across all modules (code, form and class) in
the project.

Ordinarily I'd use
If gbooDebugging Then
Debug.Assert...
End If
but since the problem is with a global I feel that might not be such a
good idea<g>.
 
R

Robert Morley

Just an outside-the-box thought here...is it possible you've declared the
variable in more than one place, and the local declaration is overriding the
global one?


Rob

JimO said:
I agree that something is changing the value, even if it is access losing
the value.
Are you saying that you had a watch set to break when gbooUseCDO...
No. The problem was noticed during one run. We ran again to test and
sure enough, the variable had been changed. A third test was made with a
watch set, but the variable was misnamed. In each of these cases a
breakpoint was set at the point the variable was set and tested and the
variable had reverted from True to False. Of course, False is the default
for a boolean so given the code it is likely that the set value was lost
and the boolean reverted to the default. It has been suggested that an
unhandled error condition caused the value to be reset.

The fourth through tenth test was made with a Watch set up. The variable
was always correct at the point that it was tested. Of course, this
program had been run many times before without the problem showing up and,
since a dialog box is displayed when the value is false, the problem would
have been noticed.

Break on all errors was enabled and a test found that in some cases an
exit routine was trying to close a closed recordset. The error was being
"handled" by an "On Error goto Next" but now the close only happens if the
recordset was opened. (A flag is set and tested.).

The only error that still exists is where the code is checking to see if
an object exists. Since the object being checked is a table then the
slimmed down code used is.
Function fnDoesObjectExist(dstrObjectName as String, dintObjectType As
Integer) As Boolean
On Error GoTo ErrorRoutine
Const cintObjectDoesNotExist As Integer = 0
Dim cat As ADOX.Catalog

Set cat = New ADOX.Catalog
cat.ActiveConnection = CurrentProject.Connection

'Generates an error if the table does not exist
If Len(cat.Tables.Item(dstrObjectName).Name) > 0 Then
jmofn_DoesObjectExist = True
End If
ExitRoutine:
On Error Resume Next
Set cat = Nothing
Exit Function
ErrorRoutine:
Resume ExitRoutine
end function

I will change the code to loop throught the catalong and check for a match
rather than allowing the "unhandled" error. Perhaps that will fix the
problem, although, since the code would have failed in all tests the value
should have been reset in all tests, which indicates an unhandled error
does not always cause the problem making testing more difficult.

Thanks for your help.
 
R

Robert Morley

A truly unhandled error should reset all values IF you choose the "End"
button. If you choose to "Debug" and then move on to a different line, or
"handle" the error by-hand, then nothing is lost and the code should
continue. If, however, you see no error message with the "Debug" option,
then something is handling the error somehow. Looking through the code you
provided, it looks to me like the error is being handled just fine. Did I
miss something?



Rob

JimO said:
I agree that something is changing the value, even if it is access losing
the value.
Are you saying that you had a watch set to break when gbooUseCDO...
No. The problem was noticed during one run. We ran again to test and
sure enough, the variable had been changed. A third test was made with a
watch set, but the variable was misnamed. In each of these cases a
breakpoint was set at the point the variable was set and tested and the
variable had reverted from True to False. Of course, False is the default
for a boolean so given the code it is likely that the set value was lost
and the boolean reverted to the default. It has been suggested that an
unhandled error condition caused the value to be reset.

The fourth through tenth test was made with a Watch set up. The variable
was always correct at the point that it was tested. Of course, this
program had been run many times before without the problem showing up and,
since a dialog box is displayed when the value is false, the problem would
have been noticed.

Break on all errors was enabled and a test found that in some cases an
exit routine was trying to close a closed recordset. The error was being
"handled" by an "On Error goto Next" but now the close only happens if the
recordset was opened. (A flag is set and tested.).

The only error that still exists is where the code is checking to see if
an object exists. Since the object being checked is a table then the
slimmed down code used is.
Function fnDoesObjectExist(dstrObjectName as String, dintObjectType As
Integer) As Boolean
On Error GoTo ErrorRoutine
Const cintObjectDoesNotExist As Integer = 0
Dim cat As ADOX.Catalog

Set cat = New ADOX.Catalog
cat.ActiveConnection = CurrentProject.Connection

'Generates an error if the table does not exist
If Len(cat.Tables.Item(dstrObjectName).Name) > 0 Then
jmofn_DoesObjectExist = True
End If
ExitRoutine:
On Error Resume Next
Set cat = Nothing
Exit Function
ErrorRoutine:
Resume ExitRoutine
end function

I will change the code to loop throught the catalong and check for a match
rather than allowing the "unhandled" error. Perhaps that will fix the
problem, although, since the code would have failed in all tests the value
should have been reset in all tests, which indicates an unhandled error
does not always cause the problem making testing more difficult.

Thanks for your help.
 
J

JimO

Your original question was; "Was the variable declared multiple times." The
answer is no. It was declared once, set once, and tested once. This, was
checked multiple times because we assumed that we had to have missed
something obvious.


We tested to see if other global variables had been reset and none that we
checked had been reset.

The code shown was the remaining code that trigger when "Break on all
errors" was enabled. Otherwise, the code executed from start to end without
stopping.

If "handling" an error by entering debug mode and stepping through
"unhandled" errors does not cause variables to be reset then handling them
with "On Error Resume Next" should not cause them to be reset either.
Unless, "that is different." ;)


Thanks for the suggestions and tips.




Robert Morley said:
A truly unhandled error should reset all values IF you choose the "End"
button. If you choose to "Debug" and then move on to a different line, or
"handle" the error by-hand, then nothing is lost and the code should
continue. If, however, you see no error message with the "Debug" option,
then something is handling the error somehow. Looking through the code you
provided, it looks to me like the error is being handled just fine. Did I
miss something?



Rob
 
R

Robert Morley

You're right in thinking that "On Error Resume Next" won't reset the
variables, so that's not it. I tend to forget about the "Break on All
Errors" option, my bad on that count.

Going even further afield, are you using any of the various API memory copy
routines anywhere in your code? It's possible it's supposed to be writing
to something else, but is in fact clobbering your global variable. That's a
shot-in-the-dark, but it sounds to me like you've covered all the
"reasonable" possibilities. :)



Rob
 
J

John Nurick

Assertions should catch that, shouldn't they?

Going even further afield, are you using any of the various API memory copy
routines anywhere in your code? It's possible it's supposed to be writing
to something else, but is in fact clobbering your global variable. That's a
shot-in-the-dark, but it sounds to me like you've covered all the
"reasonable" possibilities. :)



Rob
 
R

Robert Morley

No, an assertion would only catch if the variable was change through
"normal" means; if memory copy is clobbering it, VB will be unaware of the
change.


Rob
 
J

JimO

No. Hopefully, a memory copy that overwrites such data would generate a
larger problem than resetting a variable! hehe, but, it could happen.
 
R

Robert Morley

I was thinking of something relatively straightforward, like doing pointer
math instead of math on the result, or something of that nature. If, for
instance, a long variable is declared immediately preceding the boolean, and
you then do a memory copy on lngPointer + 4, the boolean could be
overwritten.

Another possibility, I think, might be if you passed a structure to an API
call where the structure is shorter than expected. If that structure is
declared just before the boolean, there again, there might be overwriting
issues.

These are really unusual circumstances, far more likely to crop up in C than
in VB, but still quite possible with VB.


Rob
 
J

John Nurick

I don't understand, Rob. We've declared a Boolean and VB/A has told
Windows to allocate two bytes somewhere in RAM.

Are you saying that it's possible for another bit of code to change the
value of these bytes without affecting the value of the Boolean?

....actually, in the special case of a Boolean it should be possible,
within limits, because the 65536 possible values of the two bytes of
memory are mapped onto the two possible values of the Boolean.

So perhaps a troubleshooting step is to declare the global as Integer
instead of Boolean, and use
Debug.Assert gintXXX = -1
That way, any change in the values in RAM will show up in VBA.



No, an assertion would only catch if the variable was change through
"normal" means; if memory copy is clobbering it, VB will be unaware of the
change.


Rob
 
R

Robert Morley

You're right, it does allocate two bytes somewhere (even though technically
it needs only one bit), and under "normal" circumstances, a watch will pick
up any changes to that. But when you start using API calls, you're
bypassing the normal flow of things in VB, and while it's conceivable, I
would be very surprised if it picked up on changes arising from an API
call...especially if it happens to be a buggy call.

If you're not using memory copy API calls of any kind, then you *probably*
don't have to worry.


Rob

John Nurick said:
I don't understand, Rob. We've declared a Boolean and VB/A has told
Windows to allocate two bytes somewhere in RAM.

Are you saying that it's possible for another bit of code to change the
value of these bytes without affecting the value of the Boolean?

...actually, in the special case of a Boolean it should be possible,
within limits, because the 65536 possible values of the two bytes of
memory are mapped onto the two possible values of the Boolean.

So perhaps a troubleshooting step is to declare the global as Integer
instead of Boolean, and use
Debug.Assert gintXXX = -1
That way, any change in the values in RAM will show up in VBA.



No, an assertion would only catch if the variable was change through
"normal" means; if memory copy is clobbering it, VB will be unaware of
the
change.


Rob

John Nurick said:
Assertions should catch that, shouldn't they?

On Thu, 21 Sep 2006 16:45:21 -0400, "Robert Morley"

Going even further afield, are you using any of the various API memory
copy
routines anywhere in your code? It's possible it's supposed to be
writing
to something else, but is in fact clobbering your global variable.
That's
a
shot-in-the-dark, but it sounds to me like you've covered all the
"reasonable" possibilities. :)



Rob

Your original question was; "Was the variable declared multiple
times."
The answer is no. It was declared once, set once, and tested once.
This,
was checked multiple times because we assumed that we had to have
missed
something obvious.


We tested to see if other global variables had been reset and none
that
we
checked had been reset.

The code shown was the remaining code that trigger when "Break on all
errors" was enabled. Otherwise, the code executed from start to end
without stopping.

If "handling" an error by entering debug mode and stepping through
"unhandled" errors does not cause variables to be reset then handling
them
with "On Error Resume Next" should not cause them to be reset either.
Unless, "that is different." ;)


Thanks for the suggestions and tips.




A truly unhandled error should reset all values IF you choose the
"End"
button. If you choose to "Debug" and then move on to a different
line,
or
"handle" the error by-hand, then nothing is lost and the code should
continue. If, however, you see no error message with the "Debug"
option,
then something is handling the error somehow. Looking through the
code
you provided, it looks to me like the error is being handled just
fine.
Did I miss something?



Rob

I agree that something is changing the value, even if it is access
losing
the value.

Are you saying that you had a watch set to break when gbooUseCDO...
No. The problem was noticed during one run. We ran again to test
and
sure enough, the variable had been changed. A third test was made
with
a watch set, but the variable was misnamed. In each of these cases
a
breakpoint was set at the point the variable was set and tested and
the
variable had reverted from True to False. Of course, False is the
default for a boolean so given the code it is likely that the set
value
was lost and the boolean reverted to the default. It has been
suggested
that an unhandled error condition caused the value to be reset.

The fourth through tenth test was made with a Watch set up. The
variable was always correct at the point that it was tested. Of
course,
this program had been run many times before without the problem
showing
up and, since a dialog box is displayed when the value is false, the
problem would have been noticed.

Break on all errors was enabled and a test found that in some cases
an
exit routine was trying to close a closed recordset. The error was
being "handled" by an "On Error goto Next" but now the close only
happens if the recordset was opened. (A flag is set and tested.).

The only error that still exists is where the code is checking to
see
if
an object exists. Since the object being checked is a table then
the
slimmed down code used is.
Function fnDoesObjectExist(dstrObjectName as String, dintObjectType
As
Integer) As Boolean
On Error GoTo ErrorRoutine
Const cintObjectDoesNotExist As Integer = 0
Dim cat As ADOX.Catalog

Set cat = New ADOX.Catalog
cat.ActiveConnection = CurrentProject.Connection

'Generates an error if the table does not exist
If Len(cat.Tables.Item(dstrObjectName).Name) > 0 Then
jmofn_DoesObjectExist = True
End If
ExitRoutine:
On Error Resume Next
Set cat = Nothing
Exit Function
ErrorRoutine:
Resume ExitRoutine
end function

I will change the code to loop throught the catalong and check for a
match rather than allowing the "unhandled" error. Perhaps that will
fix
the problem, although, since the code would have failed in all tests
the
value should have been reset in all tests, which indicates an
unhandled
error does not always cause the problem making testing more
difficult.

Thanks for your help.


The value of gbooUseCDO is changing, so there is *something* that
is
changing it (even if it's a passing magnetic monopole).

Are you saying that you had a watch set to break when gbooUseCDO
changes, but that the values changed without triggering the watch?
That
surprises me, but I don't know what bugs there are in the watch
system.

I'd try inserting
Debug.Assert gbooUseCDO = True
very liberally, not just in the obvious places in the execution
paths
you think are involved but across all modules (code, form and
class)
in
the project.

Ordinarily I'd use
If gbooDebugging Then
Debug.Assert...
End If
but since the problem is with a global I feel that might not be
such
a
good idea<g>.

On Wed, 20 Sep 2006 15:58:17 -0500, "JimO"

We did not use the break on all errrors, I will try that and run
the
jub
multiple times to see if anything strange happens.

A watch was set but once set the variable never changed except when
set
in
the initialization routine at the beginning of the code.

Some suggestions:

-Run with the VBE options set to "Break on All Errors"

-Set a watch to break when the value of gbooUseCDO changes.

-Use Debug.Assert.

On Wed, 20 Sep 2006 13:02:29 -0500, "JimO"

The problem is that a global boolean variable is being changed
from
true
to
false, sometimes. We saw it happen three out of 11 tests. It is
not
being
reset by code. How can this happen?

The biggest fears is that if the value of one variable can be
changed
by
the
"system" then any variable can be changed by the system.


Facts.
The database references the boolean variable only five times and
never in
either code library.
Once to declare: Public gbooUseCDO as Boolean
Once when intializing and the initialization routine is
executed
only
once per run.
If conditions = true
gbooUseCDO = true <====== Set to true here
else
gbooUseCDO = false
end if

Twice at various points.
if gbooUseCDO then <====== three out of ten
times the
value was False at this point.
code
else
code
endif

Additional information.
The database was originally coded in Access 2000, ported to 2002,
and
now
2003. "Track name AutoCorrect Info" was enabled on until
recently,
although
this variable was added after disabling the option.

References
Visual Basic for Applications
Microsoft Access 11.0 Object Library
OLE Automation
Microsoft ActiveX Data Objects 2.7 Library
Microsoft Excel 11.0 Object Library
and the two .mda code librarys

System configuration
MS Windows Server 2003 Standard Edition SP 1
Access 2003 SP2 (MS Office Professional Edition)
The server is being accessed by remote desktop via a VPN
connection .
 

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