如何使用 C++(win32/MFC) 跟踪准确的 windows 启动时间
How to track the accurate windows startup time using C++(win32/MFC)
我正在创建一个跟踪系统启动时间的应用程序。
我尝试了 GetTickcount() 方法和 WMI query.In 这两种情况我得到了相同的解决方案。
但是我得到的时间和实际启动时间是不一样的。
通过研究,我发现由于在电源选项中启用了快速启动选项,当我们关闭系统时,系统不会启动。
我需要的是实际启动时间 time.How 我们可以使用 C++ 获取实际启动时间吗?
我关闭了系统并在 20 年 6 月 24 日 8:22:05 上午打开它,但我得到的启动时间是 5:11:05 下午 5:11:05 下午
启用快速启动选项后,单击开始菜单-> 关机将使机器进入睡眠状态mode/hibernation,而不是关机。但重启菜单不受影响。 (并且从命令行关闭也不会像我的测试那样受到影响)。所以,开机时间不会被重置。
您可以尝试以下方法:
- 关闭“快速启动”选项。
- 在任务计划中添加一个任务来记录系统启动的时间。
- 阅读 Windows 事件日志:
事件 ID 27 记录内核启动事件。正如您在图片中看到的,启动类型 0x1
表示这是一个快速启动。您可以阅读最新的并获得创建时间。
示例(参考本示例文档:Querying for Events):
#include <windows.h>
#include <sddl.h>
#include <stdio.h>
#include <winevt.h>
#pragma comment(lib, "wevtapi.lib")
#define ARRAY_SIZE 1
#define TIMEOUT 1000 // 1 second; Set and use in place of INFINITE in EvtNext call
DWORD PrintResults(EVT_HANDLE hResults);
DWORD PrintEvent(EVT_HANDLE hEvent); // Shown in the Rendering Events topic
void main(void)
{
DWORD status = ERROR_SUCCESS;
EVT_HANDLE hResults = NULL;
LPCWSTR pwsPath = L"System";
LPCWSTR pwsQuery = L"Event/System[EventID=27]";
hResults = EvtQuery(NULL, pwsPath, pwsQuery, EvtQueryChannelPath | EvtQueryReverseDirection);
if (NULL == hResults)
{
status = GetLastError();
if (ERROR_EVT_CHANNEL_NOT_FOUND == status)
wprintf(L"The channel was not found.\n");
else if (ERROR_EVT_INVALID_QUERY == status)
// You can call the EvtGetExtendedStatus function to try to get
// additional information as to what is wrong with the query.
wprintf(L"The query is not valid.\n");
else
wprintf(L"EvtQuery failed with %lu.\n", status);
goto cleanup;
}
PrintResults(hResults);
cleanup:
if (hResults)
EvtClose(hResults);
}
// Enumerate all the events in the result set.
DWORD PrintResults(EVT_HANDLE hResults)
{
DWORD status = ERROR_SUCCESS;
EVT_HANDLE hEvents[ARRAY_SIZE];
DWORD dwReturned = 0;
// Get a block of events from the result set.
if (!EvtNext(hResults, ARRAY_SIZE, hEvents, INFINITE, 0, &dwReturned))
{
if (ERROR_NO_MORE_ITEMS != (status = GetLastError()))
{
wprintf(L"EvtNext failed with %lu\n", status);
}
goto cleanup;
}
// For each event, call the PrintEvent function which renders the
// event for display. PrintEvent is shown in RenderingEvents.
/*for (DWORD i = 0; i < dwReturned; i++)
{
if (ERROR_SUCCESS == (status = PrintEvent(hEvents[i])))
{
EvtClose(hEvents[i]);
hEvents[i] = NULL;
}
else
{
goto cleanup;
}
}*/
if (ERROR_SUCCESS == (status = PrintEvent(hEvents[0])))
{
EvtClose(hEvents[0]);
hEvents[0] = NULL;
}
else
{
goto cleanup;
}
cleanup:
for (DWORD i = 0; i < dwReturned; i++)
{
if (NULL != hEvents[i])
EvtClose(hEvents[i]);
}
return status;
}
DWORD PrintEvent(EVT_HANDLE hEvent)
{
DWORD status = ERROR_SUCCESS;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD dwPropertyCount = 0;
LPWSTR pRenderedContent = NULL;
if (!EvtRender(NULL, hEvent, EvtRenderEventXml, dwBufferSize, pRenderedContent, &dwBufferUsed, &dwPropertyCount))
{
if (ERROR_INSUFFICIENT_BUFFER == (status = GetLastError()))
{
dwBufferSize = dwBufferUsed;
pRenderedContent = (LPWSTR)malloc(dwBufferSize);
if (pRenderedContent)
{
EvtRender(NULL, hEvent, EvtRenderEventXml, dwBufferSize, pRenderedContent, &dwBufferUsed, &dwPropertyCount);
}
else
{
wprintf(L"malloc failed\n");
status = ERROR_OUTOFMEMORY;
goto cleanup;
}
}
if (ERROR_SUCCESS != (status = GetLastError()))
{
wprintf(L"EvtRender failed with %d\n", status);
goto cleanup;
}
}
wprintf(L"%s\n\n", pRenderedContent);
cleanup:
if (pRenderedContent)
free(pRenderedContent);
return status;
}
结果:
我正在创建一个跟踪系统启动时间的应用程序。
我尝试了 GetTickcount() 方法和 WMI query.In 这两种情况我得到了相同的解决方案。
但是我得到的时间和实际启动时间是不一样的。
通过研究,我发现由于在电源选项中启用了快速启动选项,当我们关闭系统时,系统不会启动。
我需要的是实际启动时间 time.How 我们可以使用 C++ 获取实际启动时间吗?
我关闭了系统并在 20 年 6 月 24 日 8:22:05 上午打开它,但我得到的启动时间是 5:11:05 下午 5:11:05 下午
启用快速启动选项后,单击开始菜单-> 关机将使机器进入睡眠状态mode/hibernation,而不是关机。但重启菜单不受影响。 (并且从命令行关闭也不会像我的测试那样受到影响)。所以,开机时间不会被重置。
您可以尝试以下方法:
- 关闭“快速启动”选项。
- 在任务计划中添加一个任务来记录系统启动的时间。
- 阅读 Windows 事件日志:
事件 ID 27 记录内核启动事件。正如您在图片中看到的,启动类型 0x1
表示这是一个快速启动。您可以阅读最新的并获得创建时间。
示例(参考本示例文档:Querying for Events):
#include <windows.h>
#include <sddl.h>
#include <stdio.h>
#include <winevt.h>
#pragma comment(lib, "wevtapi.lib")
#define ARRAY_SIZE 1
#define TIMEOUT 1000 // 1 second; Set and use in place of INFINITE in EvtNext call
DWORD PrintResults(EVT_HANDLE hResults);
DWORD PrintEvent(EVT_HANDLE hEvent); // Shown in the Rendering Events topic
void main(void)
{
DWORD status = ERROR_SUCCESS;
EVT_HANDLE hResults = NULL;
LPCWSTR pwsPath = L"System";
LPCWSTR pwsQuery = L"Event/System[EventID=27]";
hResults = EvtQuery(NULL, pwsPath, pwsQuery, EvtQueryChannelPath | EvtQueryReverseDirection);
if (NULL == hResults)
{
status = GetLastError();
if (ERROR_EVT_CHANNEL_NOT_FOUND == status)
wprintf(L"The channel was not found.\n");
else if (ERROR_EVT_INVALID_QUERY == status)
// You can call the EvtGetExtendedStatus function to try to get
// additional information as to what is wrong with the query.
wprintf(L"The query is not valid.\n");
else
wprintf(L"EvtQuery failed with %lu.\n", status);
goto cleanup;
}
PrintResults(hResults);
cleanup:
if (hResults)
EvtClose(hResults);
}
// Enumerate all the events in the result set.
DWORD PrintResults(EVT_HANDLE hResults)
{
DWORD status = ERROR_SUCCESS;
EVT_HANDLE hEvents[ARRAY_SIZE];
DWORD dwReturned = 0;
// Get a block of events from the result set.
if (!EvtNext(hResults, ARRAY_SIZE, hEvents, INFINITE, 0, &dwReturned))
{
if (ERROR_NO_MORE_ITEMS != (status = GetLastError()))
{
wprintf(L"EvtNext failed with %lu\n", status);
}
goto cleanup;
}
// For each event, call the PrintEvent function which renders the
// event for display. PrintEvent is shown in RenderingEvents.
/*for (DWORD i = 0; i < dwReturned; i++)
{
if (ERROR_SUCCESS == (status = PrintEvent(hEvents[i])))
{
EvtClose(hEvents[i]);
hEvents[i] = NULL;
}
else
{
goto cleanup;
}
}*/
if (ERROR_SUCCESS == (status = PrintEvent(hEvents[0])))
{
EvtClose(hEvents[0]);
hEvents[0] = NULL;
}
else
{
goto cleanup;
}
cleanup:
for (DWORD i = 0; i < dwReturned; i++)
{
if (NULL != hEvents[i])
EvtClose(hEvents[i]);
}
return status;
}
DWORD PrintEvent(EVT_HANDLE hEvent)
{
DWORD status = ERROR_SUCCESS;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD dwPropertyCount = 0;
LPWSTR pRenderedContent = NULL;
if (!EvtRender(NULL, hEvent, EvtRenderEventXml, dwBufferSize, pRenderedContent, &dwBufferUsed, &dwPropertyCount))
{
if (ERROR_INSUFFICIENT_BUFFER == (status = GetLastError()))
{
dwBufferSize = dwBufferUsed;
pRenderedContent = (LPWSTR)malloc(dwBufferSize);
if (pRenderedContent)
{
EvtRender(NULL, hEvent, EvtRenderEventXml, dwBufferSize, pRenderedContent, &dwBufferUsed, &dwPropertyCount);
}
else
{
wprintf(L"malloc failed\n");
status = ERROR_OUTOFMEMORY;
goto cleanup;
}
}
if (ERROR_SUCCESS != (status = GetLastError()))
{
wprintf(L"EvtRender failed with %d\n", status);
goto cleanup;
}
}
wprintf(L"%s\n\n", pRenderedContent);
cleanup:
if (pRenderedContent)
free(pRenderedContent);
return status;
}
结果: