Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

.NET component that simplifies tracking of system's idle time

0.00/5 (No votes)
13 Jul 2008 1  
A .NET component that simplifies tracking of system's idle time.

SystemIdleTimer Demo Application

Introduction

Often, it is needed to track a system's idle time and execute code if the system becomes idle for a certain period of time. Even though .NET framework does not have built-in functionality for this, it is quite easy to implement it using P/Invoke. Anyway, I wanted to develop a component that you could put on a form and set the parameters, and it will do the rest. So, here it is.

Getting system's idle time

First, a little bit explanation about how to track a system's idle time. Since the .NET framework has no built-in functionality for this, we must use the Win32 API. We can use the GetLastInputInfo function for this purpose. The GetLastInputInfo function is located in User32.dll.

<DllImport("User32.dll")> _
Private Shared Function GetLastInputInfo(ByRef lii As LASTINPUTINFO) As Boolean
End Function

Since GetLastInputInfo requires a LASTINPUTINFO structure, it must also be defined.

Public Structure LASTINPUTINFO
    Public cbSize As UInteger
    Public dwTime As UInteger
End Structure

And, the function that will return the total idle time is:

Public Shared Function GetIdle() As UInteger
    Dim lii As New LASTINPUTINFO()
    lii.cbSize = Convert.ToUInt32((Marshal.SizeOf(lii)))
    GetLastInputInfo(lii)
    Return Convert.ToUInt32(Environment.TickCount) - lii.dwTime
End Function

That's all the code needed to find the total idle time. All code related to Win32 API is located in the Win32Wrapper class. Here is the complete Win32Wrapper class.

Public Class Win32Wrapper
    Public Structure LASTINPUTINFO
        Public cbSize As UInteger
        Public dwTime As UInteger
    End Structure

    <DllImport("User32.dll")> _
    Private Shared Function GetLastInputInfo(ByRef lii As LASTINPUTINFO) As Boolean
    End Function

    Public Shared Function GetIdle() As UInteger
        Dim lii As New LASTINPUTINFO()
        lii.cbSize = Convert.ToUInt32((Marshal.SizeOf(lii)))
        GetLastInputInfo(lii)
        Return Convert.ToUInt32(Environment.TickCount) - lii.dwTime
    End Function
End Class

The SystemIdleTimer component

My primary goal was to create a component that would be simple to use. The result is that the SystemIdleTimer component has only a few properties. The component has a MaxIdleTime property that is used to define the maximum idle time in seconds.

For example, to set MaxIdleTime to 2 seconds, you can use the following code:

SystemIdleTimer1.MaxIdleTime = 2

The component exposes the following events:

  • OnEnterIdleState - This event is fired when the system becomes idle for an amount of time defined in the MaxIdleTime property.
  • OnExitIdleState - This event is fired when the system exists the idle state.

The SystemIdleTimer's Start method is used to start tracking the idle time. A Stop method is also available.

Here is the SystemIdleTimer class code:

Public Class SystemIdleTimer _
       Inherits Component

    Private Const INTERNAL_TIMER_INTERVAL As Double = 550

    <Description("Event that if fired when idle state is entered.")> _
    Public Event OnEnterIdleState(ByVal sender As Object, ByVal e As IdleEventArgs)
    <Description("Event that is fired when leaving idle state.")> _
    Public Event OnExitIdleState(ByVal sender As Object, ByVal e As IdleEventArgs)

    Private ticker As Timers.Timer
    Private m_MaxIdleTime As Integer
    Private m_LockObject As Object
    Private m_IsIdle As Boolean = False


    <Description("Maximum idle time in seconds.")> _
    Public Property MaxIdleTime() As UInteger
        Get
            Return m_MaxIdleTime
        End Get
        Set(ByVal value As UInteger)
            If value = 0 Then
                Throw New ArgumentException("MaxIdleTime must be larger then 0.")
            Else
                m_MaxIdleTime = value
            End If
        End Set
    End Property
    Public Sub New()
        m_LockObject = New Object()
        ticker = New Timers.Timer(INTERNAL_TIMER_INTERVAL)
        AddHandler ticker.Elapsed, AddressOf InternalTickerElapsed
    End Sub
    Public Sub Start()
        ticker.Start()
    End Sub
    Public Sub [Stop]()
        ticker.Stop()
        SyncLock m_LockObject
            m_IsIdle = False
        End SyncLock
    End Sub
    Public ReadOnly Property IsRunning() As Boolean
        Get
            Return ticker.Enabled
        End Get
    End Property
    Private Sub InternalTickerElapsed(ByVal sender As Object, _
                                      ByVal e As Timers.ElapsedEventArgs)
        Dim idleTime As UInteger = Win32Wrapper.GetIdle()
        If idleTime > (MaxIdleTime * 1000) Then
            If m_IsIdle = False Then
                SyncLock m_LockObject
                    m_IsIdle = True
                End SyncLock
                Dim args As New IdleEventArgs(e.SignalTime)
                RaiseEvent OnEnterIdleState(Me, args)
            End If
        Else
            If m_IsIdle Then
                SyncLock m_LockObject
                    m_IsIdle = False
                End SyncLock
                Dim args As New IdleEventArgs(e.SignalTime)
                RaiseEvent OnExitIdleState(Me, args)
            End If
        End If
    End Sub
End Class

The class IdleEventArgs is also needed for firing the OnEnterIdleState and OnExitIdleState events.

Public Class IdleEventArgs_
       Inherits EventArgs

    Private m_EventTime As DateTime
    Public ReadOnly Property EventTime() As DateTime
        Get
            Return m_EventTime
        End Get
    End Property
    Public Sub New(ByVal timeOfEvent As DateTime)
        m_EventTime = timeOfEvent
    End Sub
End Class

Using the SystemIdleTimer component

All you have to do is to put the SystemIdleTimer component on your form, then define the MaxIdleTime property of the SystemIdleTimer component.

MaxIdleTime property

Then, define the code needed to execute on the OnEnterIdleState and OnExitIdleState events.

Events on SystemIdleTimer compoenent

And somewhere in your code, start the SystemIdleTimer component using its Start method. For example:

Private Sub Form1_Load(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles MyBase.Load
        SystemIdleTimer1.Start()
End Sub

That's it. I hope you will find this article useful.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here