非常简单,问题是如何使用c / c ++在Windows中启动系统启动时间。
搜索这个没有得到任何答案,我只找到了一个非常hacky的方法,即读取文件时间戳(不用说,我放弃了中途阅读)。
我发现的另一种方法实际上是读取Windows诊断记录的事件?据说最后一次启动时间。
有谁知道如何做到这一点(希望没有太多丑陋的黑客)?
答案 0 :(得分:18)
GetTickCount64
“检索自系统启动以来经过的毫秒数。”
一旦您知道系统运行了多长时间,只需从当前时间减去此持续时间即可确定系统何时启动。例如,使用C ++ 11 chrono库(Visual C ++ 2012支持):
auto uptime = std::chrono::milliseconds(GetTickCount64());
auto boot_time = std::chrono::system_clock::now() - uptime;
答案 1 :(得分:6)
您还可以使用WMI来获取准确的启动时间。 WMI不适合胆小的人,但它会让你得到你想要的东西。
相关信息位于LastBootUpTime
属性下的Win32_OperatingSystem
对象上。您可以使用WMI Tools检查其他属性。
修改强> 如果您愿意,也可以从命令行获取此信息。
wmic OS Get LastBootUpTime
作为C#中的示例,它看起来像以下(Using C++ it is rather verbose):
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();
}
答案 2 :(得分:1)
我还没有做太多的事情,但是我个人认为最好的方法可能是查询“系统”进程的开始时间。在Windows上,内核会出于自身目的在启动时分配一个进程(令人惊讶的是,尽管我确定信息已经存在,但快速的Google搜索并不能轻易揭示其实际用途。)此过程在任务管理器中简称为“系统”,在当前Windows版本上始终具有PID 4(显然NT 4和Windows 2000可能已使用PID 8)。只要系统正在运行,此过程就永远不会退出,就我的测试而言,就元数据而言,它的行为就像一个成熟的过程。根据我的测试,看起来即使是没有提升权限的用户也可以打开PID 4的句柄,请求PROCESS_QUERY_LIMITED_INFORMATION
,并且生成的句柄可以与GetProcessTimes
一起使用,它将填充{{1} },以及流程开始时间的UTC时间戳。据我所知,在系统进程运行之前,Windows的运行方式没有任何有意义的方式,因此此时间戳几乎完全是Windows启动时的时间。
lpCreationTime
当前启动的比较:
#include <iostream>
#include <iomanip>
#include <windows.h>
using namespace std;
int main()
{
unique_ptr<remove_pointer<HANDLE>::type, decltype(&::CloseHandle)> hProcess(
::OpenProcess(
PROCESS_QUERY_LIMITED_INFORMATION,
FALSE, // bInheritHandle
4), // dwProcessId
::CloseHandle);
FILETIME creationTimeStamp, exitTimeStamp, kernelTimeUsed, userTimeUsed;
FILETIME creationTimeStampLocal;
SYSTEMTIME creationTimeStampSystem;
if (::GetProcessTimes(hProcess.get(), &creationTimeStamp, &exitTimeStamp, &kernelTimeUsed, &userTimeUsed)
&& ::FileTimeToLocalFileTime(&creationTimeStamp, &creationTimeStampLocal)
&& ::FileTimeToSystemTime(&creationTimeStampLocal, &creationTimeStampSystem))
{
__int64 ticks =
((__int64)creationTimeStampLocal.dwHighDateTime) << 32 |
creationTimeStampLocal.dwLowDateTime;
wios saved(NULL);
saved.copyfmt(wcout);
wcout << setfill(L'0')
<< setw(4)
<< creationTimeStampSystem.wYear << L'-'
<< setw(2)
<< creationTimeStampSystem.wMonth << L'-'
<< creationTimeStampSystem.wDay
<< L' '
<< creationTimeStampSystem.wHour << L':'
<< creationTimeStampSystem.wMinute << L':'
<< creationTimeStampSystem.wSecond << L'.'
<< setw(7)
<< (ticks % 10000000)
<< endl;
wcout.copyfmt(saved);
}
}
:2020-07-18 17:36:41.3284297
2020-07-18 17:36:41.3209437
2020-07-18 17:36:41.3134106
2020-07-18 17:36:41.3225148
2020-07-18 17:36:41.3145312
(结果因呼叫而异,因为
system_clock::now() - milliseconds(GetTickCount64())
和system_clock::now()
的运行时间不完全相同,并且精度也不相同)
::GetTickCount64()
2020-07-18 17:36:41.512344
没有结果,因为事件日志条目目前在我的系统上不存在(最早的事件是从7月23日开始)
wmic OS Get LastBootUpTime
on PID 4:2020-07-18 17:36:48.0424863
与其他方法相差几秒钟,但我想不出它本身是错误的任何方式,因为如果系统进程尚未运行,则系统实际启动了吗??
答案 3 :(得分:0)
ABI中断:已更改Windows中的启动时间戳功能,以将EventLog服务启动时间用作系统启动时间。 WMI先前使用的
LastBootupTime
由于时间同步和休眠而不稳定,在实践中无法使用。如果您确实需要获得Boost 1.54之前的行为,请从命令行或detail / workaround.hpp中定义BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME
。
在第2201行附近检查boost / interprocess / detail / win32_api.hpp,以函数inline bool get_last_bootup_time(std::string &stamp)
的实现为例。 (如果您要匹配行号,我正在使用版本1.60。)
以防万一Boost死了,而我指的是Boost没有帮助(是的),您想要的功能主要是ReadEventLogA
和要查找的事件ID(“事件日志已开始“根据Boost的评论)显然是6005
。
答案 4 :(得分:0)
这不是一个单独的答案,但是我实现了其他三个答案,并且有一些观察结果可能对那些尝试选择方法的人有所帮助。
使用GetTickCount64
并从当前时间中减去
使用LastBootUpTime
的{{1}}字段的WMI查询
Win32_OperatingSystem
命令行花费202毫秒。wmic
字符串的形式产生一致的值阅读事件日志
这些方法还产生了不同的时间戳:
结论:事件日志方法与较早的Windows版本兼容,在Unix时间中产生一致的时间戳,不受睡眠/休眠周期的影响,但也是最慢的。鉴于这不太可能循环运行,因此它可能是最佳选择。