Environment.TickCount 不够

发布于 2024-10-10 21:21:17 字数 976 浏览 12 评论 0原文

我想知道系统最后一次启动是什么时候。

Environment.TickCount 可以工作,但由于 int 的限制,它会在 48-49 天后中断。

这是我一直在使用的代码:

Environment.TickCount & Int32.MaxValue

有人知道长类型返回吗?

我用它来了解系统的空闲时间:

public static int GetIdleTime()
{
    return (Environment.TickCount & Int32.MaxValue)- (int)GetLastInputTime();
}

/// <summary>
/// Get the last input time from the input devices.
/// Exception: 
/// If it cannot get the last input information then it throws an exception with 
/// the appropriate message.
/// </summary>
/// <returns>Last input time in milliseconds.</returns>
public static uint GetLastInputTime()
{
    LastInputInfo lastInPut = new LastInputInfo();
    lastInPut.BlockSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(lastInPut);
    if (!GetLastInputInfo(ref lastInPut))
    {
        throw new Exception(GetLastError().ToString());
    }

    return lastInPut.Time;
}

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.

This is the code I've been using:

Environment.TickCount & Int32.MaxValue

Does anyone knows about long type return somehow?

I am using this to know the idle time of the system:

public static int GetIdleTime()
{
    return (Environment.TickCount & Int32.MaxValue)- (int)GetLastInputTime();
}

/// <summary>
/// Get the last input time from the input devices.
/// Exception: 
/// If it cannot get the last input information then it throws an exception with 
/// the appropriate message.
/// </summary>
/// <returns>Last input time in milliseconds.</returns>
public static uint GetLastInputTime()
{
    LastInputInfo lastInPut = new LastInputInfo();
    lastInPut.BlockSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(lastInPut);
    if (!GetLastInputInfo(ref lastInPut))
    {
        throw new Exception(GetLastError().ToString());
    }

    return lastInPut.Time;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

宣告ˉ结束 2024-10-17 21:21:17

以下代码检索自系统启动以来的毫秒数(调用非托管 API)。我测量了该互操作操作的性能成本,它与 StopWatch() 完全相同(但当然不会检索自系统直接启动以来的时间)。

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

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

遮了一弯 2024-10-17 21:21:17
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());
    }
}
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());
    }
}
栩栩如生 2024-10-17 21:21:17

您是正确的,Environment.TickCount 将在大约 25 天后溢出,因为返回值是 32 位整数。

但是,如果您想确定系统上次启动的时间,有比尝试比较 TickCount 更好的方法。您要寻找的称为系统正常运行时间。您可以通过多种不同的方式来检索此信息。

最简单的方法是使用 PerformanceCounter class(在System.Diagnostics命名空间中),它允许您查询特定的系统性能计数器。尝试以下代码:

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());

或者,您可以通过 WMI。但看起来 stian.net 的答案已经涵盖了这一点。

最后请注意,如果需要支持国际版本的 Windows,则必须本地化性能计数器的名称,因此正确的解决方案必须使用 PdhLookupPerfNameByIndex,或者您必须确保使用 PdhAddEnglishCounter 在幕后,仅在 Vista 或更高版本中受支持。有关此内容的更多信息,请此处

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.

一枫情书 2024-10-17 21:21:17

如果计算每个环绕,您可以创建自己的 64 位 TickCount,适用于 2^63 毫秒(2.92 亿年)或 2^64 毫秒(5.85 亿年)。如果不需要完整的 1ms 精度(实际上仅 10-16ms 分辨率)或范围,可以将结果除以 1000,并在 UInt32 中以一秒的分辨率表示最多 49,710 天(136 年)。

GetTickCount64() 会为您执行此操作,但仅在 Vista 或更高版本中可用。

这里我计算的是经过时间的循环,而不是 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 );
}

与 Int32.MaxValue 进行 AND 运算是不必要的,并且在 .NET 文档中是一个不好的示例。未经检查的 32 位整数减法会安全溢出。 Environment.TickCount 的符号并不重要。减法处理所有环绕的情况。例如,按 1 环绕: uiT0 = Int32.MaxValue; iTickNow = uiT0 + 1 产生 Int32.MinValue;最后,(iTickNow - uiT0) 产生 1。

uiElapsed 跟踪经过的时间一直到 49.7 天,然后才回零。每次换行时,iWrapCount 都会递增。 GetElapsedTime() 必须至少每 49.7 天调用一次,以便不会漏检任何回绕。

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.

⒈起吃苦の倖褔 2024-10-17 21:21:17

我认为这就是他们实施的方式。

它从 0 到最大值,然后从最小值到 0。

https://msdn.microsoft.com/en-us/library/system.environment.tickcount(v=vs.110).aspx

我已编辑了您正在使用的代码 < a href="http://www.codeproject.com/Articles/13384/Getting-the-user-idle-time-with-C" rel="nofollow">http://www.codeproject.com/Articles/ 13384/Getting-the-user-idle-time-with-C

为什么不直接获取绝对数字?

    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

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
浅听莫相离 2024-10-17 21:21:17

我不喜欢使用 GetTickCount() 用于获取时间戳,因为它可以返回负数。尽管使用 Abs() 可以有所帮助,但它很尴尬并且不是最佳解决方案。

最好在 .Net 中使用 StopwatchQueryPerformanceCounter 在 C++ 中作为时间戳。

在 C# 应用程序中,我创建一个全局 Stopwatch 对象并启动它。随后在应用程序中,我使用 Stopwatch.ElapsedMiliseconds 作为时间戳。

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...
            }
        }
    }
}

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...
            }
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文