Discussion:
Why doesn't this simple problem terminate correctly?
(too old to reply)
Leo Bramwell-Speer
2012-08-13 12:53:15 UTC
Permalink
Hi

It's a single form module in VB6...

-------------------------------------------------------------------------
Option Explicit
Private Quit As Boolean
-------------------------------------------------------------------------
Private Sub Form_Activate()
Do
DoEvents
Line (Rnd * ScaleWidth, Rnd * ScaleHeight)- _
(Rnd * ScaleWidth, Rnd * ScaleHeight), _
RGB(Rnd * 256, Rnd * 256, Rnd * 256)
Loop Until Quit
End Sub
-------------------------------------------------------------------------
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Quit = True
End Sub
-------------------------------------------------------------------------

The form disappears the VB6 IDE hangs in Run mode, yet if I remove the
line of code that draws the lines, it terminates correctly. The only way
of doing it is to add:

-------------------------------------------------------------------------
-Private Sub Form_Unload(Cancel As Integer)
Unload Me
End
End Sub
-------------------------------------------------------------------------

Which apparently is BAAAD, for 2 reasons: 1) The Unload Me statement is
unnecessary as the sub is already doing it? & 2)NEVER USE END as it can
cause memory leaks'n'stuff. I quote from VB6 Help:

'The End statement provides a way to force your program to halt. For
normal termination of a Visual Basic program, you should unload all
forms. Your program closes as soon as there are no other programs holding
references to objects created from your public class modules and no code
executing.'

So what gives? How do I do it properly?

Yours confusedly,
--
Leo
http://leobs.net/
DaveO
2012-08-13 13:17:23 UTC
Permalink
Hi

Not the *only* way, try adding
Unload Me
after the Loop Until Quit line.

DaveO
Post by Leo Bramwell-Speer
Hi
It's a single form module in VB6...
-------------------------------------------------------------------------
Option Explicit
Private Quit As Boolean
-------------------------------------------------------------------------
Private Sub Form_Activate()
Do
DoEvents
Line (Rnd * ScaleWidth, Rnd * ScaleHeight)- _
(Rnd * ScaleWidth, Rnd * ScaleHeight), _
RGB(Rnd * 256, Rnd * 256, Rnd * 256)
Loop Until Quit
End Sub
-------------------------------------------------------------------------
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Quit = True
End Sub
-------------------------------------------------------------------------
The form disappears the VB6 IDE hangs in Run mode, yet if I remove the
line of code that draws the lines, it terminates correctly. The only way
-------------------------------------------------------------------------
-Private Sub Form_Unload(Cancel As Integer)
Unload Me
End
End Sub
-------------------------------------------------------------------------
Which apparently is BAAAD, for 2 reasons: 1) The Unload Me statement is
unnecessary as the sub is already doing it? & 2)NEVER USE END as it can
'The End statement provides a way to force your program to halt. For
normal termination of a Visual Basic program, you should unload all
forms. Your program closes as soon as there are no other programs holding
references to objects created from your public class modules and no code
executing.'
So what gives? How do I do it properly?
Yours confusedly,
--
Leo
http://leobs.net/
Leo Bramwell-Speer
2012-08-13 14:02:51 UTC
Permalink
Post by DaveO
Not the *only* way, try adding
Unload Me
after the Loop Until Quit line.
Ah, I think between you & Deanna Earley I've figured it out :)
--
Leo
http://leobs.net/
Coder X
2012-08-13 13:18:37 UTC
Permalink
Ugh!

Move that code to a timer buddy.
Post by Leo Bramwell-Speer
Hi
It's a single form module in VB6...
-------------------------------------------------------------------------
Option Explicit
Private Quit As Boolean
-------------------------------------------------------------------------
Private Sub Form_Activate()
Do
DoEvents
Line (Rnd * ScaleWidth, Rnd * ScaleHeight)- _
(Rnd * ScaleWidth, Rnd * ScaleHeight), _
RGB(Rnd * 256, Rnd * 256, Rnd * 256)
Loop Until Quit
End Sub
-------------------------------------------------------------------------
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Quit = True
End Sub
-------------------------------------------------------------------------
The form disappears the VB6 IDE hangs in Run mode, yet if I remove the
line of code that draws the lines, it terminates correctly. The only way
-------------------------------------------------------------------------
-Private Sub Form_Unload(Cancel As Integer)
Unload Me
End
End Sub
-------------------------------------------------------------------------
Which apparently is BAAAD, for 2 reasons: 1) The Unload Me statement is
unnecessary as the sub is already doing it? & 2)NEVER USE END as it can
'The End statement provides a way to force your program to halt. For
normal termination of a Visual Basic program, you should unload all
forms. Your program closes as soon as there are no other programs holding
references to objects created from your public class modules and no code
executing.'
So what gives? How do I do it properly?
Yours confusedly,
--
Leo
http://leobs.net/
Leo Bramwell-Speer
2012-08-13 14:05:54 UTC
Permalink
Post by Coder X
Ugh!
Move that code to a timer buddy.
Yes, could do that of course, but would that not be slower, even if the
Interval was set of 1 millisecond?
--
Leo
http://leobs.net/
DaveO
2012-08-13 14:39:02 UTC
Permalink
Post by Leo Bramwell-Speer
Post by Coder X
Ugh!
Move that code to a timer buddy.
Yes, could do that of course, but would that not be slower, even if the
Interval was set of 1 millisecond?
--
Leo
http://leobs.net/
I suspect he meant use a timer as a one-shot to fire off a pseudo-thread
like this:

Sub Form_Activate
Timer1.enabled = true
End Sub

Sub Timer1_Timer
Timer1.enabled = false
Post by Leo Bramwell-Speer
Post by Coder X
DO YOUR STUFF<<
End sub

DaveO.
Leo Bramwell-Speer
2012-08-13 15:07:48 UTC
Permalink
Post by Leo Bramwell-Speer
Sub Form_Activate
Timer1.enabled = true
End Sub
Sub Timer1_Timer
Timer1.enabled = false
Post by Coder X
DO YOUR STUFF<<
End sub
I can't see the advantage of that.. it just moves the loop from
Form_Activate to Timer1_Timer?
--
Leo
http://leobs.net/
DaveO
2012-08-13 15:33:11 UTC
Permalink
Post by Leo Bramwell-Speer
Post by Leo Bramwell-Speer
Sub Form_Activate
Timer1.enabled = true
End Sub
Sub Timer1_Timer
Timer1.enabled = false
Post by Coder X
DO YOUR STUFF<<
End sub
I can't see the advantage of that.. it just moves the loop from
Form_Activate to Timer1_Timer?
As VB6 is (essentially) single threaded you cannot have multiple chains of
execution. Or can you?
Using a timer as a one-shot you can create a second chain of execution in
the same thread. One example where this can be useful is where you have
lot's of context menus, if you open a modal form from a context menu then
try to have more menus on that form you'll find the menus on the second form
don't show because of the modalality of the form prevents execution until
the form is unloaded, however if the first menu uses a time one-shot to show
the second form then the second form can have context menus. Almost anywhere
where you want the execution to continue without waiting for another process
to end can be managed with judicious use of the one-shot timer.

DaveO.
Leo Bramwell-Speer
2012-08-13 18:14:23 UTC
Permalink
Post by DaveO
As VB6 is (essentially) single threaded you cannot have multiple
chains of execution. Or can you?
Using a timer as a one-shot you can create a second chain of execution
in the same thread. One example where this can be useful is where you
have lot's of context menus, if you open a modal form from a context
menu then try to have more menus on that form you'll find the menus on
the second form don't show because of the modalality of the form
prevents execution until the form is unloaded, however if the first
menu uses a time one-shot to show the second form then the second form
can have context menus. Almost anywhere where you want the execution
to continue without waiting for another process to end can be managed
with judicious use of the one-shot timer.
Like DaveO and others are saying, VB is single threaded, and also
events like Activate/GotFocus/LostFocus happen when the focus changes
and they are not recommended for anything that takes a long time.
Also, Form_Activate could fire again if the user clicked on another
Form within the app and came back to the form again. The best option
is to use the code that DaveO gave above, but use Form_Resize event
instead. The Resize event fires when the form is first shown, and when
the form is resized, so use a flag and run any code you like there
when the form is first shown. Like many said, use a Timer if the code
Private Sub Form_Resize()
Static bShownBefore As Boolean
If Not bShownBefore Then
bShownBefore = True
Timer1.Enabled = True
End If
End Sub
Sub Timer1_Timer
Timer1.Enabled = False
' Add code here
End sub
OK that sorta makes sense.. My amended code:
---------------------------------------------------------------------------
Option Explicit
Private Quit As Boolean
Private R As Byte, G As Byte, B As Byte
Private LineX As Integer, LineY As Integer, N As Integer
---------------------------------------------------------------------------
Private Sub Form_Resize()
Cls
Static ShownBefore As Boolean
If Not ShownBefore Then ShownBefore = True: tmrTimer.Enabled = True
End Sub
---------------------------------------------------------------------------
Private Sub tmrTimer_Timer()
tmrTimer.Enabled = False
Do
R = Rnd * 255
G = Rnd * 255
B = Rnd * 255
LineX = ScaleWidth / 2 * ((Int(Rnd * 10) + 1) * 0.1)
LineY = ScaleHeight / 2 * ((Int(Rnd * 10) + 1) * 0.1)
For N = 0 To 359
Line (ScaleWidth * 0.5, ScaleHeight * 0.5)-Step(Cos(N) * LineX,
Sin(N) * LineY), RGB(R, G, B)
Next N
DoEvents
Loop Until Quit
End Sub
---------------------------------------------------------------------------
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Quit = True
End Sub
---------------------------------------------------------------------------
Brilliant - thanks guys :)
--
Leo
http://leobs.net/
Farnsworth
2012-08-13 16:49:39 UTC
Permalink
Post by DaveO
Post by Leo Bramwell-Speer
Post by Coder X
Ugh!
Move that code to a timer buddy.
Yes, could do that of course, but would that not be slower, even if the
Interval was set of 1 millisecond?
--
Leo
http://leobs.net/
I suspect he meant use a timer as a one-shot to fire off a pseudo-thread
Sub Form_Activate
Timer1.enabled = true
End Sub
Sub Timer1_Timer
Timer1.enabled = false
Post by Leo Bramwell-Speer
Post by Coder X
DO YOUR STUFF<<
End sub
DaveO.
Like DaveO and others are saying, VB is single threaded, and also events
like Activate/GotFocus/LostFocus happen when the focus changes and they are
not recommended for anything that takes a long time. Also, Form_Activate
could fire again if the user clicked on another Form within the app and came
back to the form again. The best option is to use the code that DaveO gave
above, but use Form_Resize event instead. The Resize event fires when the
form is first shown, and when the form is resized, so use a flag and run any
code you like there when the form is first shown. Like many said, use a
Timer if the code would take too long(perhaps a second or so). Example:

Private Sub Form_Resize()
Static bShownBefore As Boolean
If Not bShownBefore Then
bShownBefore = True
Timer1.Enabled = True
End If
End Sub

Sub Timer1_Timer
Timer1.Enabled = False
' Add code here
End sub
Deanna Earley
2012-08-13 13:19:42 UTC
Permalink
Post by Leo Bramwell-Speer
Hi
It's a single form module in VB6...
-------------------------------------------------------------------------
Option Explicit
Private Quit As Boolean
-------------------------------------------------------------------------
Private Sub Form_Activate()
Do
DoEvents
Line (Rnd * ScaleWidth, Rnd * ScaleHeight)- _
(Rnd * ScaleWidth, Rnd * ScaleHeight), _
RGB(Rnd * 256, Rnd * 256, Rnd * 256)
Loop Until Quit
End Sub
-------------------------------------------------------------------------
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Quit = True
End Sub
-------------------------------------------------------------------------
The form disappears the VB6 IDE hangs in Run mode, yet if I remove the
line of code that draws the lines, it terminates correctly.
Your code flow is ass follows:
1) form activate
2) start do loop
3) DoEvents
4) draw line
5) return to 2 if Quit hasn't been set.

Now, the DoEvents allows other events to run so let's add this to the
code flow.

1) form activate
2) start do loop
3) DoEvents
3a) Form QueryUnload
3b) set Quit to true
3c) form unloads
4) draw line
4a) As the form isn't loaded (see step 3c) it reloads the form
5) quit is true so exits the loop

Note that the form was reloaded at step 4a

The simple fix for this is to move the DoEvents after the Line call.

Note though that your code suffers from reentrancy.
While the form is active, and your loop is running, if the user switches
away and back again, it will start another copy of the loop.

Without knowing what yoru intended result is, it's difficult to suggest
one of the many far better ways :)
Post by Leo Bramwell-Speer
-------------------------------------------------------------------------
-Private Sub Form_Unload(Cancel As Integer)
Unload Me
End
End Sub
-------------------------------------------------------------------------
Which apparently is BAAAD, for 2 reasons: 1) The Unload Me statement is
unnecessary as the sub is already doing it? & 2)NEVER USE END as it can
'The End statement provides a way to force your program to halt. For
normal termination of a Visual Basic program, you should unload all
forms. Your program closes as soon as there are no other programs holding
references to objects created from your public class modules and no code
executing.'
It won't leak, but can cause issues with hardware access, file locks,
databases etc as they don't get chance to clean up properly.

http://hashvb.earlsoft.co.uk/index.php/End
--
Deanna Earley (***@icode.co.uk)
i-Catcher Development Team
http://www.icode.co.uk/icatcher/

iCode Systems

(Replies direct to my email address will be ignored. Please reply to the
group.)
Leo Bramwell-Speer
2012-08-13 14:00:31 UTC
Permalink
Post by Deanna Earley
Now, the DoEvents allows other events to run so let's add this to the
code flow.
1) form activate
2) start do loop
3) DoEvents
3a) Form QueryUnload
3b) set Quit to true
3c) form unloads
4) draw line
4a) As the form isn't loaded (see step 3c) it reloads the form
5) quit is true so exits the loop
Note that the form was reloaded at step 4a
The simple fix for this is to move the DoEvents after the Line call.
Ah! I think I see, so my program now...
-------------------------------------------------------------------------
Option Explicit
Private Quit As Boolean
Private R As Byte, G As Byte, B As Byte
Private LineX As Integer, LineY As Integer, N As Integer
-------------------------------------------------------------------------
Private Sub Form_Activate()
Do
R = Rnd * 255
G = Rnd * 255
B = Rnd * 255
LineX = ScaleWidth / 2 * ((Int(Rnd * 10) + 1) * 0.1)
LineY = ScaleHeight / 2 * ((Int(Rnd * 10) + 1) * 0.1)
For N = 0 To 359
Line (ScaleWidth * 0.5, ScaleHeight * 0.5)-Step(Cos(N) *
LineX, Sin(N) * LineY), RGB(R, G, B)
Next N
DoEvents
Loop Until Quit
End Sub
-------------------------------------------------------------------------
Private Sub Form_Resize()
Cls
End Sub
-------------------------------------------------------------------------
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Quit = True
End Sub
-------------------------------------------------------------------------
...is now OK? It's not loading & unloading the form millions of times a
second?
Post by Deanna Earley
Note though that your code suffers from reentrancy.
While the form is active, and your loop is running, if the user
switches away and back again, it will start another copy of the loop.
Without knowing what yoru intended result is, it's difficult to
suggest one of the many far better ways :)
The intended result is a pretty display on the screen :)

[Re END statement]...
Post by Deanna Earley
It won't leak, but can cause issues with hardware access, file locks,
databases etc as they don't get chance to clean up properly.
http://hashvb.earlsoft.co.uk/index.php/End
Enlightening - and I'd didn't know there was a VB wiki website <adds to
favourites>.
--
Leo
http://leobs.net/
Loading...