Uptime systemu Windows
Od jakiegoś czasu próbuję pobrać uptime systemu Windows. Wszystkim dobrze znana funkcja GetTickCount(), działa, ale ma jeden poważny problem. Funkcja zwraca wartość 32 bitową co oznacza, że po 49.7 dniach nastąpi przekręcenie się licznika uptime. Starsze wersje systemu Windows z serii 9x pokazywały wtedy niebieski ekran ;-) Żartownisie uważają, że specjalnie to zostało tak zrobione, bo i tak żaden Windows dłużej niż tydzień nie może działać.
Szukałem czegoś co zastąpi tę funkcję. Na stronach MSDN dowiedziałem się o istnieniu funkcji GetTickCount64(). Zbawienie dla mojego problemu. Niestety funkcja ta jest dopiero zaimplementowana w systemie Windows Vista oraz Windows Server "Longhorn". I tutaj znowu z pomocą przychodzi nam MSDN. Na stronie można przeczytać, że:
To obtain the time elapsed since the computer was started, retrieve the System Up Time counter in the performance data in the registry key HKEY_PERFORMANCE_DATA. The value returned is an 8-byte value. For more information, see Performance Counters.
Informacje pobierane są 64-bitowej wartości z rejestru. Rozwiązuje to w zupełności problem z przekręcaniem się licznika. Poniżej kod autorstwa Nathan Laredo
/* $Id: uptime.c,v 1.10 2002/08/22 19:06:58 nlaredo Exp $
* ----------------------------------------------------------------------- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* ----------------------------------------------------------------------- *
* uptime.c -- Nathan Laredo
*/
#include
#include
/* define some C99 types for windows */
typedef unsigned __int32 uint32_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int64 uint64_t;
typedef unsigned __int8 uint8_t;
typedef __int32 int32_t;
typedef __int16 int16_t;
typedef __int64 int64_t;
typedef __int8 int8_t;
static char msgstr[4096];
static int users = 0;
#define KEY_SYSTEM L"2"
#define IDX_UPTIME 674
#define IDX_PROCQUEUE 44
static void get_boottime(ULARGE_INTEGER *boottime,
ULARGE_INTEGER *nowtime,
uint32_t *procqueue)
{
BYTE pbuf[4096];
PPERF_DATA_BLOCK ppdb = (PPERF_DATA_BLOCK) pbuf;
DWORD psz = sizeof(pbuf);
PPERF_OBJECT_TYPE ppot;
PPERF_COUNTER_DEFINITION ppcd;
PPERF_COUNTER_BLOCK ppcb;
DWORD i;
memset(pbuf, 0, psz);
nowtime->QuadPart = boottime->QuadPart = 0; /* 0 = error */
/* get current 64-bit boottime in 100ns units */
RegQueryValueExW(HKEY_PERFORMANCE_DATA, KEY_SYSTEM,
NULL, NULL, pbuf, &psz);
RegCloseKey(HKEY_PERFORMANCE_DATA);
if(memcmp(pbuf, L"PERF", 8)) {
/* PERF_DATA_BLOCK signature not present */
return;
}
/* parse returned performance data */
ppot = (PPERF_OBJECT_TYPE) &pbuf[ppdb->HeaderLength];
ppcd = (PPERF_COUNTER_DEFINITION)
&pbuf[ppdb->HeaderLength + ppot->HeaderLength];
ppcb = (PPERF_COUNTER_BLOCK)
&(((uint8_t *)ppot)[ppot->DefinitionLength]);
nowtime->QuadPart = ppdb->PerfTime100nSec.QuadPart;
/* get uptime and processor queue length */
for (i = 0; i < ppot->NumCounters; i++) {
if (ppcd->CounterNameTitleIndex == IDX_UPTIME) {
boottime->QuadPart = (int64_t) *(uint64_t *)
&(((uint8_t *)ppcb)[ppcd->CounterOffset]);
}
if (ppcd->CounterNameTitleIndex == IDX_PROCQUEUE) {
*procqueue = (int32_t) *(uint32_t *)
&(((uint8_t *)ppcb)[ppcd->CounterOffset]);
}
ppcd++;
}
}
static BOOL CALLBACK ewsproc(LPTSTR lpszWindowStation, LPARAM lParam)
{
users++;
return TRUE;
}
static void uptime(void)
{
ULARGE_INTEGER bt, nt, ut;
uint32_t procqueue, days;
SYSTEMTIME bst, nst, ust;
TCHAR btstr[128], ntstr[128], bdstr[128];
get_boottime(&bt, &nt, &procqueue);
ut.QuadPart = nt.QuadPart - bt.QuadPart;
FileTimeToSystemTime((FILETIME *) &bt, &bst);
FileTimeToSystemTime((FILETIME *) &nt, &nst);
FileTimeToSystemTime((FILETIME *) &ut, &ust);
SystemTimeToTzSpecificLocalTime(NULL, &bst, &bst);
SystemTimeToTzSpecificLocalTime(NULL, &nst, &nst);
GetTimeFormat(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP, &bst, NULL,
btstr, sizeof(btstr));
GetTimeFormat(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP, &nst, NULL,
ntstr, sizeof(ntstr));
GetDateFormat(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP,
&bst, NULL, bdstr, sizeof(bdstr));
sprintf(msgstr, " %s up ", ntstr);
ut.QuadPart /= 864000000000;
days = (uint32_t) ut.QuadPart;
if (days > 1) {
sprintf(&msgstr[strlen(msgstr)], "%d days, ", days);
} else if (days == 1) {
sprintf(&msgstr[strlen(msgstr)], "1 day, ");
}
sprintf(&msgstr[strlen(msgstr)], "%02d:%02d:%02d, ",
ust.wHour, ust.wMinute, ust.wSecond);
sprintf(&msgstr[strlen(msgstr)], "%d user%s, ", users,
users == 1 ? "" : "s");
sprintf(&msgstr[strlen(msgstr)], "boot %s %s, "
"load: %d", bdstr, btstr, procqueue);
printf(msgstr);
}
int main(int argc, char **argv)
{
int count = atoi(argv[argc - 1]);
EnumWindowStations(ewsproc, 0);
uptime();
if (count==0) printf("\r\n"); else printf("\r");
fflush(stdout);
for (; count > 0; count--) {
Sleep(1000);
printf("\r");
uptime();
if (count == 1) {
printf("\r\n");
}
fflush(stdout);
}
return 0;
}
/* EOF */
21 lutego 2007, 19:46:20
Komentarze
Hehehe :) Szukałem długo w regedit: HKEY_PERFORMANCE_DATA, ale tego tam nie ma. Potem odpaliłem google i znalazłem ten kod. Bardzo ładnie się skompilował i dodałem do mojej aplikacji i ładnie działa. Teraz zmieniam troszkę tę funkcję by była bardziej optymalna.
Właśnie dlatego wycofałem się z C++ i WinAPI :)
A ja lubię C++ :) Teraz mam laboratoria z Assemblera…
Jako ciekawostke mogę powiedzieć, że znam Windows’a Me(ee) który pracuje do dzisiaj, nieprzerwanie od … 2001 roku.
Dowodów nie mogę dostarczyć, gdyż nie mam już dostępu do miejsca w którym się on znajduje, a jest to stacja pogotowia ratunkowego…
Pozdrawiam
No to niezła ciekawostka. Wiesz :) Mój Windows też może mieć wielki uptime jak go zahibernuję :)
Wiem, że w Łodzi na komendzie głównej był odpalony MS-DOS z Norton Commanderem przez kilka lat (monitor też działał non stop) i wypaliły się na nim okienka Nortona ;-)
Albo jestem jakiś dziwnie ślepy, albo w tym snippecie masz puste #include. Czyżby problem z <>?
Faktycznie. :) Problem z <> :) Myślałem, że <pre> poprawnie to zinterpretuje.
Heh. Kiedyś też babrałem się w WinAPI, stare czasy ;)
Powered by Jogger. Copyright © 2002-2003 Justin Mecham & JabberPL Group
Licencja: Creative Commons Uznanie autorstwa 3.0





Jakież to proste, banalne i króciutkie :D
;)