Discussion:
Detecting debug mode
(too old to reply)
Johan Stäck
2006-10-16 11:39:45 UTC
Permalink
Hello!

A fairly common requirement is to detect if your VB6 code is running
compiled or in the IDE.
I use this frequently.

However, I want to take it a step further, and detect (when in the IDE)
if the program is "running free" or being "single-stepped" (using F8).

I wonder if/how this can be done.

TIA

/Johan Stäck
Skellefteå
Sweden
expvb
2006-10-16 12:26:26 UTC
Permalink
Post by Johan Stäck
Hello!
A fairly common requirement is to detect if your VB6 code is running
compiled or in the IDE.
I use this frequently.
However, I want to take it a step further, and detect (when in the IDE) if
the program is "running free" or being "single-stepped" (using F8).
I wonder if/how this can be done.
TIA
/Johan Stäck
Skellefteå
Sweden
One way is to measure the time, so if the user is stepping through the code,
it takes some time. If the user was pressing and holding down F8, the step
time is defined by the repeat delay in the Control Panel. Here is some
sample code and a link to IsInIDE function:

Dim t As Single

t = Timer
' Test for IDE here
Debug.Print Timer - t

http://vbnet.mvps.org/code/core/isinide.htm
Ralph
2006-10-16 12:53:20 UTC
Permalink
Post by Johan Stäck
Hello!
A fairly common requirement is to detect if your VB6 code is running
compiled or in the IDE.
I use this frequently.
However, I want to take it a step further, and detect (when in the IDE)
if the program is "running free" or being "single-stepped" (using F8).
I wonder if/how this can be done.
I doubt it can be done because these are not actually modes or states. When
you send the debug command "single-step" the IDE places a hidden breakpoint
before the next statement then "runs-free".

Perhaps if you could be more specific about why you need such an indicator
we could suggest an alternative. Maybe using Debug.Assert would help.

-ralph
Johan Stäck
2006-10-16 14:24:59 UTC
Permalink
Post by Ralph
Post by Johan Stäck
Hello!
A fairly common requirement is to detect if your VB6 code is running
compiled or in the IDE.
I use this frequently.
However, I want to take it a step further, and detect (when in the IDE)
if the program is "running free" or being "single-stepped" (using F8).
I wonder if/how this can be done.
I doubt it can be done because these are not actually modes or states. When
you send the debug command "single-step" the IDE places a hidden breakpoint
before the next statement then "runs-free".
Perhaps if you could be more specific about why you need such an indicator
we could suggest an alternative. Maybe using Debug.Assert would help.
-ralph
Ok, I will give some information about what I want to accomplish.
In my application I use the VBaccelerator VBTrace utility a lot. (A
great utility by the way...)
It would be very convenient for me if I could skip all trace:ing when
single-stepping. (Without having to do a "step over" every time I
encounter a trace statement)

When "running free" (both compiled and IDE) I want trace:ing to be
performed normally.

/Johan
Ralph
2006-10-16 15:02:23 UTC
Permalink
Post by Johan Stäck
Post by Ralph
Post by Johan Stäck
Hello!
A fairly common requirement is to detect if your VB6 code is running
compiled or in the IDE.
I use this frequently.
However, I want to take it a step further, and detect (when in the IDE)
if the program is "running free" or being "single-stepped" (using F8).
I wonder if/how this can be done.
I doubt it can be done because these are not actually modes or states. When
you send the debug command "single-step" the IDE places a hidden breakpoint
before the next statement then "runs-free".
Perhaps if you could be more specific about why you need such an indicator
we could suggest an alternative. Maybe using Debug.Assert would help.
-ralph
Ok, I will give some information about what I want to accomplish.
In my application I use the VBaccelerator VBTrace utility a lot. (A
great utility by the way...)
It would be very convenient for me if I could skip all trace:ing when
single-stepping. (Without having to do a "step over" every time I
encounter a trace statement)
When "running free" (both compiled and IDE) I want trace:ing to be
performed normally.
/Johan
Just a guess, but the utility comes with source, you can likely rig your own
'toggle' either by fiddling with a global or registry setting. You could
create an Addin to mess with the former, or you could create a small app for
the latter and add it to your Tools menu to perform the toggle.

hth
-ralph
Ralph
2006-10-16 15:31:57 UTC
Permalink
Nevermind. I wasn't thinking - this would stop the 'trace' but not a step
thru.

You might bracket your asserts with code like this...
If ToggleNoTracing Then vbtrace Assert ....

-ralph
expvb
2006-10-16 15:57:10 UTC
Permalink
When I press and hold F8, lines are executed in 45 milliseconds intervals,
which is my keyboard repeat rate. Timer function has a resolution of 10 ms
or better in "new" systems, so it can detect if I used F5 or F8. Try the
following code and use break points to test it:



Option Explicit

Private Sub Form_Load()
Debug.Print IsInIDEStepMode()
Debug.Print IsInIDEStepMode()
Debug.Print IsInIDEStepMode()
Debug.Print IsInIDEStepMode()
Debug.Print IsInIDEStepMode()
End Sub

Public Function IsInIDEStepMode() As Boolean
Dim t1 As Single
Dim t2 As Single

If IsInIDE() Then
t1 = Timer
t2 = Timer
If t2 < t1 Then
t2 = t2 + 86400 ' Adjust for past midnight
End If
If t2 - t1 > 0.01 Then
' More than 10 milliseconds between lines
IsInIDEStepMode = True
End If
End If
End Function


IsInIDE function can be found here:

http://vbnet.mvps.org/code/core/isinide.htm
Jim Carlock
2006-10-16 17:19:07 UTC
Permalink
Post by expvb
When I press and hold F8, lines are executed in 45 milliseconds
intervals, which is my keyboard repeat rate. Timer function has
a resolution of 10 ms or better in "new" systems, so it can detect
if I used F5 or F8. Try the following code and use break points
The following code was taken from this link (watch the word wrap
in the newsreaders):
http://www.vbaccelerator.com/home/vb/code/libraries/XP_Visual_Styles/Preventing_Crashes_at_Shutdown/Clean_Unload_with_Manifest_Tester_zip_mMain_bas.asp

Private miIsInIDE As Long

Public Property Get InIDE() As Long
Debug.Assert (IsInIDE())
InIDE = m_bInIDE
End Property

Private Function IsInIDE() As Long
m_bInIDE = (m_bInIDE Or -1)
IsInIDE = m_bInIDE
End Function

There's another way to do the same thing using the following as well.

Public Function IsInIDE() As Long
On Error Resume Next
Debug.Print 1 / 0
If Err.Number Then IsInIDE = (IsInIDE Or 1)
End Function

Hope this helps.
--
Jim Carlock
Post replies to the group.
Larry Serflaten
2006-10-16 17:34:11 UTC
Permalink
Post by Jim Carlock
m_bInIDE = (m_bInIDE Or -1)
If Err.Number Then IsInIDE = (IsInIDE Or 1)
What's with their using Or for these???

LFS
Jim Carlock
2006-10-16 18:03:12 UTC
Permalink
Post by Larry Serflaten
Post by Jim Carlock
m_bInIDE = (m_bInIDE Or -1)
If Err.Number Then IsInIDE = (IsInIDE Or 1)
What's with their using Or for these???
Oops... the corrected code.

'---
Private miInIDE As Long

Public Property Get InIDE() As Long
Debug.Assert IsInIDE()
InIDE = miInIDE
End Property

Private Sub IsInIDE()
miInIDE = -1&
End Function
'---

The Or definitely makes it harder to read, doesn't it? Simpler
code is always a better way to go. I really don't know what
was going through my head there, Larry. <g> Been messing
with building a DLL in assembly language and I guess that
recent assembly language exploits induced it.

The above looks a lot better.

Thanks for the comment!
--
Jim Carlock
Post replies to the group.
Larry Serflaten
2006-10-16 18:16:01 UTC
Permalink
Post by Jim Carlock
Oops... the corrected code.
Correcting the correction...
Post by Jim Carlock
'---
Private miInIDE As Long
Public Property Get InIDE() As Long
Debug.Assert Not IsInIDE() ' We don't want to stop here....
InIDE = miInIDE
End Property
Private Sub IsInIDE()
miInIDE = -1&
End Function
'---
;-)
LFS
Bob O`Bob
2006-10-17 06:53:42 UTC
Permalink
Post by Larry Serflaten
Post by Jim Carlock
Oops... the corrected code.
Correcting the correction...
Post by Jim Carlock
'---
Private miInIDE As Long
Public Property Get InIDE() As Long
Debug.Assert Not IsInIDE() ' We don't want to stop here....
InIDE = miInIDE
End Property
Private Sub IsInIDE()
miInIDE = -1&
End Function
'---
still clearly a typ[o]ing job.

I mean, really - "Private Sub" ... "End Function" ??

Is it really so hard for people to simply copy & paste actual code?

And there's nothing "wrong" with the keyword 'True'.
Jim Carlock
2006-10-17 15:21:06 UTC
Permalink
'---
Private miInIDE As Long

Public Property Get InIDE() As Long
Debug.Assert Not IsInIDE()
InIDE = miInIDE
End Property

Private Function IsInIDE() As Long
miInIDE = &HFFFF
End Function
'---
Post by Bob O`Bob
And there's nothing "wrong" with the keyword 'True'.
Microsoft seems to drop some 16-bit support in their next
OS (Wis-duh). So perhaps converting all the Boolean VB
types to Longs helps?

I'm curious... how many here are testing Wis-duh?

I tested the code up above this time. I was messing trying
to figure a way to get the IsInIDE() function to return -1&,
other than the normal assignment, IsInIDE = -1&. I tried
things like:

Private Function IsInIDE() As Long
'miInIDE = &HFFFF
'IsInIDE = (miInIDE Or -1&)
IsInIDE = (miInIDE Or (miInIDE Or -1&))
End Function

And was hoping to get the assignment to work for the miInIDE
on the same line as well.

I also tried:

Debug.Assert miInIDE = IsInIDE()

But couldn't get the assignment to miInIDE to work there. The
Assert maintains it as a comparison. So the following works also
but it also detracts from the readability, so is it better than using
the Not?

'---
Private miInIDE As Long

Public Property Get InIDE() As Long
Debug.Assert miInIDE = IsInIDE()
InIDE = miInIDE
End Property

Private Function IsInIDE() As Long
miInIDE = &HFFFF
End Function
'---

::::-o-::::
Jim Carlock
Post replies to the group.
Larry Serflaten
2006-10-16 17:27:03 UTC
Permalink
Post by Johan Stäck
Ok, I will give some information about what I want to accomplish.
In my application I use the VBaccelerator VBTrace utility a lot. (A
great utility by the way...)
It would be very convenient for me if I could skip all trace:ing when
single-stepping. (Without having to do a "step over" every time I
encounter a trace statement)
When "running free" (both compiled and IDE) I want trace:ing to be
performed normally.
Go to the project's Properties and choose the Make tab. Under the
Conditional Compilation Settings, add the text "TRACEMODE = 0".
(Or change the value that is already there....)

You'll still go to the bas module but it will only be for two instructions.
What they've done is something like this:

Private Sub Form_Load()

Call Trace(1)

End Sub


#If TRACEMODE Then

' Called if tracemode is 1
Private Sub Trace(ByVal X)
' Code to handle Trace
MsgBox X ' sample
End Sub

#Else

' Called if tracemode is 0
Private Sub Trace(ByVal X)
End Sub

#End If

The only other way would be to define your own compiler constant
and use that for all your trace activity. Example:


Private Sub Form_Load()

#If DoTrace Then
Call Trace(1)
#End If

End Sub


You'd have to do that wherever you call out to Trace or Assert.
When you set DoTrace to 0 all three lines will be skipped. But
you'd have to remeber to set DoTrace to 1 when you do a final
build, to keep the tracing in the program.

HTH
LFS
Ulrich Korndoerfer
2006-10-17 06:39:10 UTC
Permalink
Hi,
Post by Johan Stäck
Hello!
A fairly common requirement is to detect if your VB6 code is running
compiled or in the IDE.
I use this frequently.
However, I want to take it a step further, and detect (when in the IDE)
if the program is "running free" or being "single-stepped" (using F8).
I wonder if/how this can be done.
It can be done using the undocumented EbMode function in the vba*.dll:

Private Declare Function EbMode Lib "vba5" () As Long 'vb5 ide
Private Declare Function EbMode Lib "vba6" () As Long 'vb6 ide

EbMode returns 1 if a programming is running and 2 if the program has
been halted (is in break mode).

But that alone does not help as, when it is called from VB code, even
when single stepping, in the moment it is called the function returns 1
because then the program is running.

So it must be called from the "outside", that is not from the program
under test but eg from windows itself. One way would be to use Paul
Catons API-Timer class. This class uses an assembler thunk for the timer
callback. In this thunk EbMode is called and, if 2 is returned, the
method to notificate in the program is not called. One would have to
modify this to just setting some memory location, reachable for the
program, to the last result of the EbMode call.

Assume a global variable in a module is used, named say "gMode". Then in
your code all calls to the traceing routines would have been needed to
rewritten like such:

If gMode = 1 Then Trace

However this is not a bullet proof method. Eg if by "stepping over" a
greater portion of code is run and in the meantime the timer fires, it
would set gMode to 1 and all remaining code to execute would see this mode.

BTW, there is a simple method for detecting if in IDE running, which
works also when it is embedded in a dll:

Private Declare Function GetModuleHandleA Lib "kernel32" _
(ByVal lpModuleName As String) As Long

Private Function InIde6() As Boolean
InIde = (GetModuleHandle("vba6") <> 0)
End Function

Private Function InIde5() As Boolean
InIde = (GetModuleHandle("vba5") <> 0)
End Function

:-)
--
Ulrich Korndoerfer

VB tips, helpers, solutions -> http://www.proSource.de/Downloads/

-----------------------------------------------------------------------
Plea for a bright future for VB classic.
Sign the petition to Microsoft: -> http://classicvb.org/petition/
-----------------------------------------------------------------------
Ralph
2006-10-17 12:44:27 UTC
Permalink
Post by Ulrich Korndoerfer
Hi,
Post by Johan Stäck
Hello!
<snipped>
BTW, there is a simple method for detecting if in IDE running, which
Private Declare Function GetModuleHandleA Lib "kernel32" _
(ByVal lpModuleName As String) As Long
Private Function InIde6() As Boolean
InIde = (GetModuleHandle("vba6") <> 0)
End Function
Private Function InIde5() As Boolean
InIde = (GetModuleHandle("vba5") <> 0)
End Function
This method needs to be used with care for Dlls as it reports whether or not
it is participating in a debugging session, not whether or not it itself is
running in an IDE.

-ralph
Ulrich Korndoerfer
2006-10-18 14:30:32 UTC
Permalink
Hi,
Post by Ralph
Post by Ulrich Korndoerfer
BTW, there is a simple method for detecting if in IDE running, which
Private Declare Function GetModuleHandleA Lib "kernel32" _
(ByVal lpModuleName As String) As Long
Private Function InIde6() As Boolean
InIde = (GetModuleHandle("vba6") <> 0)
End Function
Private Function InIde5() As Boolean
InIde = (GetModuleHandle("vba5") <> 0)
End Function
This method needs to be used with care for Dlls as it reports whether or not
it is participating in a debugging session, not whether or not it itself is
running in an IDE.
It reports both. If the Dll is used by an app running in the IDE (thats
what you call "debug session" I presume) it reports "In IDE" and if
itself runs in the IDE it always reports "In IDE", no matter wether the
user of the Dll is running compiled or in the Ide himself.

There are four possible combinations:

Application The Dll itself Report Truth
using the Dll

A Runs compiled Runs compiled Standalone App True , Dll True
B Runs compiled Runs in IDE In IDE App False, Dll True
C Runs in IDE Runs compiled In IDE App True , Dll False
D Runs in IDE Runs in IDE In IDE App True , Dll True

For the app case B fails. But I think this is a rather rare combination.
And the Dll should use for detecting its *own* runstate the Debug.Assert
kind. The goal of my method is to encapsulate an in IDE detection for
reuse in a dll. Others have done this using GetProcessName and the like.
But those suffer from the same behavior as mine.
--
Ulrich Korndoerfer

VB tips, helpers, solutions -> http://www.proSource.de/Downloads/

-----------------------------------------------------------------------
Plea for a bright future for VB classic.
Sign the petition to Microsoft: -> http://classicvb.org/petition/
-----------------------------------------------------------------------
Ralph
2006-10-18 16:17:51 UTC
Permalink
Post by Ulrich Korndoerfer
Hi,
Post by Ralph
Post by Ulrich Korndoerfer
BTW, there is a simple method for detecting if in IDE running, which
Private Declare Function GetModuleHandleA Lib "kernel32" _
(ByVal lpModuleName As String) As Long
Private Function InIde6() As Boolean
InIde = (GetModuleHandle("vba6") <> 0)
End Function
Private Function InIde5() As Boolean
InIde = (GetModuleHandle("vba5") <> 0)
End Function
This method needs to be used with care for Dlls as it reports whether or not
it is participating in a debugging session, not whether or not it itself is
running in an IDE.
It reports both. If the Dll is used by an app running in the IDE (thats
what you call "debug session" I presume) it reports "In IDE" and if
itself runs in the IDE it always reports "In IDE", no matter wether the
user of the Dll is running compiled or in the Ide himself.
Application The Dll itself Report Truth
using the Dll
A Runs compiled Runs compiled Standalone App True , Dll True
B Runs compiled Runs in IDE In IDE App False, Dll True
C Runs in IDE Runs compiled In IDE App True , Dll False
D Runs in IDE Runs in IDE In IDE App True , Dll True
For the app case B fails. But I think this is a rather rare combination.
And the Dll should use for detecting its *own* runstate the Debug.Assert
kind. The goal of my method is to encapsulate an in IDE detection for
reuse in a dll. Others have done this using GetProcessName and the like.
But those suffer from the same behavior as mine.
Interesting. But you are only confirming my warning.

This method only reports if the Dll is participating in a debugging
session - not whether or not it running in an IDE itself. There may be some
value in knowing this. Thus, if the App is running in the IDE and the Dll is
compiled, the Dll will report "True", ie. that it thinks it's running in an
IDE but it's not.

It also appears, based on your code, your reporting is incorrect.
(InIDE means true if running in the IDE.)
App Compiled - False; Dll Compiled - False
App Compiled - False; Dll in IDE - False
App In IDE - True; Dll Compiled - True
App In IDE - True; Dll in IDE - True

It tracks only the runstate of the App. In two out of four conditions this
method in a Dll is lying. Is that a reason enough to provide a warning? <g>

"And the Dll should use for detecting its *own* runstate the Debug.Assert
kind."
Bingo!

Need to change your signature to...
Private Function IsAppInIde6() As Boolean

-ralph
Ralph
2006-10-18 16:47:55 UTC
Permalink
Oops!
Post by Ralph
App Compiled - False; Dll in IDE - False
Should be
App Compiled - False; Dll in IDE - True

So it errors only once out of four, not two out of four. <g>

-ralph
Ulrich Korndoerfer
2006-10-18 17:49:13 UTC
Permalink
Hi,
Post by Ralph
Post by Ulrich Korndoerfer
Application The Dll itself Report Truth
using the Dll
A Runs compiled Runs compiled Standalone App True , Dll True
B Runs compiled Runs in IDE In IDE App False, Dll True
C Runs in IDE Runs compiled In IDE App True , Dll False
D Runs in IDE Runs in IDE In IDE App True , Dll True
For the app case B fails. But I think this is a rather rare combination.
And the Dll should use for detecting its *own* runstate the Debug.Assert
kind. The goal of my method is to encapsulate an in IDE detection for
reuse in a dll. Others have done this using GetProcessName and the like.
But those suffer from the same behavior as mine.
Interesting. But you are only confirming my warning.
This method only reports if the Dll is participating in a debugging
session - not whether or not it running in an IDE itself. There may be some
value in knowing this. Thus, if the App is running in the IDE and the Dll is
compiled, the Dll will report "True", ie. that it thinks it's running in an
IDE but it's not.
If the Dll runs in a "debug session" aka running in the IDE it has to
report InIde of course. And if its user runs in a debug session, it has
to report True too.
Post by Ralph
It also appears, based on your code, your reporting is incorrect.
(InIDE means true if running in the IDE.)
App Compiled - False; Dll Compiled - False
App Compiled - False; Dll in IDE - False
App In IDE - True; Dll Compiled - True
App In IDE - True; Dll in IDE - True
It tracks only the runstate of the App. In two out of four conditions this
method in a Dll is lying. Is that a reason enough to provide a warning? <g>
You corrected yourself already.

The main point is to give the app a reusable method from a dll, so that
is not necessary for each app needing such functionality to implement it
self.

Everybody has some methods he often needs and therefore stuff's them
away in a tool dll. So also an in IDE detector should reside there
(detecting if the *app* is running in the IDE).

The Debug.Assert kind of detection does *not* allow this. My mehtod
does. Its only itch is that the tool dll must not run in the IDE as then
the reported state for the *app* is incorrect.

But as already stated, this case (Dll in IDE and app compiled) is seldom
and cean be easily avodied (a tool dll mostly is used and not developed
:-) Of course one has to be aware if this flaw.
--
Ulrich Korndoerfer

VB tips, helpers, solutions -> http://www.proSource.de/Downloads/

-----------------------------------------------------------------------
Plea for a bright future for VB classic.
Sign the petition to Microsoft: -> http://classicvb.org/petition/
-----------------------------------------------------------------------
Ralph
2006-10-18 21:21:28 UTC
Permalink
Post by Ulrich Korndoerfer
Hi,
Post by Ralph
Post by Ulrich Korndoerfer
Application The Dll itself Report Truth
using the Dll
A Runs compiled Runs compiled Standalone App True , Dll True
B Runs compiled Runs in IDE In IDE App False, Dll True
C Runs in IDE Runs compiled In IDE App True , Dll False
D Runs in IDE Runs in IDE In IDE App True , Dll True
For the app case B fails. But I think this is a rather rare
combination.
Post by Ulrich Korndoerfer
Post by Ralph
Post by Ulrich Korndoerfer
And the Dll should use for detecting its *own* runstate the
Debug.Assert
Post by Ulrich Korndoerfer
Post by Ralph
Post by Ulrich Korndoerfer
kind. The goal of my method is to encapsulate an in IDE detection for
reuse in a dll. Others have done this using GetProcessName and the like.
But those suffer from the same behavior as mine.
Interesting. But you are only confirming my warning.
This method only reports if the Dll is participating in a debugging
session - not whether or not it running in an IDE itself. There may be some
value in knowing this. Thus, if the App is running in the IDE and the Dll is
compiled, the Dll will report "True", ie. that it thinks it's running in an
IDE but it's not.
If the Dll runs in a "debug session" aka running in the IDE it has to
report InIde of course. And if its user runs in a debug session, it has
to report True too.
Post by Ralph
It also appears, based on your code, your reporting is incorrect.
(InIDE means true if running in the IDE.)
App Compiled - False; Dll Compiled - False
App Compiled - False; Dll in IDE - False
App In IDE - True; Dll Compiled - True
App In IDE - True; Dll in IDE - True
It tracks only the runstate of the App. In two out of four conditions this
method in a Dll is lying. Is that a reason enough to provide a warning? <g>
You corrected yourself already.
The main point is to give the app a reusable method from a dll, so that
is not necessary for each app needing such functionality to implement it
self.
Everybody has some methods he often needs and therefore stuff's them
away in a tool dll. So also an in IDE detector should reside there
(detecting if the *app* is running in the IDE).
The Debug.Assert kind of detection does *not* allow this. My mehtod
does. Its only itch is that the tool dll must not run in the IDE as then
the reported state for the *app* is incorrect.
But as already stated, this case (Dll in IDE and app compiled) is seldom
and cean be easily avodied (a tool dll mostly is used and not developed
:-) Of course one has to be aware if this flaw.
As Mr. French likes to say (I think it is him) - horses for courses. If
every problem domain had the same ideal solution - we would be slinging
hamburgers for some excitement. <g>

-ralph

Continue reading on narkive:
Loading...