Results 1 to 19 of 19

Thread: Proper way to end a program with Timer controls

  1. #1

    Thread Starter
    Member
    Join Date
    Oct 2014
    Posts
    42

    Proper way to end a program with Timer controls

    I would have expected clicking on the command button to end the following program but all it does is to cause the window to disappear while the process continues indefinitely.

    If you wan to see it for yourself, it just contains a timer control , a command button and a text box.

    Edit: Sorry I should have added my question, what is the proper way to end this program?

    Code:
    Option Explicit
    
    Private Sub Command1_Click()
        Timer1.Interval = 0
        Unload Me
       
        
    End Sub
    
    
    Private Sub Timer1_Timer()
    
        Static alreadyhere As Boolean
        
        If Not alreadyhere Then
            alreadyhere = True
            
            Dim c As Long
            
            For c = 1 To 50000
               
                Text1.Text = c
                 DoEvents
            Next
            
            alreadyhere = False
        End If
        
    End Sub
    Last edited by C++Novice; Dec 10th, 2017 at 05:55 AM.

  2. #2
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,120

    Re: Proper way to end a program with Timer controls

    Try with a termination flag like this
    vb Code:
    1. Option Explicit
    2.  
    3. Private m_bTerminated As Boolean
    4.  
    5. Private Sub Command1_Click()
    6.     m_bTerminated = True
    7.     Unload Me
    8. End Sub
    9.  
    10. Private Sub Timer1_Timer()
    11.     Dim c As Long
    12.     Static alreadyhere As Boolean
    13.    
    14.     If Not alreadyhere Then
    15.         alreadyhere = True
    16.         For c = 1 To 50000
    17.             Text1.Text = c
    18.             DoEvents
    19.             If m_bTerminated Then
    20.                 Exit Sub
    21.             End If
    22.         Next
    23.         alreadyhere = False
    24.     End If
    25. End Sub
    cheers,
    </wqw>

  3. #3
    Addicted Member Cristian's Avatar
    Join Date
    Jun 2006
    Posts
    228

    Re: Proper way to end a program with Timer controls

    Seems to me that you missing stop the timer when m_bTerminated = true

  4. #4

    Thread Starter
    Member
    Join Date
    Oct 2014
    Posts
    42

    Re: Proper way to end a program with Timer controls

    Thanks wqw
    That does the trick all right.

  5. #5

    Thread Starter
    Member
    Join Date
    Oct 2014
    Posts
    42

    Re: Proper way to end a program with Timer controls

    Hi I am back again, sorry!
    Your solution works wqw but what about situations like in the slightly altered code below, where the DoEvents call is inside a nested procedure and the outer procedure later updates a control? If the nested procedure was called in many different places or nested deeply it could become a big chore making
    sure there was no possibility of a control being referenced and preventing the process from ending.
    I am not trying to be smart but just looking to understand this better or get guidance for dos and donts in general.
    Code:
    Option Explicit
     
    Private m_bTerminated As Boolean
     
    Private Sub Command1_Click()
        m_bTerminated = True
        Unload Me
    End Sub
    
    Private Sub Timer1_Timer()
        
        Static alreadyhere As Boolean
        
        If Not alreadyhere Then
            alreadyhere = True
            Nested_Procedure
            Text1.Refresh 'added this to trigger form load
            alreadyhere = False
        End If
    End Sub
    
    Private Sub Nested_Procedure()
    Dim c As Long
            For c = 1 To 50000
                Text1.Text = c
                DoEvents
                If m_bTerminated Then
                    Exit Sub
                End If
            Next
    End Sub

  6. #6
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,120

    Re: Proper way to end a program with Timer controls

    You can prevent form reloading with
    vb Code:
    1. Private Sub Form_Load()
    2.     If m_bTerminated Then
    3.         Unload Me
    4.     End If
    5. End Sub
    This way you can trap "Object was unloaded" error in the IDE when control usage after termination is not guarded by m_bTerminated flag and impl sanity checks.

    Calling out DoEvents and/or raising events can lead to all sorts of reentrancy complications, incl. form being unloaded by client code.

    cheers,
    </wqw>

  7. #7

    Thread Starter
    Member
    Join Date
    Oct 2014
    Posts
    42

    Re: Proper way to end a program with Timer controls

    Quote Originally Posted by wqweto View Post
    You can prevent form reloading with
    vb Code:
    1. Private Sub Form_Load()
    2.     If m_bTerminated Then
    3.         Unload Me
    4.     End If
    5. End Sub
    This way you can trap "Object was unloaded" error in the IDE when control usage after termination is not guarded by m_bTerminated flag and impl sanity checks.

    Calling out DoEvents and/or raising events can lead to all sorts of reentrancy complications, incl. form being unloaded by client code.

    cheers,
    </wqw>
    Thanks wqw, that's clever.
    I am going to play with this for awhile.
    Until recently I wasn't aware of how much can go wrong when using doevents and I have probably tended to use it too much.
    I think maybe it's a really bad idea to have a doevents inside a timer, more so than in other places?

  8. #8
    Fanatic Member
    Join Date
    Jan 2013
    Posts
    894

    Re: Proper way to end a program with Timer controls

    why not just "END" instruction inside the Timer code? it is buggy?

  9. #9

    Thread Starter
    Member
    Join Date
    Oct 2014
    Posts
    42

    Re: Proper way to end a program with Timer controls

    Quote Originally Posted by flyguille View Post
    why not just "END" instruction inside the Timer code? it is buggy?
    I believe that it is a bad idea to use "End" (i could be wrong though), and that the proper way is to unload all the forms in your application as in something like the following:
    Code:
    Private Sub Shutdown()
    
        Dim F As Form
        
        For Each F In Forms
            Unload F
        Next
        
    End Sub

  10. #10
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Proper way to end a program with Timer controls

    Quote Originally Posted by flyguille View Post
    why not just "END" instruction inside the Timer code? it is buggy?
    Hi Flyguille,

    The problem is, you don't execute your Form_Unload events or your Class_Terminate events. In addition, if you're doing subclassing or any OS hooking, you're quite possibly not gracefully backing out of that either.

    Given those things, using the "End" statement can easily crash the VB6 IDE, and it can possibly even crash Windows under specific circumstances. Truth be told, even using the "End" button on the VB6 IDE isn't entirely advisable (although, with care, I'll admit that I often do that).

    I've heard someone describe the "End" statement as comparable to snatching the key out of a simi-truck barreling down the interstate and throwing them out the window. C++Novice has shown you how to find an exit ramp and pull into a truck-stop.

    Here's some code to test and see what I'm saying.

    Code:
    
    Option Explicit
    
    Private Sub Form_DblClick()
        End
    End Sub
    
    Private Sub Form_Terminate()
        MsgBox "terminate COM"
    End Sub
    
    Private Sub Form_Unload(Cancel As Integer)
        MsgBox "unload"
    End Sub
    
    Good Luck,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  11. #11
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,721

    Re: Proper way to end a program with Timer controls

    I always use End, but with caution.
    in the Form_Unload you set Cancel = 1, this will break the unloading,
    now, you do whatever you need to stop subclassing/unloading/set nothing etc.
    also, if you are using components/apis that require some "time" to end, you need to wait until its done,
    at the very end of the line, a nice and destructive "End".
    the problem with "End" is that it used before some stuff are terminated/closed/ended, like subclassing.
    that is why we use WM_NCDESTROY, to avoid such problems.
    but its better to stop the subclassing manually.

    and of course, as Elroy pointed out, we can create crashes if we run different things simultaneously.
    but if you are doing it right, end should not give you any problems. at least not for me.

  12. #12
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Proper way to end a program with Timer controls

    End isn't quite as drastic as some think:

    The End statement stops code execution abruptly, without invoking the Unload, QueryUnload, or Terminate event, or any other Visual Basic code. Code you have placed in the Unload, QueryUnload, and Terminate events of forms and class modules is not executed. Objects created from class modules are destroyed, files opened using the Open statement are closed, and memory used by your program is freed. Object references held by other programs are invalidated.
    But:

    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.
    I can't remember using End in over 15 years. Use the recommended route described above.

  13. #13
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,721

    Re: Proper way to end a program with Timer controls

    that is why you create a "termination" function, that will do important cleanups before you call end.
    i have used end over 15 years without any issues.
    its quite amusing that some are afraid of using end.

    Text1.Refresh will not trigger Form_Load!
    if you want to avoid api's and just want to play with vb timer, i would:

    Private Sub Command1_Click()
    Form_Unload 1
    End Sub

    Private Sub Timer1_Timer()
    Dim c As Long
    Timer1.Enabled = False
    For c = 1 To 50000
    Text1.text = c
    DoEvents
    If m_bTerminated Then Exit Sub
    Next c
    Timer1.Enabled = True
    End Sub

    Private Sub Form_Unload(Cancel As Integer)
    Cancel = 1
    m_bTerminated = True
    ' other cleanups, save function, etc '
    End
    End Sub

    the reason I call Form_Unload is that you can use the button or the "x" button.
    inside the timer, i simply stop the timer, do the for/next and start the timer again.
    also, depending what you want to do and how fast it is, but just running a loop its quite pointless and to call a doevent for each number?,
    i would try to update every 10, 100 or even 1000 instead of each one.
    also, better use Label instead of Textbox.

  14. #14
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Proper way to end a program with Timer controls

    Ugh.

  15. #15
    Smooth Moperator techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,532

    Re: Proper way to end a program with Timer controls

    Quote Originally Posted by baka View Post
    that is why you create a "termination" function, that will do important cleanups before you call end.
    i have used end over 15 years without any issues.
    its quite amusing that some are afraid of using end.
    You know what you're doing. So does Dill... so do I... problem is that a lot of the people around here don't. So you can't leave the door open even just a crack for things like that. If someone starts to think it's ok to use End in one situation, they start thinking it's OK to use it any time they want, as long as they are careful... then they forget... that one time they aren't careful... and take the easy way out...

    Same thing happens with On Error Resume Next ... I advocate not using it for the same reasons... it makes it too easy for people to paint themselves into a corner they don't understand and can't get out of. It's not that any of it is evil (which we've been accused of as well) or that we're afraid of it, it's that we know better and we've got painful battle scars we'd just rather others not have to experience. We've done the bare foot fire walk and this is us telling the others, hey look, fireproof boots.

    And that's why you get so much push back on some of your advice. It make work for you, but it simply isn't safe for some of the others around here. Not to mention those that stumble into the middle of the thread from a search that don't have the benefit of having read the entire thread, or all of your posts where you've noted the lengths you've gone to. And that's what the problem is.

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  16. #16
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,721

    Re: Proper way to end a program with Timer controls

    no, we should not hold hand. programming is progress and learning.
    why tell people to not do something because it could get ugly? no, let people try and figure it out.

    im with you with on error, but its not that we can avoid it completely. sometimes it's useful. but we add it because we are 100% certain whats going on, not because we don't have a clue and we put it there to avoid errors.
    and thats the point, we want to learn "how to use it", not to "avoid and never learn about it".

    its quite silly that you assume people are ignorant and need protection. its not fatal to do mistakes and mess up.
    again, you put unneeded fears into peoples mind and after a while people start spreading those fears around and people believes they need to follow and in the end, they don't learn, they just avoid. bravo.

  17. #17

    Thread Starter
    Member
    Join Date
    Oct 2014
    Posts
    42

    Re: Proper way to end a program with Timer controls

    Thanks everyone. Your method looks interesting Baka but as techgnome says, I don't know enough to feel confident enough to use it.
    Also is it not losing one of the advantages that vb gives us over languages where you have to manually dispose of stuff?

    In my software I have a timer that regularly checks a database for tasks to do, most of which would have been added remotely.
    There might be 0, 1, 100s or rarely 1000s of tasks added and it loops through them.
    There's doevents in there to allow the user to do stuff in the program at the same time.
    The timer was so as to have it happen automatically, the doevents so as not to tie stuff up on the user.
    It's worked away fine as far as I can see but just it's dawned on me that I am very likely doing it wrong.
    I should probably fire the timer more often and limit it to a task or two per timer event rather than relying on doevents or does
    it make any practical difference?

  18. #18
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,721

    Re: Proper way to end a program with Timer controls

    End, is a way to tell VB its time to halt everything and close, it will not trigger Unload, QueryUnload, and Terminate.
    No matter if we are using Unload Me or a custom termination procedure, we need a Cleanup (usually we have modules, references, classes etc)
    In a big project, it could be that the "cleanup" don't work, maybe a references API/Object is not responding.
    In this case, End will break that reference and force the program to terminate.

    sometimes it is better to spread around the calls instead of calling all procedures inside a loop.
    example:

    we call 10 different procedures in a timer, using:

    for i = 1 to 10: call procedure i: next i

    that would call all 10 in a sequence, each time the timer is triggered
    but we could also do:

    static i&
    i = i + 1
    if i = 11 then i = 1
    call procedure i

    that way, each time the timer is triggered, it will call 1 procedure (we need to adjust the interval)
    doing so, we avoid the "loop" freezing and maybe we don't need DoEvents at all.

  19. #19
    PowerPoster ChrisE's Avatar
    Join Date
    Jun 2017
    Location
    Frankfurt
    Posts
    3,046

    Re: Proper way to end a program with Timer controls

    Quote Originally Posted by C++Novice View Post
    Thanks everyone. Your method looks interesting Baka but as techgnome says, I don't know enough to feel confident enough to use it.
    Also is it not losing one of the advantages that vb gives us over languages where you have to manually dispose of stuff?

    In my software I have a timer that regularly checks a database for tasks to do, most of which would have been added remotely.
    There might be 0, 1, 100s or rarely 1000s of tasks added and it loops through them.
    There's doevents in there to allow the user to do stuff in the program at the same time.
    The timer was so as to have it happen automatically, the doevents so as not to tie stuff up on the user.
    It's worked away fine as far as I can see but just it's dawned on me that I am very likely doing it wrong.
    I should probably fire the timer more often and limit it to a task or two per timer event rather than relying on doevents or does
    it make any practical difference?
    Hi,
    I posted this in another thread, and it always worked for me.

    here the sample..
    Code:
    Option Explicit
    
    Private NextAction As Date
    Private Interval As Long
    Private IntervalType As String
    
    Private Sub Command1_Click()
       
       Dim i As Long
       
          'next full hour
          i = Hour(Now)
          Interval = 1
          IntervalType = "h"
          NextAction = DateAdd(IntervalType, Interval, Date + CDate(i & ":00:00"))
          Timer1.Interval = 1000
          Timer1.Enabled = True
          
          Label2.Caption = Format(NextAction, "dd.mm.yyyy hh:nn:ss")
          Command4.Caption = "Stop"
    End Sub
    
    Private Sub Command2_Click()
    
       Dim i As Long
       
          'every 10sec.
          Interval = 10
          IntervalType = "s"
          NextAction = Now
          Timer1.Interval = 1000
          Timer1.Enabled = True
          Label2.Caption = Format(NextAction, "dd.mm.yyyy hh:nn:ss")
          Command4.Caption = "Stop"
    End Sub
    
    Private Sub Command3_Click()
    
       Dim i As Long
       
          'every 2min.
          Interval = 2
          IntervalType = "n"
          NextAction = Now
          Timer1.Interval = 1000
          Timer1.Enabled = True
          NextAction = DateAdd(IntervalType, Interval, Date + CDate(i & ":00:00"))
          Label2.Caption = Format(NextAction, "dd.mm.yyyy hh:nn:ss")
          Command4.Caption = "Stop"
    End Sub
    
    Private Sub Command4_Click()
    
          Timer1.Enabled = False
          Command4.Caption = "Stopped"
    End Sub
    
    Private Sub Form_Load()
    
          Command1.Caption = "every hour"
          Command2.Caption = "every 10sec."
          Command3.Caption = "every 2min."
          Command4.Caption = "Stopp"
    End Sub
    
    Private Sub Timer1_Timer()
    
       Dim s As String
       
          s = "Countdown " & Format(NextAction - Now, "hh:nn:ss")
          If NextAction > Now Then
             If Label1.Caption <> s Then
                Label1.Caption = s
             End If
             Exit Sub
          End If
          
          NextAction = DateAdd(IntervalType, Interval, Now)
          Timer1.Enabled = False
          'your action here
          
          List1.AddItem "Action " & Format(Now, "dd.mm.yy hh:nn:ss")
          Timer1.Enabled = True
          Label2.Caption = Format(NextAction, "dd.mm.yyyy hh:nn:ss")
    End Sub
    regards
    Chris
    to hunt a species to extinction is not logical !
    since 2010 the number of Tigers are rising again in 2016 - 3900 were counted. with Baby Callas it's 3901, my wife and I had 2-3 months the privilege of raising a Baby Tiger.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width