Last Boot Time in Registry or API?

I want to find out the last time the system booted. I’m not particular on
the time exactly. I just want to get some approximate time that the
operating system had just been started, or even, perhaps, the last time it
was shut down, or as a last resort, the amount of time that it’s been up.

I just want some reference to a time period before any drivers or services
could have started. (The reason for this is so that I can rename my log
files, which were created during the previous boot, to something with a
meaningful timestamp – however, I want all of my drivers and services to
agree on this name, so just getting the current time does not cut it.)

I expected that I’d find it in the Registry or through some API, but I was
unable to find it.

(And yes, I know that I could parse the Event Log, but that’s far more
trouble than it’s worth.)

Any ideas? I’m sure it must exist!

Thanks!


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

DWORD GetTickCount(VOID);

From the MSDN.
“The return value is the number of milliseconds that have elapsed since the
system was started”

Rob Linegar
Software Engineer
Data Encryption Systems Limited

-----Original Message-----
From: Taed Nelson [mailto:xxxxx@vertical.com]
Sent: 06 April 2001 16:48
To: NT Developers Interest List
Subject: [ntdev] Last Boot Time in Registry or API?

I want to find out the last time the system booted. I’m not particular on
the time exactly. I just want to get some approximate time that the
operating system had just been started, or even, perhaps, the last time it
was shut down, or as a last resort, the amount of time that it’s been up.

I just want some reference to a time period before any drivers or services
could have started. (The reason for this is so that I can rename my log
files, which were created during the previous boot, to something with a
meaningful timestamp – however, I want all of my drivers and services to
agree on this name, so just getting the current time does not cut it.)

I expected that I’d find it in the Registry or through some API, but I was
unable to find it.

(And yes, I know that I could parse the Event Log, but that’s far more
trouble than it’s worth.)

Any ideas? I’m sure it must exist!

Thanks!


You are currently subscribed to ntdev as: xxxxx@des.co.uk
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

Taed,

Rob’s answer answer does not really tell you a way to figure a boot time
that is consistent from any driver. Using GetTicCount() and rounding your
computation to the nearest minute would help, but you might still get things
that were off by a minute if you were near the rounding cutoff.

You could couple something like GetTickCount() with some shared memory and
synchronization. A simple way would be to have each driver to try to create
a named event (manual reset). The first driver to do so (i.e., if the event
did not already exist) would then create a shared memory region, set the
start time in the shared memory based on the current time minus the system
uptime, and signal the event. If the event already existed, the driver
would just wait on it. Then it would open the shared memory and check the
time value.

[Note: there are some degenerate cases where this would not work – most
notably if driver1 starts then stops and then driver2 starts then stops –
you will likely get different times in such a case.]

You should also be aware that GetTickCount() is only valid if the system has
been up for less than about 47 days. If the drivers could be started after
47 days of system uptime, GetTickCount() would not be appropriate. For more
than 47 days, you can use performance counters.

Below is some test performance counter code to get you started. It has been
tested on Windows 2000. Note that there is a difference between the awake
time and the elapsed time of the system/idle processed if the system is
hibernated. That’s why I output both. The process uptimes were just for
more research. You can just remove that.

In general, however, the event log is the only way I know to get a
consistent system start time w/o creating your own canonical start time
source.

Enjoy,

  • Danilo

P.S.: You’ll need to link with psapi.lib and pdh.lib


#define WIN32_LEAN_AND_MEAN 1

#include <windows.h>
#include <winperf.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include <pdh.h>
#include <psapi.h>

void
print_time(
char* prefix,
__int64 t
)
{
__int64 secs = t % 60;
t /= 60;
int64 mins = t % 60;
t /= 60;
int64 hours = t % 24;
t /= 24;
__int64 days = t;

printf(“%s”
“%3I64d days, %2I64d hours, %2I64d minutes, %2I64d seconds\n”,
prefix,
days, hours, mins, secs);
}

PDH_STATUS
get_number_cv(
char* counter,
DWORD pdwType,
PDH_FMT_COUNTERVALUE pcv
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
HQUERY hQuery = 0;
HCOUNTER hCounter = 0;

pdhStatus = PdhOpenQuery(0, 0, &hQuery);
if (pdhStatus != ERROR_SUCCESS)
{
fprintf(stderr, “Error while opening query\n”);
goto cleanup;
}

pdhStatus = PdhAddCounter(hQuery, counter, 0, &hCounter);
if (pdhStatus)
{
fprintf(stderr, “Error while adding counter %s to query\n”,
counter);
goto cleanup;
}

pdhStatus = PdhCollectQueryData(hQuery);
if (pdhStatus)
{
fprintf(stderr, “Error collecting query data\n”);
goto cleanup;
}
pdhStatus = PdhGetFormattedCounterValue(hCounter,
PDH_FMT_LARGE | PDH_FMT_NOSCALE,
pdwType, pcv);
if (pdhStatus)
{
fprintf(stderr, “Error formatting counter value\n”);
goto cleanup;
}

// We can close the query since we do not need to refer to any of the
// string members.

cleanup:
if (hQuery)
PdhCloseQuery(hQuery);
return pdhStatus;
}

PDH_STATUS
get_and_print_time_cv(
char
prefix,
char
path
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
DWORD dwType = 0;
PDH_FMT_COUNTERVALUE cv;

pdhStatus = get_number_cv(path, &dwType, &cv);
if (pdhStatus)
return pdhStatus;

//printf(“Type: 0x%08x, Value: 0x%016I64x\n”, dwType, cv.largeValue);
print_time(prefix, cv.largeValue);
return 0;
}

__int64
filetime_to_seconds(
FILETIME ft
)
{
return ((__int64)&ft) / ( 1000 * 1000 * 1000 / 100 );
}

void
do_processes()
{
int i;
DWORD cb = 0;
BOOL ok = TRUE;
DWORD chunk = 5 * sizeof(DWORD);
DWORD size = chunk;
DWORD* ap = (DWORD*) malloc(size);

while ((ok = EnumProcesses(ap, size, &cb)) &&
(size < (sizeof(DWORD) + cb)))
{
cb = 0;
free(ap);
size += chunk;
ap = (DWORD*)malloc(size);
}
if (!ok)
{
printf(“Error enumerating processes (%u)\n”, GetLastError());
goto cleanup;
}

for (i = 0; i < (cb / sizeof(DWORD)); i++)
{
DWORD p = ap[i];

char label[64];
_snprintf(label, sizeof(label) - 1, “Up Time (%6u): “, p);

HANDLE hp = OpenProcess(STANDARD_RIGHTS_READ |
PROCESS_QUERY_INFORMATION,
FALSE, p);
if (!hp || (hp == INVALID_HANDLE_VALUE))
{
printf(”%s could not open process (error %u)\n”,
label, GetLastError());
continue;
}

fflush(stdout);

FILETIME ft;
FILETIME ft1;
FILETIME ft2;
FILETIME ft3;

if (GetProcessTimes(hp, &ft, &ft1, &ft2, &ft2))
{
FILETIME sft;
GetSystemTimeAsFileTime(&sft);
__int64 st = filetime_to_seconds(sft);
__int64 pt = filetime_to_seconds(ft);
if (pt)
{
print_time(label, st - pt);
}
else
{
printf(“%s no creation time\n”, label);
}
}
else
{
printf(“%s could not get times (error %u)\n”,
label, GetLastError());
}
}
cleanup:
if (ap)
free(ap);
}

void
usage(
char* progname
)
{
printf(“usage: %s [-p]\n”
" -p show process times\n",
progname);
exit(1);
}

int
main(
int argc,
char* argv
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
BOOL bProc = FALSE;

if (argc > 2)
usage(argv[0]);

if (argc > 1)
{
if (!strcmp(argv[1], “-p”))
{
bProc = TRUE;
}
else
{
usage(argv[0]);
}
}

pdhStatus = get_and_print_time_cv(" Awake Time: ",
“\System\System Up Time”);
if (pdhStatus)
exit(1);

pdhStatus = get_and_print_time_cv("Elapsed Time: ",
“\Process(System)\Elapsed Time”);
if (pdhStatus)
exit(1);

pdhStatus = get_and_print_time_cv("Elapsed Time: ",
“\Process(Idle)\Elapsed Time”);
if (pdhStatus)
exit(1);

if (bProc)
do_processes();

return 0;
}

> -----Original Message-----
> From: xxxxx@lists.osr.com
> [mailto:xxxxx@lists.osr.com]On Behalf Of xxxxx@des.co.uk
> Sent: Friday, April 06, 2001 12:01 PM
> To: NT Developers Interest List
> Subject: [ntdev] RE: Last Boot Time in Registry or API?
>
>
>
> DWORD GetTickCount(VOID);
>
> From the MSDN.
> “The return value is the number of milliseconds that have elapsed
> since the
> system was started”
>
> Rob Linegar
> Software Engineer
> Data Encryption Systems Limited
>
> -----Original Message-----
> From: Taed Nelson [mailto:xxxxx@vertical.com]
> Sent: 06 April 2001 16:48
> To: NT Developers Interest List
> Subject: [ntdev] Last Boot Time in Registry or API?
>
>
> I want to find out the last time the system booted. I’m not particular
> on the time exactly. I just want to get some approximate time that the
> operating system had just been started, or even, perhaps, the last time
> it was shut down, or as a last resort, the amount of time that it’s been >
up.
>
> I just want some reference to a time period before any drivers or
> services could have started. (The reason for this is so that I can
> rename my log files, which were created during the previous boot, to
> something with a meaningful timestamp – however, I want all of my
> drivers and services to agree on this name, so just getting the current
> time does not cut it.)
>
> I expected that I’d find it in the Registry or through some API, but I
> was unable to find it.
>
> (And yes, I know that I could parse the Event Log, but that’s far more
> trouble than it’s worth.)
>
> Any ideas? I’m sure it must exist!
>
> Thanks!


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com</psapi.h></pdh.h></tchar.h></stdlib.h></stdio.h></malloc.h></winperf.h></windows.h>

Hi ,

Check the following keys. Value type is Binary :

  1. HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Windows\ShutdownTime
  2. HKEY_LOCAL_MACHINE\SYSTEM\ControlSet002\Control\Windows\ShutdownTime

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Windows\ShutdownTime

Hope this helps,

Regards,
Satish K.S

----- Original Message -----
From: “Taed Nelson”
To: “NT Developers Interest List”
Sent: Friday, April 06, 2001 9:18 PM
Subject: [ntdev] Last Boot Time in Registry or API?

> I want to find out the last time the system booted. I’m not particular on
> the time exactly. I just want to get some approximate time that the
> operating system had just been started, or even, perhaps, the last time it
> was shut down, or as a last resort, the amount of time that it’s been up.
>
> I just want some reference to a time period before any drivers or services
> could have started. (The reason for this is so that I can rename my log
> files, which were created during the previous boot, to something with a
> meaningful timestamp – however, I want all of my drivers and services to
> agree on this name, so just getting the current time does not cut it.)
>
> I expected that I’d find it in the Registry or through some API, but I was
> unable to find it.
>
> (And yes, I know that I could parse the Event Log, but that’s far more
> trouble than it’s worth.)
>
> Any ideas? I’m sure it must exist!
>
> Thanks!
>
>
> —
> You are currently subscribed to ntdev as: xxxxx@aalayance.com
> To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

Hi:

At any time in your driver, get current time and subtract from it
GetTickCount()
properly scaled. Then store it in the registry. Next time you boot, it will
be there
for you… Use it or save it before you replace it with the new value.

George

At 08:48 AM 4/6/01 -0700, you wrote:

I want to find out the last time the system booted. I’m not particular on
the time exactly. I just want to get some approximate time that the
operating system had just been started, or even, perhaps, the last time it
was shut down, or as a last resort, the amount of time that it’s been up.

I just want some reference to a time period before any drivers or services
could have started. (The reason for this is so that I can rename my log
files, which were created during the previous boot, to something with a
meaningful timestamp – however, I want all of my drivers and services to
agree on this name, so just getting the current time does not cut it.)

I expected that I’d find it in the Registry or through some API, but I was
unable to find it.

(And yes, I know that I could parse the Event Log, but that’s far more
trouble than it’s worth.)

Any ideas? I’m sure it must exist!

Thanks!


You are currently subscribed to ntdev as: xxxxx@ntrealtime.com
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

> HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Windows\ShutdownTime

Thanks! That is PERFECT!

I did some quick testing, and it even seems to handle the case where I just
shut off the machine without warning. Of course, I don’t expect it to be
accurate, but I don’t care for my purposes.

I suspect this key was added in NT SP 4 as part of the “uptime”
enhancements? If so, it should be updated every 5 minutes (although that
can be disabled if you desire to have the hard drive go into sleep mode).
(BTW, if you haven’t used the UPTIME tool, I suggest you download it from
Microsoft; it’s very useful for presenting a nice summary (and statistics)
of the information in the Event Log.)


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com