Created
March 3, 2020 14:30
-
-
Save WebFreak001/904ca3c97f9d961661a2b2c2e90f52a5 to your computer and use it in GitHub Desktop.
Get windows startup boot time in D using Win32 Event Log APIs or GetTickCount64 fallback
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
SysTime getBootTime() | |
{ | |
SysTime ret = getBootTimeUsingEventLog(); | |
if (ret == SysTime.init) | |
ret = getBootTimeUsingTicks(); | |
return ret; | |
} | |
SysTime getBootTimeUsingTicks() | |
{ | |
return Clock.currTime - GetTickCount64().msecs; | |
} | |
// based off boost source code, so I guess this function is BSL licensed | |
SysTime getBootTimeUsingEventLog() | |
{ | |
const(char)* source_name = "System"; | |
const(char)* provider_name = "Microsoft-Windows-Winlogon"; | |
// winlogon | |
const ushort event_id = 7001u; | |
// The source name (provider) must exist as a subkey of Application. | |
void* hEventLog = OpenEventLogA(null, source_name); | |
if (!hEventLog) | |
return SysTime.init; | |
scope (exit) | |
CloseHandle(hEventLog); | |
scope ubyte[] heap = new ubyte[4096]; | |
while (true) | |
{ | |
DWORD dwBytesRead = 0; | |
DWORD dwMinimumBytesToRead = 0; | |
if (!ReadEventLogA(hEventLog, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_BACKWARDS_READ, 0, | |
&heap[0], cast(DWORD) heap.length, &dwBytesRead, &dwMinimumBytesToRead)) | |
{ | |
auto status = GetLastError(); | |
if (ERROR_INSUFFICIENT_BUFFER == status) | |
{ | |
if (dwMinimumBytesToRead > heap.length) | |
heap.length = dwMinimumBytesToRead; | |
} | |
else | |
{ | |
return SysTime.init; | |
} | |
} | |
else | |
{ | |
EVENTLOGRECORD* pTypedRecord; | |
// Print the contents of each record in the buffer. | |
if (find_record_in_buffer(heap, dwBytesRead, provider_name, event_id, pTypedRecord)) | |
{ | |
return SysTime.fromUnixTime(pTypedRecord.TimeGenerated); | |
} | |
} | |
} | |
} | |
bool find_record_in_buffer(ubyte[] pBuffer, DWORD dwBytesRead, | |
const(char)* provider_name, uint id_to_find, ref EVENTLOGRECORD* pevent_log_record) | |
{ | |
const(ubyte)* pRecord = cast(const(ubyte)*)(pBuffer); | |
const(ubyte)* pEndOfRecords = pRecord + dwBytesRead; | |
while (pRecord < pEndOfRecords) | |
{ | |
EVENTLOGRECORD* pTypedRecord = cast(EVENTLOGRECORD*) pRecord; | |
// Check provider, written at the end of the fixed-part of the record | |
if (0 == strcmp(provider_name, cast(char*)(pRecord + EVENTLOGRECORD.sizeof))) | |
{ | |
// Check event id | |
if (id_to_find == (pTypedRecord.EventID & 0xFFFF)) | |
{ | |
pevent_log_record = pTypedRecord; | |
return true; | |
} | |
} | |
pRecord += pTypedRecord.Length; | |
} | |
pevent_log_record = null; | |
return false; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment