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,
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>