GetLastInputInfo计数器溢出问题:寻求解决与测试方案
问题解决与测试建议
问题原因
Environment.TickCount是32位有符号整数,最大值为2^31-1毫秒(约24天20小时31分钟),溢出后会变为负数。同时你定义的Lastinputinfo结构体中dwTime用了int类型,但WinAPI的LASTINPUTINFO结构体中dwTime是无符号32位整数(DWORD),溢出后转成int会导致时间计算错误,最终出现LastInput被算成超前DateTime.Now的情况。
修复方案
1. 修正结构体类型
将dwTime的类型从int改为uint,匹配WinAPI的DWORD定义:
private struct LastInputInfo { public uint cbSize; public uint dwTime; // 替换原readonly int类型 }
2. 补充完整DllImport定义
确保GetLastInputInfo的调用签名正确:
[DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetLastInputInfo(ref LastInputInfo plii);
3. 重新实现空闲时间计算
使用无符号整数减法自动处理TickCount的溢出回绕,同时用Environment.TickCount64(64位整数,无24天溢出问题)计算系统启动时间:
private static uint LastInputTicks { get { var lii = new LastInputInfo { cbSize = (uint)Marshal.SizeOf(typeof(LastInputInfo)) }; GetLastInputInfo(ref lii); return lii.dwTime; } } public static DateTime LastInput { get { // 用TickCount64获取系统运行总毫秒数,避免溢出 long systemUptimeMs = Environment.TickCount64; DateTime systemStartupUtc = DateTime.UtcNow.AddMilliseconds(-systemUptimeMs); // 转换为本地时间返回 return systemStartupUtc.AddMilliseconds(LastInputTicks).ToLocalTime(); } } public static TimeSpan IdleTime { get { uint currentTick = (uint)Environment.TickCount; uint lastInputTick = LastInputTicks; // 无符号减法自动处理溢出回绕,得到正确的空闲毫秒数 uint idleMilliseconds = currentTick - lastInputTick; return TimeSpan.FromMilliseconds(idleMilliseconds); } }
测试建议
1. 单元测试模拟溢出场景
编写单元测试覆盖溢出前后的情况:
- 溢出前场景:模拟
currentTick = 0x7FFFFFFF(TickCount最大值),lastInputTick = 0x7FFFFFFF - 1000,验证IdleTime返回1秒。 - 溢出后场景:模拟
currentTick = 0x00000001(溢出后),lastInputTick = 0xFFFFFFFE(溢出前),验证IdleTime返回3毫秒(无符号减法会自动计算0x00000001 - 0xFFFFFFFE = 0x00000003)。
2. 模拟TickCount返回值
通过反射或测试桩替换Environment.TickCount的返回值,快速验证溢出逻辑:
// 测试时临时替换TickCount(需用反射实现) var tickCountField = typeof(Environment).GetField("s_tickCount", BindingFlags.NonPublic | BindingFlags.Static); tickCountField.SetValue(null, unchecked((int)0x00000001)); // 设置为溢出后的值 // 调用IdleTime并验证结果
3. 长时间运行测试(可选)
在虚拟机中部署程序,设置虚拟机连续运行超过24天20小时,观察程序是否仍能正确计算用户空闲状态(此方法耗时较长,适合最终验证)。
内容的提问来源于stack exchange,提问作者Dhinu Thampi
相关产品推荐
相关产品推荐

