Click here to Skip to main content
Click here to Skip to main content
Go to top

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

, 13 Jul 2008
Rate this:
Please Sign up or sign in to vote.
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Dazdarevic Edin
Software Developer DevLogic d.o.o
Bosnia And Herzegovina Bosnia And Herzegovina
No Biography provided

Comments and Discussions

 
Generalclose the application [modified] Pinmembergktamilarasan28-Sep-10 2:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140916.1 | Last Updated 13 Jul 2008
Article Copyright 2008 by Dazdarevic Edin
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid