VB6 overflow error when using function TimeGetTime of winmm.dll

I use the function TimeGetTime to control time spans in this way (to do something all 20 s):

Public Declare Function gr_GetTime Lib "winmm.dll" _
  Alias "timeGetTime" _
  () As Long
Public StartNew as long


StartNew = gr_GetTime()
Do while True
  If Abs(gr_GetTime() - StartNew) >= 20000 Then
    'Do something
    StartNew = gr_GetTime()
  end if '20 s later?

This works fine for at most 24.8551 days. Then an overflow error occurs because in VB6 long variagles are signed whereas timeGetTime returns unsigned dword (32 bit). So the difference between actuell time and StartNew exceeds 2,147,483,647 (the range of VB6 longs).

What can I best do to avoid this failure?
(The function's TimeGetTime >>return value wraps around to 0 every 2^32 milliseconds, which is about 49.71 days<<, so that is no problem)
see: http://msdn.microsoft.com/de-de/library/windows/desktop/dd757629%28v=vs.85%29.aspx

Thanks for help
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

This may work....

Can you save the result in a double rather than a long.

Also why don't you use a timer control or use Now to return the current time and then use DateDiff to check for 20 seconds elapsing.
If, for accuracy, you require a very big 'integer' type, you can use the Currency type.

It will deal with at least 14 decimal places, but will not ignore the least significant digits if they have an absolute value greater than .0001.

In fact it, as designed, it can take four (non-lossy) decimal places, so it can be arithmetically manipulated to cater for integers with 18 digits.
joschrammAuthor Commented:
Hi, ChloesDad,
>>Also why don't you use a timer control or use Now to return the current time and then use DateDiff to check for 20 seconds elapsing.<<
Because I needed a precise timer with a great range of time intervalls, which are very nice with long vars. So since years and years I use TimeGetTime in nearly all my projects. Unfortunately it never occurred to me that the said problem exists.
So I would like still to use longs. I need an encapsulating funged gr_GetTime with this features:
VB6 maps hex values to long in this way:
00000000 .. 7FFFFFFF ==> 0 .. 2147483647
80000000 .. FFFFFFFF ==> -2147483648 .. -1
I need this mapping:
00000000 .. 7FFFFFFF ==> 0 .. 2147483647
80000000 .. FFFFFFFF ==> 2147483648 .. 1
How do I achieve this?
Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook now!

If you need numbers greater than 2 billion, you MUST move to a different data type like the other experts recommended.  Still pull back a long from the API (since you can not change that) but wrap your function call in another function that returns a different data type.

Once you've done that, you can have your wrapper function take negative numbers and modify them to the appropriate value... something like this:  (Sorry, this is off the cuff as I currently don't have a VB6 editor to check the text).

Public Function GetTimeDouble() as double
Dim lTime as long
Dim dTime as double

    lTime = gr_GetTime();
    if lTime < 0 Then
        dTime = CDbl( lTime )
        GetTimeDouble = 4294967296.0 - dTime;
        GetTimeDouble = CDbl( lTime )
    end if
End Function

Open in new window

Otherwise, you have to find a way to deal with negative numbers.  Interestingly enough, your last statement above basically asks for a way to map 800000000...FFFFFFFF to make to 2147483648 to 1... which you can do by multiplying the result by negative one... except for when you have the value 80000000... since there is no way to represent positive 2147483648 with a signed long.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
joschrammAuthor Commented:
Hi HooKooDooKu,
thats it!
Many thanks
That solution is still setting the return value into a long, so will still crash when you try and put a value >= 2^31

Public Function GetTimeDouble() as double
Dim dTime as double

    dTime = CDbl(gr_GetTime());
    if dTime < 0 Then
        GetTimeDouble = 4294967296.0 - dTime;
        GetTimeDouble = dTime
    end if
End Function

Open in new window

joschrammAuthor Commented:
Hi CloesDad,  you are right, of course. However: The function's TimeGetTime >>return value wraps around to 0 every 2^32 milliseconds (see above). What is more:
 if dTime < 0 Then
        GetTimeDouble = 4294967296.0 - dTime;
should be
 if dTime < 0 Then
        GetTimeDouble = 4294967296.0 + dTime;
as dTime is clearly negative.
I did some more musing and now found this solution:
Private Declare Function my_GetTime Lib "winmm.dll" _
  Alias "timeGetTime" _
  () As Long

' Procedure : gr_GetTime
' Author    : JSchramm
' Date      : 10.11.2014
' Purpose   : Wrapper to prevent Out Of Range Error through the fact that VB long values are signed,
'             whereas timeGetTime delivers unsigned word

'             Use of gr_GetTime (all times in ms):
'             lTimeStart = gr_GetTime()
'             ...
'             lSomeTimeLater = Abs(gr_GetTime() - lTimeStart)
'             Only in case of wraparound between two immediately following calls of my_GetTime
'             over the "magical" border of &H80000000 there is a loss of one millisecond (ms)

Public Function gr_GetTime()
  Dim lTimeCur As Long
  lTimeCur = my_GetTime()
  If lTimeCur = &H80000000 Then
    'to prevent out of Range thru result of -1 * &H80000000
    'which would be greater than &H7FFFFFFF, the greatest positive long value
    lTimeCur = &H7FFFFFFF
  ElseIf lTimeCur < 0 Then
    lTimeCur = CLng(-1# * CDbl(lTimeCur))
    'lTimeCur is not changed
  End If 'special cases
  gr_GetTime = lTimeCur
End Function
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic Classic

From novice to tech pro — start learning today.