C++ 以编程方式在c++;(窗口)

C++ 以编程方式在c++;(窗口),c++,c,windows,C++,C,Windows,因此,很简单,问题是如何在使用c/c++的windows中获得系统启动时间 搜索这个并没有给我任何答案,我只找到了一种非常粗糙的方法,即读取文件时间戳(不用说,我中途放弃了阅读) 我发现的另一种方法实际上是读取windows诊断记录的事件?应该是最后一次启动了 是否有人知道如何执行此操作(希望不会有太多丑陋的黑客)?“检索自系统启动以来经过的毫秒数。” 一旦知道系统已经运行了多长时间,只需从当前时间中减去该持续时间即可确定系统何时启动。例如,使用C++ 11的时间库(Visual C++ 201

因此,很简单,问题是如何在使用c/c++的windows中获得系统启动时间

搜索这个并没有给我任何答案,我只找到了一种非常粗糙的方法,即读取文件时间戳(不用说,我中途放弃了阅读)

我发现的另一种方法实际上是读取windows诊断记录的事件?应该是最后一次启动了

是否有人知道如何执行此操作(希望不会有太多丑陋的黑客)?

“检索自系统启动以来经过的毫秒数。”

一旦知道系统已经运行了多长时间,只需从当前时间中减去该持续时间即可确定系统何时启动。例如,使用C++ 11的时间库(Visual C++ 2012支持):

您还可以使用获取引导的精确时间。WMI不是为胆小的人准备的,但它会帮你找到你想要的东西

相关信息位于
LastBootUpTime
属性下的对象上。可以使用检查其他属性

编辑: 如果愿意,也可以从命令行获取此信息

wmic OS Get LastBootUpTime
作为C#中的一个示例,它将如下所示():

C++Boost

ABI中断:更改Windows中的bootstamp函数,以使用事件日志服务启动时间作为系统启动时间。以前从WMI使用的
LastBootupTime
,由于时间同步和休眠而不稳定,在实践中无法使用。如果您确实需要从命令行或detail/workaround.hpp获取Boost 1.54之前的行为,请定义
Boost\u进程间\u BOOTSTAMP\u是\u LASTBOOTUPTIME

查看boost/interprocess/detail/win32_api.hpp,第2201行附近的函数
inline bool get\u last\u bootup\u time(std::string&stamp)
的实现,例如。(如果您想匹配行号,我正在查看1.60版。)

万一Boost不知怎么死了,我给你指Boost也没用(没错),你需要的功能主要是
ReadEventLogA
,要查找的事件ID(“根据Boost注释,事件日志已启动”)显然是
6005

“系统”上的“系统启动时间”性能计数器对象是另一个源。它可以通过编程方式使用。但是,它对睡眠/休眠周期并不健壮,因此可能并不比
GetTickCount()
/
GetTickCount64()
好多少

读取计数器将返回一个64位
FILETIME
值,即自Windows纪元(1601-01-01 00:00:00 UTC)以来的100-NS刻度数。您还可以通过读取WMI表来查看计数器返回的值,该表公开了用于计算该值的原始值。(使用COM以编程方式读取,或从wmic获取命令行:)

该查询为我生成132558992761256000

您可以使用等效的
performatteddata
获取浮点秒数,或从
wmic
中的命令行读取该秒数,或在PowerShell中查询计数器:

Get-Counter -Counter '\system\system up time'
这将返回427.0152秒的正常运行时间

我还实现了其他3个答案中的每一个,并且有一些观察结果可以帮助那些试图选择方法的人

使用
GetTickCount64
并从当前时间中减去

  • 最快的方法,以0.112毫秒计时
  • 不以其参数的100 ns分辨率生成唯一/一致的值,因为它依赖于时钟信号。返回值之间的间隔都在1/64秒之内
  • 需要Vista或更高版本。如果您的应用程序/库必须支持较旧的Windows版本,XP的32位计数器将在49天内滚动,并且不能用于此方法
使用WMI查询
Win32\u操作系统的
LastBootUpTime
字段

  • 使用COM时为84毫秒,使用wmic时为202ms
  • 将一致的值生成为
    CIM_DATETIME
    字符串
  • WMI类需要Vista或更高版本
读取事件日志

  • 最慢的方法,需要229毫秒
  • 以秒为单位生成一致的值(Unix时间)
  • 适用于Windows 2000或更新版本
  • 正如评论中所指出的,不保证会产生结果
这些方法还产生了不同的时间戳:

  • 正常运行时间:1558758098843=2019-05-25 04:21:38 UTC(有时:37)
  • WMI:20190524222528.665400-420=2019-05-25 05:25:28 UTC
  • 事件日志:1558693023=2019-05-24 10:17:03 UTC
结论:


事件日志方法与较早的Windows版本兼容,在unix时间内生成一致的时间戳,该时间戳不受睡眠/休眠周期的影响,但也是最慢的。考虑到这不太可能在循环中运行,这可能是一个可接受的性能影响。但是,使用这种方法仍然需要处理事件日志达到容量并删除旧消息的情况,可能会使用其他选项之一作为备份。

我没有玩过这么多,但我个人认为最好的方法可能是查询“系统”进程的开始时间。在Windows上,内核在启动时为自己的目的分配一个进程(令人惊讶的是,一个快速的Google搜索并不容易发现它的实际目的,尽管我确信信息就在那里)。这个过程在任务管理器中被简单地称为“系统”,并且在当前的Windows版本中总是有PID 4(显然NT 4和Windows 2000可能使用PID 8)。只要系统在运行,这个进程就永远不会退出,在我的测试中,就metadat而言,它的行为就像一个成熟的进程
static void Main(string[] args)
{      
    // Create a query for OS objects
    SelectQuery query = new SelectQuery("Win32_OperatingSystem", "Status=\"OK\"");

    // Initialize an object searcher with this query
    ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);

    string dtString;
    // Get the resulting collection and loop through it
    foreach (ManagementObject envVar in searcher.Get())
        dtString = envVar["LastBootUpTime"].ToString();
}
wmic path Win32_PerfRawData_PerfOS_System  get systemuptime
Get-Counter -Counter '\system\system up time'