Solved

VB6 overflow error when using function TimeGetTime of winmm.dll

Posted on 2014-10-27
7
446 Views
Last Modified: 2014-11-10
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
  DoEvents
  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
Josef
0
Comment
Question by:joschramm
7 Comments
 
LVL 15

Expert Comment

by:ChloesDad
Comment Utility
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.
0
 
LVL 76

Expert Comment

by:GrahamSkan
Comment Utility
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.
0
 

Author Comment

by:joschramm
Comment Utility
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?
0
Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

 
LVL 16

Accepted Solution

by:
HooKooDooKu earned 500 total points
Comment Utility
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;
    else
        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.
0
 

Author Closing Comment

by:joschramm
Comment Utility
Hi HooKooDooKu,
thats it!
Many thanks
Josef
0
 
LVL 15

Expert Comment

by:ChloesDad
Comment Utility
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;
    else
        GetTimeDouble = dTime
    end if
End Function

Open in new window

0
 

Author Comment

by:joschramm
Comment Utility
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))
  Else
    'lTimeCur is not changed
  End If 'special cases
  gr_GetTime = lTimeCur
 
End Function
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

When trying to find the cause of a problem in VBA or VB6 it's often valuable to know what procedures were executed prior to the error. You can use the Call Stack for that but it is often inadequate because it may show procedures you aren't intereste…
Article by: Martin
Here are a few simple, working, games that you can use as-is or as the basis for your own games. Tic-Tac-Toe This is one of the simplest of all games.   The game allows for a choice of who goes first and keeps track of the number of wins for…
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now