I want to know on when was the last time the system was started.
Environment.TickCount will work but it is breaking after 48-49 days because of the limitation of int
public void BootTime(){
SelectQuery query = new SelectQuery("SELECT LastBootUpTime FROM Win32_OperatingSystem WHERE Primary='true'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
foreach (ManagementObject mo in searcher.Get())
{
DateTime dtBootTime = ManagementDateTimeConverter.ToDateTime(mo.Properties["LastBootUpTime"].Value.ToString());
Console.WriteLine(dtBootTime.ToString());
}
}
I am not a fan of using GetTickCount() for timestamp because it can return negative numbers. Even though using Abs() can help, but it's awkward and not an optimal solution.
It's better to use Stopwatch in .Net or QueryPerformanceCounter in C++ as timestamp.
Within a C# application, I create a global Stopwatch object, start it. Later on in the application, I use the Stopwatch.ElapsedMiliseconds as timestamp.
using System;
using System.Diagnostics;
using System.Windows.Forms;
namespace MiscApp
{
public partial class Form1 : Form
{
private Stopwatch globalTimer = new Stopwatch();
private long myStamp1 = 0;
public Form1()
{
InitializeComponent();
globalTimer.Start();
}
private void SomeFunction()
{
if (globalTimer.ElapsedMilliseconds - myStamp1 >= 3000)
{
myStamp1 = globalTimer.ElapsedMilliseconds;
//Do something here...
}
}
}
}
The following code retrieves the milliseconds since system start (call to unmanged API). I measured the performance costs for that interop operation, and it is quite identical to StopWatch() (but that doesn't retrieve the time since system start directly of course).
using System.Runtime.InteropServices;
...
[DllImport("kernel32.dll") ]
public static extern UInt64 GetTickCount64();
...
var tickCount64 = GetTickCount64();
https://msdn.microsoft.com/de-de/library/windows/desktop/ms724411(v=vs.85).aspx
You're correct that Environment.TickCount
will overflow after approximately 25 days, because the return value is a 32-bit integer.
But there's a better way than trying to compare the TickCount
if you want to determine when the system was last started. What you're looking for is called the system up-time. There are a couple of different ways that you can retrieve this.
The easiest way is to use the PerformanceCounter class (in the System.Diagnostics
namespace), which lets you query a particular system performance counter. Try the following code:
TimeSpan upTime;
using (var pc = new PerformanceCounter("System", "System Up Time"))
{
pc.NextValue(); //The first call returns 0, so call this twice
upTime = TimeSpan.FromSeconds(pc.NextValue());
}
Console.WriteLine(upTime.ToString());
Alternatively, you can do this through WMI. But it looks like stian.net's answer has that covered.
Note, finally, that the performance counter's name must be localized if you need to support international versions of Windows, so the correct solution must look up the localized strings for "System" and "System Up Time" using PdhLookupPerfNameByIndex, or you must ensure you are using the PdhAddEnglishCounter under the hood, which is only supported in Vista or higher. More about this here.
If you count each wraparound, you can make your own 64-bit TickCount, good for 2^63 ms (292 million years) or 2^64 ms (585 million years). If you don't need the full 1ms precision (actually only 10-16ms resolution) or range, you can divide the result by 1000 and represent up to 49,710 days (136 years), with a resolution of one second, in a UInt32.
GetTickCount64()
does this for you, but is only available in Vista or later.
Here I count the wraparounds of elapsed time, not TickCount.
// C# (untested)
...
// Initialize and start timer:
uint uiT0 = unchecked((uint)Environment.TickCount); // T0 is NOW. // ms since boot, 10-16ms res.
uint uiElapsedPrev = 0;
uint uiWrapCount = 0;
...
long x = GetElapsedTime();
public static long GetElapsedTime()
{
uint uiElapsed = unchecked((uint)Environment.TickCount - uiT0) // 0 to +49.71 days
if (uiElapsed < uiElapsedPrev) // IF uiElapsed decreased,
uiWrapCount++; // increment the wrap counter.
uiElapsedPrev = uiElapsed; // Save the previous value.
return ( ((long)uiWrapCount << 32) + (long)uiElapsedPrev );
}
ANDing with Int32.MaxValue is unnecessary and a bad example in the .NET documentation. Unchecked subtraction of 32-bit integers overflows safely. The sign of Environment.TickCount never matters. Subtraction handles all cases that wrap around. Example, wraparound by one: uiT0 = Int32.MaxValue; iTickNow = uiT0 + 1 yields Int32.MinValue; finally, (iTickNow - uiT0) yields 1.
uiElapsed tracks elapsed time all the way to 49.7 days before it wraps to zero. Each time it wraps, iWrapCount is incremented. GetElapsedTime() must be called at least once every 49.7 days, so that no wraparound goes undetected.
I think it's just the way they have implemented it.
It goes from 0 to max and then goes from min to 0.
https://msdn.microsoft.com/en-us/library/system.environment.tickcount(v=vs.110).aspx
I have edited the code you are using from http://www.codeproject.com/Articles/13384/Getting-the-user-idle-time-with-C
Why don't you just get the Absolute number?
Public Shared Function GetIdle() As UInteger
Dim lii As New LASTINPUTINFO()
lii.cbSize = Convert.ToUInt32((Marshal.SizeOf(lii)))
GetLastInputInfo(lii)
Dim totalTicks As Long = 0
If Environment.TickCount > 0 Then
totalTicks = Convert.ToUInt64(Environment.TickCount)
Else
totalTicks = Convert.ToUInt64(Environment.TickCount * -1)
End If
Return Math.Abs(totalTicks - lii.dwTime)
End Function