Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

integer wrap-around issue with GetLastInputInfo

Tags:

c#

.net

int

winapi

I want to check for user inactivity in my application. I did a little bit of research and went for using GetLastInputInfo and Environment.TickCount because it seemed very simple. Unfortunately it turns out to be a little bit touchy.

GetLastInputInfo returns a LASTINPUTINFO structure which has the last "TickCount" value as a DWORD (i.e. UInt32). In theory, I want to substract that value from Environment.TickCount and that gives me for how many ms the user has been inactive.

Environment.TickCount returns an Int32. Both will wrap around when they hit their max value, which is different for an Int32 and a UInt32. I'm a little uncomfortable dealing with this especially since the code essentially can't be tested (Environment.TickCount wraps around after 24.9 days and the feature is due before that).

Here's what I've done so far:

[DllImport("user32.dll")]
static extern bool GetLastInputInfo(out LastInputInfo plii);
struct LastInputInfo
{
  public uint cbSize;
  public uint dwTime;
}

//(...)
var lastInputInfo = new LastInputInfo();
lastInputInfo.cbSize = (uint)Marshal.SizeOf(lastInputInfo);
if (GetLastInputInfo(out lastInputInfo))
{
  // The next line obviously will not work when either of the terms has wrapped around
  var idleTime = Environment.TickCount - lastInputInfo.dwTime;
  if (idleTime > mTimeOut)
  {
    // user is inactive!
  }
}

Is there a simple enough way to deal with both wrap-arounds or should I use another approach to detect user inactivity altogether? Also any advice on how to test this without dedicating a computer for 25 days is appreciated.

like image 505
Asik Avatar asked Dec 21 '22 19:12

Asik


1 Answers

As the period of inactivity is considerably smaller than the capacity of the tick counters, it's not a problem at all.

If one of the counters have wrapped around and not the other, the result in your subtraction will also wrap around and give you the correct result. You just have to cast the values so that the are the same data type:

int idleTime = Environment.TickCount - (int)lastInputInfo.dwTime;

If for example Environment.TickCount has wrapped around to -2147483612 and lastInputInfo.dwTime is 2147483624, then -2147483612 - 2147483624 = 60.

You could even cast both values down to a smaller data type, like Int16, and you would still get the correct result after the subtraction as long as the idle time fits in the data type.

like image 59
Guffa Avatar answered Jan 07 '23 15:01

Guffa