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

如何通过CallNtPowerInformation获取LastSleepTime?代码示例求助

使用CallNtPowerInformation获取LastSleepTime的完整示例

嘿,我看到你在调用CallNtPowerInformation接口获取上次睡眠时间时遇到了问题,我来帮你梳理下正确的实现方式,附上可运行的完整代码:

首先,你原来的DllImport声明有个小问题:lpOutputBuffer不需要用ref修饰,我们需要手动分配内存缓冲区传递给API,调用完成后再从缓冲区读取数据。另外,要明确LastSleepTime对应的POWER_INFORMATION_LEVEL枚举值是27,返回的是一个64位的FILETIME格式时间值。

完整代码实现

using System;
using System.Runtime.InteropServices;

public class PowerInfoHelper
{
    // 定义POWER_INFORMATION_LEVEL枚举,这里只列出我们需要的LastSleepTime
    private enum POWER_INFORMATION_LEVEL : uint
    {
        LastSleepTime = 27
    }

    // 修正后的DllImport声明
    [DllImport("PowrProf.dll", SetLastError = true)]
    private static extern uint CallNtPowerInformation(
        POWER_INFORMATION_LEVEL InformationLevel,
        IntPtr lpInputBuffer,
        uint nInputBufferSize,
        IntPtr lpOutputBuffer,
        uint nOutputBufferSize
    );

    public DateTime? GetLastSleepTime()
    {
        // LastSleepTime返回的是8字节的LARGE_INTEGER(对应.NET的long)
        const int bufferSize = 8;
        IntPtr outputBuffer = IntPtr.Zero;

        try
        {
            // 分配非托管内存缓冲区
            outputBuffer = Marshal.AllocHGlobal(bufferSize);

            // 调用API获取LastSleepTime
            uint result = CallNtPowerInformation(
                POWER_INFORMATION_LEVEL.LastSleepTime,
                IntPtr.Zero, // 不需要输入缓冲区
                0,
                outputBuffer,
                (uint)bufferSize
            );

            // 检查调用是否成功(返回0表示成功)
            if (result != 0)
            {
                int errorCode = Marshal.GetLastWin32Error();
                throw new System.ComponentModel.Win32Exception(errorCode);
            }

            // 从缓冲区读取64位整数(FILETIME格式)
            long fileTime = Marshal.ReadInt64(outputBuffer);

            // 将FILETIME转换为DateTime(FILETIME是从1601年1月1日开始的100纳秒间隔)
            if (fileTime == 0)
            {
                // 如果返回0,表示系统从未进入过睡眠状态
                return null;
            }

            return DateTime.FromFileTime(fileTime);
        }
        finally
        {
            // 释放非托管内存,避免泄漏
            if (outputBuffer != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(outputBuffer);
            }
        }
    }

    // 调用示例
    public static void Main()
    {
        PowerInfoHelper helper = new PowerInfoHelper();
        try
        {
            DateTime? lastSleep = helper.GetLastSleepTime();
            if (lastSleep.HasValue)
            {
                Console.WriteLine($"上次睡眠时间:{lastSleep.Value:yyyy-MM-dd HH:mm:ss}");
            }
            else
            {
                Console.WriteLine("系统从未进入过睡眠状态");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"获取失败:{ex.Message}");
        }
    }
}

关键说明

  • 缓冲区管理:必须手动分配和释放非托管内存,因为CallNtPowerInformation不会自动管理这些内存,忘记释放会导致内存泄漏。
  • 错误处理:调用失败时通过Marshal.GetLastWin32Error()获取具体的Windows错误码,方便排查问题。
  • 时间转换:返回的FILETIME值需要用DateTime.FromFileTime()转换为.NET的DateTime类型,如果返回0则表示系统从未睡眠过。
  • 参数修正:把nInputBufferSize和nOutputBufferSize改为uint类型,更贴合原生API的参数定义,避免类型转换问题。

你可以直接运行这段代码,测试获取上次睡眠时间的功能,如果还有问题,可以查看控制台输出的错误信息来进一步排查。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:38:14