views:

173

answers:

4

LastInput.time is an Integer and m_idleTime is an Integer too. This line sometimes generates an Overflow exception, I think that this happens when both values are big negative values.

(Environment.TickCount - lastInput.time) > m_idleTime

How can I avoid that? With casting?

(CType(Environment.TickCount,Long) - CType(lastInput.time,Long)) > m_idleTime

Or maybe with this cast?

CType((Environment.TickCount - lastInput.time),Long) > m_idleTime

Thanks in advance.

EDIT: I'm using the GetLastInputInfo method to check how many time has been the computer idle. I have declared the return value from the call this way:

    <StructLayout(LayoutKind.Sequential)> Public Structure StructLastInputInfo
        <MarshalAs(UnmanagedType.U4)> Dim size As Integer
        <MarshalAs(UnmanagedType.U4)> Dim time As Integer
    End Structure

So I think that when the Environment.TickCount returns a negative value the same will happen with the GetLastInputInfo, right? But then the values of the substraction will be wrong because they will be negative, so as far as I see the problem what should be done is this:

Math.Abs(CType(Environment.TickCount, Long) - CType(lastInput.time, Long)) > m_idleTime

What do you think?

+1  A: 

Assuming the problem is as you described, you need the first of those options:

(CType(Environment.TickCount,Long) - CType(lastInput.time,Long)) > m_idleTime

The second will fail before it converts to Long, because the conversion is done after the calculation.

But I would think that you shouldn't have large negative values in this calculation. Note that after 24.9 days, Environment.TickCount overflows and becomes negative. Maybe this is what is happening? If so, the above code won't throw but it will give the wrong answer.

Why are you doing it this way? Why not just compare two DateTimes?

Mark Byers
Well, the fact is that this bug happens after a long running time. I'm doing this in this way because I'm using the GestLastInput Windows API and this returns an Integer tickcount, not a DateTime. I don't know if there is a better way of doing this.
SoMoS
Is "a long running time" about 25 days?
Mark Byers
Yes, it can be running more that 25 days.
SoMoS
A: 

In C# we just use "unchecked" block. Not sure what's the equivalent in VB.NET.

Lex Li
As far as I know this feature is not available in Vb.Net
SoMoS
+1  A: 

Yes, this code will bomb after the machine has been running for 2^31 milliseconds. You cannot selectively suppress overflow checking in VB.NET. There's only one fix for this: Project + Properties, Compile tab, scroll down, Advanced Compile Options, check "Remove integer overflow checks". It is not a terrible loss but you do lose a level of protection.

Another way to do this that doesn't cause overflow is by using DateTime.UtcNow. Subtracting produces a TimeSpan, use its TotalMilliseconds property. The accuracy is the same. Beware that it returns a Double, avoid equality checks.

Hans Passant
But doing the cast will also avoid the exception isn't it?
SoMoS
No exception, but also a timer that no longer works. You need the overflow to make it work.
Hans Passant
Please, check the edit of the question.
SoMoS
Yes, it will fail with LastInputInfo.dwTime. Using DateTime won't work, use the "Remove integer overflow checks" option. You can put the code in a separate assembly if you prefer to leave it on for the rest of your code.
Hans Passant
Mmm, can you say why my last line won't work? As far as I see the problem it should work because now you don't have Overflows and the change of sign is handled with the Abs, isn't that right? Thanks in advance Nobugz, I recall that you helped me several times here and in other forums. Thanks a lot.
SoMoS
Hans Passant
Can you check my own solution to see if you agree with it? It is working with numbers but maybe there are some side effects that I don't see.
SoMoS
A: 

That's how I fixed the problem:

            currentTime = BitConverter.ToUInt32(BitConverter.GetBytes(Environment.TickCount), 0) #'' This code can fail with 1 tick error when changing the sign of one item.
            lastInputTime = BitConverter.ToUInt32(BitConverter.GetBytes(lastInput.time), 0)

            If currentTime - lastInputTime > m_idleTime Then

This code works because you get the bytes of the Integer and just use them as if they where an UInteger, this does not throw OverflowException.

The only problem I've seen is that you have a 1 unit error when doing the subtraction when the sign of one item has changed, not sure about what is happening but anyway having 1 tick error is not an issue.

SoMoS