1

I am working on a Windows Service, that needs to know how long the local machine has been idle. I have tried the standard Qt approach, but because the Service is run as LocalSystem, it doesn't register the local users activity.

Any ideas about how to get the machine idle status, when the application is running as LocalSystem?

Terry Jan Reedy
  • 18,414
  • 3
  • 40
  • 52
user1282008
  • 11
  • 1
  • 2

2 Answers2

0

I've found two options.

A user-mode helper.

  1. It calls GetLastInputInfo().
  2. It can be registered as a Task Scheduler task. It should be continuously running like a daemon.
  3. To communicate back to the service, it can use writing to a file, serving HTTP, and probably other IPC methods.

WTSAPI + CreateProcessAsUser() + a user-mode helper.

  1. The helper calls GetLastInputInfo().
  2. But in this case it doesn't have to be always running.
  3. The service finds an active user session with WTSAPI and runs the helper with CreateProcessAsUser().

Why getting into a user session is complicated and how to do it: https://web.archive.org/web/20211106110931/https://3735943886.com/?p=80 https://stackoverflow.com/a/35297713/633969

Andrey Moiseev
  • 3,914
  • 7
  • 48
  • 64
0

Not sure if this helps. From article: here

Since we're using an unmanaged library, first comes the additional using statement:

using System.Runtime.InteropServices;

// Unmanaged function from user32.dll    
[DllImport("user32.dll")]    
static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
// Struct we'll need to pass to the function    
internal struct LASTINPUTINFO    
{    
    public uint cbSize;    
    public uint dwTime;    
}

private void tmrIdle_Tick(object sender, EventArgs e)    
{    
    // Get the system uptime    
    int systemUptime = Environment.TickCount;    
    // The tick at which the last input was recorded    
    int LastInputTicks = 0;    
    // The number of ticks that passed since last input    
    int IdleTicks = 0;            
    // Set the struct    
    LASTINPUTINFO LastInputInfo = new LASTINPUTINFO();    
    LastInputInfo.cbSize = (uint)Marshal.SizeOf(LastInputInfo);    
    LastInputInfo.dwTime = 0;       

    // If we have a value from the function    
    if (GetLastInputInfo(ref LastInputInfo))    
    {    
        // Get the number of ticks at the point when the last activity was seen    
        LastInputTicks = (int)LastInputInfo.dwTime;    
        // Number of idle ticks = system uptime ticks - number of ticks at last input    
        IdleTicks = systemUptime - LastInputTicks;    
    }        

    // Set the labels; divide by 1000 to transform the milliseconds to seconds    
    lblSystemUptime.Text = Convert.ToString(systemUptime / 1000) + " seconds";    
    lblIdleTime.Text = Convert.ToString(IdleTicks / 1000) + " seconds";    
    lblLastInput.Text = "At second " + Convert.ToString(LastInputTicks / 1000);    
}
Andrew
  • 7,619
  • 13
  • 63
  • 117
  • I tried that, but it seems to look at LocalSystem's inactivity, and reports that the system has been inactive since boot... – user1282008 Mar 21 '12 at 05:12
  • If you look at my first comment on your question you'll see it uses this same code but launches this process as the user logged in. Definitely a duplicate quesiton. – Erik Philips Mar 21 '12 at 17:17