C# Environment.TickCount不够

C# Environment.TickCount不够,c#,.net,c#-4.0,environment-variables,gettickcount,C#,.net,C# 4.0,Environment Variables,Gettickcount,我想知道上次启动系统是什么时候 Environment.TickCount将起作用,但由于int的限制,它在48-49天后会中断 这是我一直在使用的代码: Environment.TickCount & Int32.MaxValue 有人知道长型返回吗 我用它来了解系统的空闲时间: public static int GetIdleTime() { return (Environment.TickCount & Int32.MaxValue)- (int)GetLast

我想知道上次启动系统是什么时候

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;
}
publicstatic int GetIdleTime()
{
返回(Environment.TickCount&Int32.MaxValue)-(int)GetLastInputTime();
}
/// 
///从输入设备获取上次输入时间。
///例外情况:
///如果无法获取最后的输入信息,则抛出异常
///适当的信息。
/// 
///上次输入时间(毫秒)。
公共静态uint GetLastInputTime()
{
LastInputInfo lastInPut=新的LastInputInfo();
lastInPut.BlockSize=(uint)System.Runtime.InteropServices.Marshal.SizeOf(lastInPut);
如果(!GetLastInputInfo(参考lastInPut))
{
抛出新异常(GetLastError().ToString());
}
返回lastInPut.Time;
}

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

但是,如果要确定系统上次启动的时间,有一种比尝试比较滴答数更好的方法。您需要的是系统启动时间。有两种不同的方法可以检索这个

最简单的方法是使用(在
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());
或者,您可以通过。但看起来这已经涵盖了


最后,请注意,如果您需要支持Windows的国际版本,则必须本地化性能计数器的名称,因此正确的解决方案必须使用查找本地化字符串“System”和“System up Time”,或者您必须确保使用的是仅在Vista或更高版本中支持的under-the-hood。更多信息。

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

它从0变为最大值,然后从最小值变为0

我已编辑了您从中使用的代码

你为什么不直接得到绝对数呢

    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
我不喜欢使用时间戳,因为它可以返回负数。尽管使用Abs()可能会有所帮助,但这很尴尬,而且不是最佳解决方案

<> >在.NET或C++中作为时间戳更好。

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...
            }
        }
    }
}
在C#应用程序中,我创建了一个全局秒表对象,然后启动它。稍后在应用程序中,我使用Stopwatch.elapsediliseconds作为时间戳

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

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

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

在这里,我计算过去的时间,而不是滴答数

// 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 );
}
/C#(未测试)
...
//初始化和启动计时器:
uint uiT0=未选中((uint)Environment.TickCount);//T0现在是开机后毫秒,10-16ms分辨率。
uint uiElapsedPrev=0;
uint uiWrapCount=0;
...
长x=GetElapsedTime();
公共静态长GetElapsedTime()
{
uint uiappeased=unchecked((uint)Environment.TickCount-uiT0)//0到+49.71天
if(uielappeadreturn(((long)uiWrapCount以下代码检索自系统启动(调用unmanged API)以来的毫秒数。我测量了互操作操作的性能成本,它与StopWatch()完全相同(当然,这不会直接检索自系统启动以来的时间)


您需要参阅System.Managements让我在这里重新调整相位…是否有任何方法可以获得总空闲时间,至少以长刻度(毫秒)为单位。这个空闲时间意味着系统启动-收到的最后一个输入。有了上面的内容,我可以很长时间获得系统启动时间,但是收到的最后一个输入是按uint计算的,所以48天后它将崩溃。是的,这就是我使用的:internal struct LASTINPUTINFO{public uint cbSize;public uint dwTime;}您可以看到dwTime为uint。请确保您已处理ManagementObjectSearcher实例。WMI可以在计算机上禁用,并且此代码将不起作用。确定后,您可以编写Console.WriteLine(DateTime.Now-upTime);并获取正确的日期:)但我仍然会使用WMI。在我的系统上,PerformanceCounter使用2秒来显示启动时间。WMI使用40秒ms@stian:很公平。
PerformanceCounter
可能是“官方”NET的方式,在我看来,这似乎不太可能是值得优化的东西,因为它不会在循环中调用。但我同意WMI可能是更好的选择,我甚至在回答中建议使用它。最初我发现,考虑到Windows的这一部分的用途,使用性能计数器会很慢,这让我相当惊讶。Howev呃,在我的计算机上,调用
新性能计数器
加载的DLL不少于80个!这需要相当长的时间,但这是一次性的成本,在这之后,性能计数器似乎表现得非常好。@Martin:测试这一点做得很好。我也在想同样的事情。这确实是一个令人难以置信的数字就像这样一个简单的任务。在命令提示符下从运行
net statistics workstation
检索信息不会花那么长时间。谢谢大家…问题是GetLastInputTime(…)仍然返回整数。我可以用什么方法来确定时间
using System.Runtime.InteropServices;
[DllImport("kernel32.dll") ]
public static extern UInt64 GetTickCount64();
var tickCount64 = GetTickCount64();