Re: Getting system uptime on Windows
- From: David Gravereaux <davygrvy@xxxxxxxxx>
- Date: Tue, 29 Nov 2005 09:08:18 -0800
walton.paul@xxxxxxxxx wrote:
> Does anyone know of a way to find the system uptime or the time of the
> last boot on Windows?
>
> With TWAPI, I can get the time that different users logged on. I´ve
> also found a registry key that stores the time of the last system
> shutdown. But still I can´t find any way to get the system uptime.
>
> I can parse the time from the output of the following system commands,
> but running these commands with [exec] gives no return value, so I
> can´t access the output within Tcl:
> net statistics workstation
> net statistics server
>
>
> Now I´m trying to do it by reading the Windows event log through
> TWAPI, but still no luck.
>
> Any ideas? Thanks in advance.
>
>
> Paul
>
Hmm.. uptime.. Your answer is:
% winutils::duration [winutils::uptime]
proc ::winutils::duration { int_time } {
set timeList [list]
foreach div {86400 3600 60 1} mod {0 24 60 60} name {day hr min sec} {
set n [expr {$int_time / $div}]
if {$mod > 0} {set n [expr {$n % $mod}]}
if {$n > 1} {
lappend timeList "$n ${name}s"
} elseif {$n == 1} {
lappend timeList "$n $name"
}
}
return [join $timeList]
}
The performance counter used is "\\System\\System Up Time", FYI. If
TWAPI can query performance counter bits, you won't need my C source.
/* ---------------------------------------------------------------------- * UpTime.c --
*
* The uptime command. Fully thread safe. Returns the number of
* seconds since boot. Limited to only 49 days on Win9X, but tops
* the chart and, basically, has no realistic limit on NT.
*
* ----------------------------------------------------------------------
*
* Written by: David Gravereaux <davygrvy@xxxxxxxxx>
*
* No restrictions are placed on the redistribution of this code. See
* license.txt for more detail.
*
* ----------------------------------------------------------------------
* RCS: @(#) $Id: UpTime.c,v 1.9 2002/05/21 23:39:44 davygrvy Exp $
* ----------------------------------------------------------------------
*/
#include "tcl.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <pdh.h>
TCL_DECLARE_MUTEX(initLock)
static int initialized = 0;
static int usePerfMon = 0;
static int gotWideInt = 0;
static HMODULE hPDH;
struct {
PDH_STATUS (__stdcall *PdhOpenQueryProc)
(LPCSTR, DWORD_PTR, PDH_HQUERY *);
PDH_STATUS (__stdcall *PdhAddCounterProc)
(PDH_HQUERY, LPCSTR, DWORD_PTR, PDH_HCOUNTER *);
PDH_STATUS (__stdcall *PdhCollectQueryDataProc)
(PDH_HQUERY);
PDH_STATUS (__stdcall *PdhGetFormattedCounterValueProc)
(PDH_HCOUNTER, DWORD, LPDWORD, PPDH_FMT_COUNTERVALUE);
PDH_STATUS (__stdcall *PdhCloseQueryProc)
(PDH_HQUERY);
} pdhProcs;
Tcl_Obj *GetPdhMsgObj(PDH_STATUS id)
{
int chars;
char sysMsgSpace[512];
chars = wsprintf(sysMsgSpace, "[0x%X] ", id);
FormatMessage(FORMAT_MESSAGE_FROM_HMODULE|
FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_MAX_WIDTH_MASK,
hPDH, id, 0, sysMsgSpace+chars, (512-chars), 0);
return Tcl_NewStringObj(sysMsgSpace, -1);
}
int
UpTimeObjCmd (ClientData cData, Tcl_Interp *interp, int objc,
struct Tcl_Obj * CONST objv[])
{
HQUERY hQuery;
HCOUNTER *pCounterHandle;
PDH_STATUS pdhStatus;
DWORD ctrType;
PDH_FMT_COUNTERVALUE fmtValue;
if (usePerfMon) {
pCounterHandle = (HCOUNTER *) GlobalAlloc(GPTR,sizeof(HCOUNTER));
if ((pdhStatus = pdhProcs.PdhOpenQueryProc(0, 0, &hQuery))
!= NO_ERROR) {
goto pdhError;
}
if ((pdhStatus = pdhProcs.PdhAddCounterProc(hQuery,
"\\System\\System Up Time", 0, pCounterHandle))
!= NO_ERROR) {
goto pdhError;
}
if ((pdhStatus = pdhProcs.PdhCollectQueryDataProc(hQuery))
!= NO_ERROR) {
goto pdhError;
}
if (gotWideInt) {
/* Get the 64-bit size */
if ((pdhStatus = pdhProcs.PdhGetFormattedCounterValueProc(
*pCounterHandle, PDH_FMT_LARGE|PDH_FMT_NOSCALE,
&ctrType, &fmtValue)) != NO_ERROR) {
goto pdhError;
}
/* Set a 64-bit native object. Behavior of unsigned is
* unknown, but at 2^63 seconds, who cares... */
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(
fmtValue.largeValue));
} else {
/* Get the 32-bit size */
if ((pdhStatus = pdhProcs.PdhGetFormattedCounterValueProc(
*pCounterHandle, PDH_FMT_LONG|PDH_FMT_NOSCALE,
&ctrType, &fmtValue)) != NO_ERROR) {
goto pdhError;
}
/* 2^31 max possible */
Tcl_SetObjResult(interp, Tcl_NewIntObj(fmtValue.longValue));
}
pdhProcs.PdhCloseQueryProc(hQuery);
GlobalFree(pCounterHandle);
} else {
/* Get milliseconds since boot and truncate it to seconds */
Tcl_SetObjResult(interp, Tcl_NewIntObj(GetTickCount() / 1000));
}
return TCL_OK;
pdhError:
GlobalFree(pCounterHandle);
Tcl_SetObjResult(interp, GetPdhMsgObj(pdhStatus));
return TCL_ERROR;
}
void Uptime_ExitProc(ClientData clientData)
{
/* be festideous */
FreeLibrary(hPDH);
}
int
Uptime_Init(Tcl_Interp *interp)
{
Tcl_MutexLock(&initLock);
if (!initialized) {
OSVERSIONINFO os;
int major, minor, patchLevel, type;
initialized = 1;
os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&os);
/*
* When running under NT, use the performance monitor API. This
* allows for *really big* __int64 results without milliseconds
* (seconds only). So max seconds since boot could be up to 2^63
* or 9,223,372,036,854,775,808. Which is, 106,751,991,167,300
* days 15 hrs 30 mins 8 secs or 292,471,208,677+ years! We use
* the new Tcl_WideInt type, when supported, to maintain this
* size.
*
* If the core doesn't support Tcl_WideInt, then we get a 32-bit
* result which has a max of 24855 days 3 hrs 14 mins 8 secs.
* Not shabby @ 68+ years for 2^31 seconds.
*
* Under Win9X, rollover to zero happens at 49 days 17 hrs 2 mins
* 47 secs using GetTickCount() where we truncate the
* milliseconds to return only seconds. Very shabby.
*/
if (os.dwPlatformId == VER_PLATFORM_WIN32_NT) {
if ((hPDH = LoadLibrary("pdh.dll")) == 0L) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"Can't load pdh.dll",-1));
return TCL_ERROR;
}
usePerfMon = 1;
(void *) pdhProcs.PdhOpenQueryProc =
GetProcAddress(hPDH, "PdhOpenQueryA");
(void *) pdhProcs.PdhAddCounterProc =
GetProcAddress(hPDH, "PdhAddCounterA");
(void *) pdhProcs.PdhCollectQueryDataProc =
GetProcAddress(hPDH, "PdhCollectQueryData");
(void *) pdhProcs.PdhGetFormattedCounterValueProc =
GetProcAddress(hPDH, "PdhGetFormattedCounterValue");
(void *) pdhProcs.PdhCloseQueryProc =
GetProcAddress(hPDH, "PdhCloseQuery");
Tcl_CreateExitHandler(Uptime_ExitProc, 0L);
}
Tcl_GetVersion(&major, &minor, &patchLevel, &type);
/* Check for the Tcl_WideInt type by core version. */
if (major > 8 || (major == 8 && minor > 4) || (major == 8 &&
minor == 4 && ((type == TCL_ALPHA_RELEASE &&
patchLevel >= 4) || type > TCL_ALPHA_RELEASE)))
{
/* use the new Tcl_WideInt type when available */
gotWideInt = 1;
}
}
Tcl_MutexUnlock(&initLock);
if (usePerfMon) {
Tcl_CreateObjCommand(interp, "winutils::uptime", UpTimeObjCmd, 0L,
0L);
}
return TCL_OK;
}
- References:
- Getting system uptime on Windows
- From: walton . paul
- Getting system uptime on Windows
- Prev by Date: Re: Packaging Tcl/Tk Application on Windows: Single File Executable
- Next by Date: Tcl core work [Was: Re: BLT ZoomStack ( and an enq. for Mr. J. Hobbs )
- Previous by thread: Re: Getting system uptime on Windows
- Next by thread: string handle problem
- Index(es):
Relevant Pages
|