【问题标题】:integer wrap-around issue with GetLastInputInfoGetLastInputInfo 的整数环绕问题
【发布时间】:2012-06-27 16:47:12
【问题描述】:

我想检查我的应用程序中的用户不活动。我做了一些研究并选择使用 GetLastInputInfo 和 Environment.TickCount 因为它看起来很简单。不幸的是,结果有点棘手。

GetLastInputInfo 返回一个 LASTINPUTINFO 结构,该结构具有最后一个“TickCount”值作为 DWORD(即 UInt32)。理论上,我想从 Environment.TickCount 中减去该值,这样我就知道了用户处于非活动状态的毫秒数。

Environment.TickCount 返回一个 Int32。当它们达到最大值时,两者都会环绕,这对于 Int32 和 UInt32 是不同的。处理这个我有点不舒服,特别是因为代码基本上无法测试(Environment.TickCount 会在 24.9 天后回绕,并且该功能应在此之前到期)。

这是我到目前为止所做的:

[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!
  }
}

是否有一种足够简单的方法来处理这两种环绕,或者我应该使用另一种方法来完全检测用户的不活动状态?也欢迎任何关于如何在不使用计算机 25 天的情况下进行测试的建议。

【问题讨论】:

  • 请记住,这种方式只能检测到用户不活动时间以 ~50 天为模。
  • @HristoIliev 感谢您的提醒,但此功能的用例是 5 分钟到 1 小时不活动,所以这不是问题。

标签: c# .net winapi int


【解决方案1】:

由于不活动的时间远远小于滴答计数器的容量,所以这根本不是问题。

如果其中一个计数器已经环绕而不是另一个,则减法中的结果也将环绕并为您提供正确的结果。您只需要转换这些值,以便它们是相同的数据类型:

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

例如,如果 Environment.TickCount 已回绕到 -2147483612 并且 lastInputInfo.dwTime 为 2147483624,则 -2147483612 - 2147483624 = 60。

您甚至可以将这两个值转换为较小的数据类型,例如 Int16,只要空闲时间适合数据类型,在减法之后您仍然会得到正确的结果。

【讨论】:

  • 看起来是正确的,我在 F# 交互中做了一些测试来验证。 :P 谢谢!
  • 确认一下,假设你使用 Win32 GetTickCount() 返回一个 uint,结果是否正确?
  • 如果系统正常运行时间达到49.7天,并且最后一次用户交互发生在Environment.TickCount环绕之前,那么只要用户处于空闲状态,就无法获取idleTime?
【解决方案2】:

这只是对 Guffa 答案的补充。

在依赖整数溢出时始终使用unchecked 关键字是“最佳实践”。这有两个原因:

  1. 它让读者知道你故意依赖溢出
  2. 虽然未选中是 C# 中的默认设置,但可以在编译器的命令行上进行更改。

Checked and Unchecked (C# Reference)

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

【讨论】:

  • +1 是的,这使得代码信息量更大,更健壮,不依赖于特定的编译器设置。
猜你喜欢
  • 2013-01-08
  • 1970-01-01
  • 2023-02-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-16
  • 1970-01-01
  • 2015-11-13
  • 1970-01-01
相关资源
最近更新 更多