5

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

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;
}
4

6 回答 6

9

以下代码检索自系统启动以来的毫秒数(调用未管理的 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

于 2017-05-03T17:03:06.320 回答
8
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());
    }
}
于 2011-01-10T09:19:09.393 回答
6

你是对的,Environment.TickCount大约 25 天后会溢出,因为返回值是一个 32 位整数。

TickCount但是,如果您想确定系统上次启动的时间,则有比尝试比较更好的方法。您正在寻找的是系统正常运行时间。有几种不同的方法可以检索它。

最简单的方法是使用PerformanceCounter(在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 或更高版本中受支持。更多关于这里的信息。

于 2011-01-10T09:24:56.223 回答
0

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

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 进行与运算是不必要的,也是 .NET 文档中的一个坏例子。32 位整数的未经检查的减法安全溢出。Environment.TickCount 的符号无关紧要。减法处理所有环绕的情况。示例,环绕一:uiT0 = Int32.MaxValue; iTickNow = uiT0 + 1 产生 Int32.MinValue;最后,(iTickNow - uiT0) 产生 1。

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

于 2016-10-24T04:51:47.350 回答
-1

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

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

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

我已经从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
于 2015-05-17T23:38:23.663 回答
-1

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

最好使用.Net中的Stopwatch或 C++ 中的QueryPerformanceCounter作为时间戳。

在 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...
            }
        }
    }
}
于 2015-07-20T00:19:52.243 回答