13

Is there a way to query windows how much time is left until it goes to suspend/sleep mode?

I am using vbscript and suspect there might be a WMI answer, but any language like c/c++, *.NET, or even java, if possible, may fit my needs.

EDIT

I want to be able to query Windows with a method, not to be alerted by events when it is about to suspend.

Eduardo Poço
  • 2,819
  • 1
  • 19
  • 27

2 Answers2

7

There's no API to know how much time is left since Windows will try to complete entering S3 (Sleep) or S4 (Hibernate) as quick as possible.

Windows will send a notification to all processes about the pending power state change and allow applications to prepare for that event.

You can find most of what you need here.

Basically you have 20 seconds to process the first message. Your process can delay replying to the message, taking care of all the various power cycle tasks, e.g. close files, save your state, etc.

egur
  • 7,830
  • 2
  • 27
  • 47
4

You might want to call CallNtPowerInformation API function that takes the following params:

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

In the InformationLevel paramer you pass the SystemPowerInformation enum value that fills the lpOutputBuffer with a SYSTEM_POWER_INFORMATION structure:

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

Then get the TimeRemaining, which is expressed in seconds.

edit: tested in VB.NET. edit: code added.

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

Form:

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
vulkanino
  • 9,074
  • 7
  • 44
  • 71
  • 1
    There is a bug mentioned in the link from @HansPassant - *TimeRemaining is actually LONG, not ULONG. (TimeRemaining goes into negative numbers when the system is due to sleep but is unable to for whatever reason.)* – Weather Vane Dec 21 '15 at 16:24
  • It is returning random strange values each time it runs. I added a **iSpan.Days** to verify and it goes up to 1044 days. Did that happened to you? – Eduardo Poço Dec 21 '15 at 17:53
  • The `TimeRemaining` is undefined when the function's return value is not 0. The problem is that this function returns an error I couldn't decipher, maybe due to query permissions? 0xC0000005 – vulkanino Dec 22 '15 at 07:53