1

I need to get the time of the latest system boot. I'm using the following boost function:

#include <boost/interprocess/detail/win32_api.hpp>

std::string SystemLastBootTime = "";
if (boost::interprocess::winapi::get_last_bootup_time(SystemLastBootTime)) {
    MessageBox(NULL, SystemLastBootTime.c_str(), "Last Boot Time", MB_OK | MB_ICONEXCLAMATION);
}

The output of SystemLastBootTime is:

AA000000_0E030000

What's exactly in this string, and how to convert it to a "normal" unix time, so I can compare and see if the system booted during the last 5 minutes or later?

Mona
  • 337
  • 3
  • 15
  • You're probably looking for [GetTickCount64](https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-gettickcount64). – IInspectable Sep 18 '21 at 22:49
  • @IInspectable No, I need to know the time when system started (reboot, power-on after the shutdown, etc). GetTickCount64 would get the current time. – Mona Sep 18 '21 at 22:59
  • Oh, I think i know what you mean. However, the GetTickCount64() is not "reset" after normal shutdown (only the full reboot). So I would still need to get the last bootup time to substract it from the GetTickCount time. – Mona Sep 18 '21 at 23:08

1 Answers1

1

The implementation is right there. There's actually different implementations:

  • when BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED is defined
  • when BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED is defined

From Session Manager

inline bool get_last_bootup_time(std::string &stamp)
{
   unsigned dword_val = 0;
   std::size_t dword_size = sizeof(dword_val);
   bool b_ret = get_registry_value_buffer( hkey_local_machine
      , "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management\\PrefetchParameters"
      , "BootId", &dword_val, dword_size);
   if (b_ret)
   {
      char dword_str[sizeof(dword_val)*2u+1];
      buffer_to_narrow_str(&dword_val, dword_size, dword_str);
      dword_str[sizeof(dword_val)*2] = '\0';
      stamp = dword_str;

      b_ret = get_registry_value_buffer( hkey_local_machine
         , "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Power"
         , "HybridBootAnimationTime", &dword_val, dword_size);
      //Old Windows versions have no HybridBootAnimationTime
      if(b_ret)
      {
         buffer_to_narrow_str(&dword_val, dword_size, dword_str);
         dword_str[sizeof(dword_val)*2] = '\0';
         stamp += "_";
         stamp += dword_str;
      }
      b_ret = true;
   }
   return b_ret;
}

From Event Log

This is even grittier, and way more code since apparently they chose not to use an existing library. They end up looking for event ID 6005, and then reading the

unsigned long  TimeGenerated; // Seconds since 1-1-1970

from that record.

Summarizing

As you can see the whole thing is proprietary, and you might just want to implement it yourself without (ab)using implementation details from Boost Interprocess.

The "good news" is that you might be able to get some documentation from Microsoft about either the Session Manager registry key, or System event 6005.

Oh, and don't forget that defining BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED could we result in a readable timestamp to begin with, since it just formats the UNIX timestamp with %u to the output.

sehe
  • 374,641
  • 47
  • 450
  • 633
  • Avoid UNIX timestamps whenever possible. Windows' [FILETIME](https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime) timestamps have both higher resolution and continue to work [well beyond](https://stackoverflow.com/a/18188484/1889329) the year 2038. – IInspectable Sep 21 '21 at 09:27
  • @IInspectable Who is that directed at? It seems a pet peeve at best here. For one, OP doesn't control what is stored in the windows event log. Neither is sub-microsecond accuracy relevant to (checks notes) time of boot. – sehe Sep 21 '21 at 14:43
  • That comment was directed at the remark that suggested to use UNIX timestamps for convenience. There is no convenience gained in implementing (or recommending to implement) a solution that will break in the foreseeable future. Resolution may not be important, but correctness always is. – IInspectable Sep 22 '21 at 09:00
  • @IInspectable Good thing I didn't do that, then! Nobody "suggested" anything, certainly not "for convenience". If anything, the gist of my answer is that _all of the approaches here are prone to break_ — doubly so if (ab)used from implementation details of an unrelated library. The quest for a UNIX timestamp is actually in the question title, so did you mean to post your comment at the question? I merely analyzed the **existing** implementation of the functions the question refers to. Don't shoot the messenger? – sehe Sep 22 '21 at 10:17
  • Thank you for your answer. The boost implementation seem to be very confusing. First of all the "HybridBootAnimationTime" doesn't exist on all Windows 10 installations that I tested (possibly when the fast startup is disabled). On installations with "HybridBootAnimationTime" existing this DWORD has nonsense values (always a relatively small number), totally mismatching with what the EVENTLOG_BASED would return. I think as noted in your answer, it will be better to search for a different method. – Mona Sep 30 '21 at 14:43
  • I strongly agree. Strive for a "not reinventing the wheel". I can only imagine that Boost Interprocess has this arcane implementation as a crutch to approximate robust mutexes so persistent shared memory can "heal" after a reboot. But this is pure guesswork. In general it's aVery Bad Idea to rely on the implementation details of a library. They're hidden for a reason. And unless the behavior is explicitly documented, you shouldn't expect it to work in the first place. – sehe Sep 30 '21 at 20:16