You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Win32 API的系统空闲时间计算出现负数异常求助

问题原因分析
  • 32位API函数溢出导致:你大概率使用了GetTickCount()这个32位API计算空闲时间。该函数返回系统启动以来的毫秒数,是32位无符号整数,会在系统持续运行约49.7天后溢出归零并重新计数。溢出发生后,GetTickCount()返回的数值会小于LASTINPUTINFO结构中记录的最后输入时间(dwTime),两者相减时,在PowerShell的有符号整数环境下就会得到负数结果。

  • 未使用64位替代函数:若脚本运行在64位系统上,应该优先调用GetTickCount64(),它返回64位整数,几乎不会出现溢出问题(要溢出需系统连续运行约292亿年,完全不可能)。

  • 变量类型的隐性转换:即便你检查了变量类型,DWORD(32位无符号)在PowerShell中会被自动转换为有符号整数。当GetTickCount()溢出后,较小的有符号整数减去较大的有符号整数,结果自然为负。

修复方案
  • 替换API调用:把脚本中调用GetTickCount()的部分改为GetTickCount64(),对应的P/Invoke声明需调整返回值类型为UInt64:

    Add-Type @"
    using System;
    using System.Runtime.InteropServices;
    public class User32 {
        [DllImport("user32.dll")]
        public static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
        [StructLayout(LayoutKind.Sequential)]
        public struct LASTINPUTINFO {
            public uint cbSize;
            public uint dwTime;
        }
        [DllImport("kernel32.dll")]
        public static extern UInt64 GetTickCount64();
    }
    "@
    
  • 重新计算空闲时间:用GetTickCount64()的结果减去LASTINPUTINFO.dwTime,得到正确的空闲毫秒数,不会出现负数:

    $lastInputInfo = New-Object User32+LASTINPUTINFO
    $lastInputInfo.cbSize = [System.Runtime.InteropServices.Marshal]::SizeOf($lastInputInfo)
    [void][User32]::GetLastInputInfo([ref]$lastInputInfo)
    $idleTimeMs = [User32]::GetTickCount64() - $lastInputInfo.dwTime
    

内容的提问来源于stack exchange,提问作者Andrew D

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 06:55:03