Skip to content

Instantly share code, notes, and snippets.

@WebFreak001
Created March 3, 2020 14:30
Show Gist options
  • Save WebFreak001/904ca3c97f9d961661a2b2c2e90f52a5 to your computer and use it in GitHub Desktop.
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
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