【问题标题】:Time left until Windows suspend距离 Windows 挂起的剩余时间
【发布时间】:2015-12-21 14:06:58
【问题描述】:

有没有办法查询窗口在进入挂起/睡眠模式之前还剩多少时间?

我正在使用 vbscript 并怀疑可能有 WMI 答案,但任何语言,如 c/c++、*.NET 甚至 java,如果可能的话,都可能满足我的需求。

编辑

我希望能够使用一种方法查询 Windows,而不是在即将挂起时收到事件警报。

【问题讨论】:

标签: c++ c windows wmi


【解决方案1】:

没有 API 可以知道还剩多少时间,因为 Windows 会尝试尽快完成进入 S3(睡眠)或 S4(休眠)。

Windows 将向所有进程发送有关未决电源状态更改的通知,并允许应用程序为该事件做好准备。

您可以在here找到大部分您需要的东西。

基本上你有 20 秒的时间来处理第一条消息。您的进程可能会延迟回复消息,处理所有各种电源循环任务,例如关闭文件,保存您的状态等。

【讨论】:

    【解决方案2】:

    您可能想要调用采用以下参数的CallNtPowerInformation API 函数:

    NTSTATUS WINAPI CallNtPowerInformation(
      _In_  POWER_INFORMATION_LEVEL InformationLevel,
      _In_  PVOID                   lpInputBuffer,
      _In_  ULONG                   nInputBufferSize,
      _Out_ PVOID                   lpOutputBuffer,
      _In_  ULONG                   nOutputBufferSize
    );
    

    在InformationLevel 参数中,您传递SystemPowerInformation 枚举值,该值用SYSTEM_POWER_INFORMATION 结构填充lpOutputBuffer:

    typedef struct _SYSTEM_POWER_INFORMATION {
      ULONG MaxIdlenessAllowed;
      ULONG Idleness;
      ULONG TimeRemaining;
      UCHAR CoolingMode;
    } SYSTEM_POWER_INFORMATION, *PSYSTEM_POWER_INFORMATION;
    

    然后得到TimeRemaining,以秒为单位。

    编辑:在 VB.NET 中测试。 编辑:添加代码。

    Queryer.vb

    Imports System.Runtime.InteropServices
    
    Public Class Queryer
    
        Const SystemPowerInformation As Integer = 12
        Const STATUS_SUCCESS As Integer = 0
    
        Private Structure SYSTEM_POWER_INFORMATION
            Public MaxIdlenessAllowed As UInteger
            Public Idleness As UInteger
            Public TimeRemaining As Integer
            Public CoolingMode As Byte
        End Structure
    
        <DllImport("PowrProf.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
        Public Shared Function CallNtPowerInformation(
                ByVal InformationLevel As Int32,
                ByVal lpInputBuffer As IntPtr,
                ByVal nInputBufferSize As UInt32,
                ByVal lpOutputBuffer As IntPtr,
                ByRef nOutputBufferSize As UInt32) As UInt32
        End Function
    
        Public Function Query() As Integer
    
            Dim PowerInformation As SYSTEM_POWER_INFORMATION
            Dim Status As IntPtr = IntPtr.Zero
            Dim ReturnValue As UInteger
            Try
                Status = Marshal.AllocCoTaskMem(Marshal.SizeOf(GetType(SYSTEM_POWER_INFORMATION)))
                ReturnValue = CallNtPowerInformation(SystemPowerInformation, Nothing, 0, Status, Marshal.SizeOf(GetType(SYSTEM_POWER_INFORMATION)))
    
                PowerInformation = Marshal.PtrToStructure(Status, GetType(SYSTEM_POWER_INFORMATION))
            Catch ex As Exception
                Return 0
            Finally
                Marshal.FreeCoTaskMem(Status)
    
            End Try
            Return PowerInformation.TimeRemaining
    
        End Function
    
    End Class
    

    表格:

    Public Class Form1
    
    
        Public Sub Loader() Handles Me.Load
    
            Dim rolex As New Timer()
            rolex.Interval = 500
            AddHandler rolex.Tick, AddressOf TimerScattato
    
            rolex.Start()
    
        End Sub
    
        Private Sub TimerScattato()
            Dim secondi As Integer = q.Query()
            Dim iSpan As TimeSpan = TimeSpan.FromSeconds(secondi)
    
            lblTimeLeft.Text = String.Format("{0,2}:{1,2}:{2,2}", iSpan.Hours, iSpan.Minutes, iSpan.Seconds)
    
    
        End Sub
    
        Private q As New Queryer
    End Class
    

    【讨论】:

    • @HansPassant 的链接中提到了一个错误 - TimeRemaining 实际上是 LONG,而不是 ULONG。 (当系统由于某种原因无法进入睡眠状态时,TimeRemaining 变为负数。)
    • 每次运行时都会返回随机的奇怪值。我添加了一个 iSpan.Days 进行验证,最长可达 1044 天。你遇到过这种情况吗?
    • TimeRemaining 在函数返回值不为 0 时未定义。问题是这个函数返回一个我无法解读的错误,可能是由于查询权限? 0xC0000005
    猜你喜欢
    • 1970-01-01
    • 2017-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-13
    • 2018-02-03
    • 2018-05-01
    • 1970-01-01
    相关资源
    最近更新 更多