• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 597
  • Last Modified:

Detecting Systemwide User Idle Time in Windows XP with Visual Basic .NET

Hello all,
          This might be a silly question but I just can't figure it out and any help would be greatly appreciated.

I am trying to code a routine in Visual Basic .NET that will tell me how long the user has been idle (how long since no keyboard and mouse input has been detected.) If idle time exceeds a certain ammount of minutes, my program needs to pop up a message and do other things.

I have tried to use the API GetLastInputInfo in order retrieve this information, but it is just not working.  Here is the code I am using:

In a module, I have added:

    Public Structure LastInputInfo
        Public cbSize As Long
        Public dwTime As Long
    End Structure

    Declare Function GetLastInputInfo Lib "User32" (ByRef lastinfo As LastInputInfo) As Boolean

And my form code reads something like this (I have ommited Windows Form Designer Generated Code for the sake of clarity):

Private Sub Timer1_Elapsed(ByVal sender As System.Object, ByVal e As System.Timers.ElapsedEventArgs) Handles Timer1.Elapsed

        'Timer is set to run every second

        Dim res As Boolean
        Dim info As LastInputInfo

        info.cbSize = Len(info)
        res = GetLastInputInfo(info)
        MessageBox.Show(res & " " & info.dwTime.ToString)
          ' This messagebox is there for debug purposes.  It ends up showing that res is False and
          '  info.dwTime.ToString is 0; indicating the function has failed.

          ' I have also omitted the code to test for elapsed idle time, etc, since the point here is to
          '   show the function is failing.

End Sub

What I don't understand is why the function is failing.  I must be doing something wrong, either when declaring it, or when calling it.

I don't necessarily have to use GetLastInputInfo, I just thought using that API would be the easiest and 'cleanest' way of telling how long the system has been idle.  I am open for other solutions as well.  Just keep in mind my program is coded in Visual Basic .NET and I know nothing of C++.

Any help greatly appreciated. Thank you very much!
1 Solution
Jason EvansSenior Software DeveloperCommented:

Hi there.

Try using the following code in your form:

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.ANSI)> Public Structure LastInputInfo
    Public cbSize As Int32
    Public dwTime as int32
End Structure

Private Declare Function GetLastInputInfo Lib "User32.dll" (<MarshalAs(UnmanagedType.Struct)> ByRef lpLastInputInfo As LastInputInfo) As Int32  

I tried this just now and it works fine. The new method of passing types/structures in VB.NET can be a bit scary at first, but u get used to it.

Hope this helps.
Another way to do this is to set up a system wide hook on all keyboard and mouse inputs, this everytime you get one, just "reset" your start counter and disable, reenable a timer.  If the timer fires (time has elasped) then the system has been idle for your elasped time. This is a method to keep you from "polling" the system and chewing up a lot of cycles.

if you need more detail, let me know.

SpandaAuthor Commented:
Thank you for the quick response.  This has fixed my problem.  If I may add, one needs to add the following line of code in order for the declarations to work: Imports System.Runtime.InteropServices

Featured Post

Become an Android App Developer

Ready to kick start your career in 2018? Learn how to build an Android app in January’s Course of the Month and open the door to new opportunities.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now