Question Cant stop Overflow Exception

stejefferies

Member
Joined
Mar 13, 2013
Messages
5
Programming Experience
Beginner
Hi All

I downloaded a class called countdown.vb to implement into my program. The original creator of the class seems to have stopped posting or giving help on the site, but I pushed on.

Basically i'm making a standalone app that reads 3 textboxes for the time, compares to current time and tells you when to go for break - this bit works a treat. The second phase is to have 3 countdowns based on different break lengths.

Whilst with the class, it counts down and displays the correct time remaining, when it gets to 0 it creates an overflow exception - UNLESS the time remaining is displayed in me.timeleft (im trying to show in one place)

I am completely lost now, and i have gone through the usage guide and it is well commented. Any help appreciated.

Many thanks
Steve

Full project enclosed including the countdown class.
 
Last edited:
I have removed your attachment because it contained binary files, which is against forum rules. If you want to attach a zipped project then always delete the bin and obj folders first.

That said, attaching a whole project should generally be a last resort. You should generally post just the relevant code directly first, so we can see it without having to go anywhere or open anything. If there's an exception then there's a call stack, so you should know exactly what line it is thrown on. In that case, you can break on that line and determine which reference is Nothing. You can also tell us what other data values are involved.
 
I have removed your attachment because it contained binary files, which is against forum rules. If you want to attach a zipped project then always delete the bin and obj folders first.

That said, attaching a whole project should generally be a last resort. You should generally post just the relevant code directly first, so we can see it without having to go anywhere or open anything. If there's an exception then there's a call stack, so you should know exactly what line it is thrown on. In that case, you can break on that line and determine which reference is Nothing. You can also tell us what other data values are involved.

Apologies

From the class

    Private Sub Timer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs)
        TimeLeft -= 1


        RaiseEvent Tick(Me, e)


        If TimeLeft = 0 Then
            Time.Stop()
            RaiseEvent TimesOut(Me, e)
        End If
    End Sub


So when i execute this code, when it hits 0 it throws an overflow exception

Private Sub btn15_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn15.Click


        count = New CountDown(0, 1) 'sets the countdown to 1 minute - to amend to 15 in live
        AddHandler count.Tick, AddressOf Count_Tick
        count.Start()
End Sub

Private Sub Count_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs)
        'since we added the handler, this code will occur once each second


        'get the time left
        lblCountdown.Text = sender.Minutes & ":" & sender.Seconds & " left"

 'Me.Text = & sender.Minutes & "minutes and " & sender.Seconds & " seconds left."
        If lblCountdown.Text = "0:0 left" Then
            MessageBox.Show("BREAK OVER")


        End If
    End Sub
 
Last edited by a moderator:
in fact, its not a null reference, its an overflow =_=. Sorry guys! Details below. Do you need the original class it is called from?

System.OverflowException was unhandled
Message=Value was either too large or too small for a UInt64.
Source=mscorlib
StackTrace:
at System.Decimal.ToUInt64(Decimal d)
at System.Convert.ToUInt64(Decimal value)
at Chronos.CountDown.Timer_Tick(Object sender, EventArgs e) in N:\projects\Chronos\Chronos\Countdown.vb:line 71
at System.Windows.Forms.Timer.OnTick(EventArgs e)
at System.Windows.Forms.Timer.TimerNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.SafeNativeMethods.MessageBox(HandleRef hWnd, String text, String caption, Int32 type)
at System.Windows.Forms.MessageBox.ShowCore(IWin32Window owner, String text, String caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, Boolean showHelp)
at System.Windows.Forms.MessageBox.Show(String text)
at Chronos.Form1.Count_Tick(Object sender, EventArgs e) in N:\projects\Chronos\Chronos\Form1.vb:line 79
at Chronos.CountDown.Timer_Tick(Object sender, EventArgs e) in N:\projects\Chronos\Chronos\Countdown.vb:line 73
at System.Windows.Forms.Timer.OnTick(EventArgs e)
at System.Windows.Forms.Timer.TimerNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
at Chronos.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:line 81
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.Runtime.Hosting.ManifestRunner.Run(Boolean checkAptModel)
at System.Runtime.Hosting.ManifestRunner.ExecuteAsAssembly()
at System.Runtime.Hosting.ApplicationActivator.CreateInstance(ActivationContext activationContext, String[] activationCustomData)
at System.Runtime.Hosting.ApplicationActivator.CreateInstance(ActivationContext activationContext)
at System.Activator.CreateInstance(ActivationContext activationContext)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssemblyDebugInZone()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
 
Did you read the information you posted? It's telling you exactly what the problem is and exactly where it's happening. It's telling you that, on line 71, in the Chronos.CountDown.Timer_Tick method, you're trying to use a UInt64 to work with a value that's too big or too small for that type. I'm not sure why you would need any more explanation than that. You need to look at that value and work out why you have a value that is incompatible with the type you're using and change one or the other. My guess would be that the number is negative but you don't have to guess. You're running the code so you can see exactly what the value is.
 
Did you read the information you posted? It's telling you exactly what the problem is and exactly where it's happening. It's telling you that, on line 71, in the Chronos.CountDown.Timer_Tick method, you're trying to use a UInt64 to work with a value that's too big or too small for that type. I'm not sure why you would need any more explanation than that. You need to look at that value and work out why you have a value that is incompatible with the type you're using and change one or the other. My guess would be that the number is negative but you don't have to guess. You're running the code so you can see exactly what the value is.


That was also my guess. I am pretty new to programming - i did it 10 years ago and now just trying to learn.
The class used was taken from somewhere else, and line 71 IS where it errors. What i dont understand is beneath that command there is an if loop to detect when it hits 0 to catch the exception. I cant figure out why it isnt catching it and discarding? Or is there another property type i can use instead of uInt64?

Many thanks
Steve
 
Hi,

My first recommendation would be to bin anything you have downloaded from somewhere else and write your own class. The beauty of this is that you then know exactly how it works and then when something goes wrong you know how to fix things.

That said, I agree with jcmilhinney's comment regarding a negative value not being compatible with a variable type declared as UInt64. Do you know what this means? The reason I think this, is the code in this class:-

VB.NET:
Private Sub Timer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs)
  TimeLeft -= 1
 
  RaiseEvent Tick(Me, e)
 
  If TimeLeft = 0 Then
    Time.Stop()
    RaiseEvent TimesOut(Me, e)
  End If
End Sub

What happens here is that when the TimeLeft variable reaches Zero it calls:-

VB.NET:
Time.Stop()

Which may be fine for something else in the class but this subroutine implies that there is a Timer component called TIMER and NOT TIME and since the statement above calls:-

VB.NET:
Time.Stop()

Then this subroutine CONTINUES to run which means the variable TimeLeft runs into negative numbers, therefore causing your error, if this variable is declared as type UInt64.

I am guessing that this should be:-

VB.NET:
Timer.Stop()

Hope that helps.

Cheers,

Ian
 
Hi Ian

Thank you for your reply
I can't believe how many problems a simple countdown project can cause lol.

Countdown.vb declares
Private Time As Timer
Private TimeLeft As ULong

It then goes on to set out how the class should work

''' <summary>
''' Initializes a new instance of the CountDown class.
''' </summary>
Public Sub New()
SetNew()
End Sub
''' <summary>
''' Initializes a new instance of the CountDown class with the value from a System.Timespan.
''' </summary>
''' <param name="Span">The System.TimeSpan to take the value from</param>
Public Sub New(ByVal Span As TimeSpan)
TimeLeft = Span.Seconds
End Sub
''' <summary>
''' Initializes a new instance of the CountDown class with the value from Seconds.
''' </summary>
''' <param name="Seconds">Number of Seconds</param>
Public Sub New(ByVal Seconds As Integer)
SetNew()
TimeLeft = Seconds
End Sub
''' <summary>
''' Initializes a new instance of the CountDown class with the value from Seconds and Minutes.
''' </summary>
''' <param name="Seconds">Number of Seconds</param>
''' <param name="Minutes">Number of Minutes</param>
Public Sub New(ByVal Seconds As Integer, ByVal Minutes As Integer)
SetNew()
TimeLeft = Seconds + Minutes * 60
End Sub

From what I understand, it then handles the timer?
Private Sub SetNew()
Time = New Timer
Time.Interval = 1000
AddHandler Time.Tick, AddressOf Timer_Tick
End Sub




Private Sub Timer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs)
TimeLeft -= 1


RaiseEvent Tick(Me, e)


If TimeLeft = 0 Then
Time.Stop()
RaiseEvent TimesOut(Me, e)
End If
End Sub




''' <summary>
''' Start the timer.
''' </summary>
Public Sub Start()
If TimeLeft <> 0 Then
Time.Start()
Else
Throw New NullReferenceException
End If
End Sub
''' <summary>
''' Pause the timer.
''' </summary>
Public Sub Pause()
Time.Stop()
End Sub
''' <summary>
''' Stop the timer and reset the time.
''' </summary>
Public Sub Reset()
TimeLeft = 0
Time.Stop()
End Sub


''' <summary>
''' Set the time of the timer with the value from a System.Timespan.
''' </summary>
''' <param name="Span">The System.TimeSpan to take the value from</param>
Public Sub SetTime(ByVal Span As TimeSpan)
TimeLeft = Span.TotalSeconds
End Sub
''' <summary>
''' Set the time of the timer with Seconds.
''' </summary>
''' <param name="Seconds">Number of Seconds</param>
Public Sub SetTime(ByVal Seconds As Integer)
TimeLeft = Seconds
End Sub
''' <summary>
''' Set the time of the timer with Seconds and Minutes.
''' </summary>
''' <param name="Seconds">Number of Seconds</param>
''' <param name="Minutes">Number of Minutes</param>
Public Sub SetTime(ByVal Seconds As Integer, ByVal Minutes As Integer)
TimeLeft = Seconds + Minutes * 60
End Sub

I have cut out the parts of the class not called - IE the Days/Hours features but these dont look vital to the running of the class - only working out the seconds in x days

It then appears to get the return values
''' <summary>
''' Returns the number of Seconds left.
''' </summary>
Public ReadOnly Property Seconds() As Integer
Get
Return TimeSplit(3)
End Get
End Property
''' <summary>
''' Returns the number of Minutes left.
''' </summary>
Public ReadOnly Property Minutes() As Integer
Get
Return TimeSplit(2)
End Get
End Property
''' <summary>
''' Returns the number of Hours left.
''' </summary>
Public ReadOnly Property Hours() As Integer
Get
Return TimeSplit(1)
End Get
End Property
''' <summary>
''' Returns the number of Days left.
''' </summary>
Public ReadOnly Property Days() As Integer
Get
Return TimeSplit(0)
End Get
End Property


Private Function TimeSplit() As Integer()
Dim TimeLeftClone As ULong = TimeLeft
Dim ReturnValue(4) As Integer




While TimeLeftClone > 0
Select Case TimeLeftClone
Case Is >= 86400
TimeLeftClone -= 86400
ReturnValue(0) += 1
Case Is >= 3600
TimeLeftClone -= 3600
ReturnValue(1) += 1
Case Is >= 60
TimeLeftClone -= 60
ReturnValue(2) += 1
Case Else
ReturnValue(3) = TimeLeftClone
TimeLeftClone = 0
End Select
End While


Return ReturnValue
End Function






''' <summary>
''' Returns the time in Seconds.
''' </summary>
Public ReadOnly Property TotalSeconds() As Double
Get
Return New Double = TimeLeft
End Get
End Property
''' <summary>
''' Returns the time in Minutes.
''' </summary>
Public ReadOnly Property TotalMinutes() As Double
Get
Return New Double = TimeLeft / 60
End Get
End Property

and finally, as commented - it should call this when TimesOut

''' <summary>
''' Raises when the timer reaches 0.
''' </summary>
Public Event TimesOut(ByVal sender As Object, ByVal e As EventArgs)
''' <summary>
''' Raises each Seconds.
''' </summary>
Public Event Tick(ByVal sender As Object, ByVal e As EventArgs)




End Class



In my form, I put the following code in

Private Sub btn15_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn15.Click


count = New CountDown(0, 1)
AddHandler count.Tick, AddressOf Count_Tick
count.Start()




End Sub

Private Sub Count_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs)
'since we added the handler, this code will occur once each second


'get the time left
lblCountdown.Text = sender.Minutes & ":" & sender.Seconds & " left"
'Me.Text = sender.Days & " days, " & sender.Hours & " hours, " & sender.Minutes & " minutes and " & sender.Seconds & " seconds left." ***THIS WAS THE ORIGINAL LINE***

If lblCountdown.Text = "0:0 left" Then
MessageBox.Show("BREAK OVER")


End If
End Sub

If it makes it easier i think i can show you the class - but i think you are right - it seems easier to rewrite the class. I am trying to avoid recreating the wheel though.

Is there anything you can suggest that may be worth a look? I dont want the answer (this is part of my development, the answer defeats the purpose of learning) however a pointer in the right direction would be most helpful.

Would it be easier to just replicate the code in each button using the same timer with different variables for the countdown, or write a new class, or just figure out how to fix this?

Much appreciated guys/gals

Steve
 
Last edited:
Hi,

This is actually a threading issue so it may take you a bit of time to get this right. The class actually works fine but is badly written due to the fact that the class does NOT take into account what you may be doing on the UI Thread when the Timer reaches zero. In this case you display a button which may take you a moment or two to press.

So how does that help to solve the problem?

To demonstrate that it does work. call the class with the following:-

VB.NET:
Dim count = New CountDown(2, 0)

Then get ready to press the button on the "Break Over" message box. You have to be quick here. Do it a few times until you get it right. You will see that you do not get the error. Why is that, would you think?

What you need to realise is that when you use a Timer it is executed on a Secondary Thread and gives no consideration as to what is going on in the UI Thread (i.e your Form Thread). So what happens is that when the timer reaches zero you display a message in the UI thread to say its finished but the class has NOT AS YET EXECUTED the code in the class to ACTUALLY STOP the timer so it keeps ticking once a second in the secondary thread, which ultimately sets the TimeLeft variable of type ULong to -1 which then throws the error due to its type.

How to fix this then. All I will say at this point is that this section of code in the class needs rewriting to accommodate the above situation:-

VB.NET:
Private Sub Timer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs)
  TimeLeft = CULng(TimeLeft - 1)
 
  RaiseEvent Tick(Me, e)
 
  If TimeLeft = 0 Then
    Time.Stop()
    RaiseEvent TimesOut(Me, e)
  End If
End Sub

Hope that helps and good luck.

Cheers,

Ian

A couple of other points for you:-

1) Please use Code tags when posting code and not Quote tags.
2) Turn Option Strict On and Option Explicit On in your projects. This will give you a load of conversion errors but this will help later on when trying to figure out conversion issues with your variables. If you do this now then you will need to Cast your sender object on the form to the correct type. i.e:-

VB.NET:
lblCountdown.Text = DirectCast(sender, CountDown).Minutes & ":" & DirectCast(sender, CountDown).Seconds & " left"
 
Back
Top