Uptime past 49.7 days (without using GetTickCount)

I want to get the system uptime.. I can't use GetTickCount because it returns a 32-bit integer, resulting in a wraparound after 49.7 days.

I've read that using the registry root HKEY_PERFORMANCE_DATA you can read the system uptime (using RegQueryValueEx) but I'm not sure how to go about it.. the stuff over at MSDN isn't very helpful and I haven't managed to find any sample Delphi code anywhere.

Any help appreciated :)

nem2k4
nem2k4Asked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
Lee_NoverConnect With a Mentor Commented:
I use this and it works perfectly:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    txtUptime: TEdit;
    Timer1: TTimer;
    procedure Timer1Timer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormKeyUp(Sender: TObject; var Key: Word;
      Shift: TShiftState);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses DateUtils;

{$R *.dfm}

function GetTickCount: Int64;
var
  nTime, freq: Int64;
begin
  if Windows.QueryPerformanceFrequency(freq) then
    if Windows.QueryPerformanceCounter(nTime) then
       result:=Trunc(nTime/Freq*1000)
    else
       result:= Windows.GetTickCount
  else
    result:= Windows.GetTickCount;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var dt: TDateTime;
begin
     dt:=0;
     dt:=IncMilliSecond(dt, GetTickCount);
     txtUptime.Text:=Format('%d d %s', [DaysBetween(dt, 0), FormatDateTime('hh:nn:ss', dt)]);
     txtUptime.SelectAll;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
     Timer1Timer(Sender);
end;

procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
     if Key = VK_ESCAPE then
        Close;
end;

end.
0
 
shaneholmesCommented:
Maybe this can help you.....

 Delphi 3.0 Performance Data Viewer for NT

 displays a tree view of the data held in the dynamic HKEY_PERFORMANCE_DATA registry hive.  
The download  includes components which encapsulate the performance data - including source, and a demo program.

http://www.wilsonc.demon.co.uk/delphi3.htm#NT%20Specific%20Components

Shane

0
 
shaneholmesCommented:
Maybe this can help you.....

 Delphi 3.0 Performance Data Viewer for NT

 displays a tree view of the data held in the dynamic HKEY_PERFORMANCE_DATA registry hive.  
The download  includes components which encapsulate the performance data - including source, and a demo program.

http://www.wilsonc.demon.co.uk/delphi3.htm#NT%20Specific%20Components

Shane

0
Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
nem2k4Author Commented:
Thanks.. http://www.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_20047646.html?query=HKEY_PERFORMANCE_DATA&searchType=topic has the same problem I'm having - how do you actually query it (concrete code)?


The Performance Data Viewer displays perfmon info which is handy but there's no uptime statistic in there.. it uses HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\PerfLib\009
0
 
shaneholmesConnect With a Mentor Commented:
hmmmm,

I' have never dove into that far into the registry (i.e. HKEY_PERFORMANCE_DATA key).

Nor have I had any inclination to use the system uptime, but i did find some example code on how to use
 RegQueryValueEx in another delphi example ....


Maybe you can use this....

Shane

Here is an example which reads the content of the "CommonFilesDir" value under "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion"

procedure TForm1.Button1Click(Sender: TObject);
var
  hReg: Integer;
  dwType, BufSize: DWORD;
  pBuf: array[0..MAX_PATH] of Char;
begin
  if RegOpenKey(HKEY_LOCAL_MACHINE, 'Software\Microsoft\Windows\CurrentVersion', hReg) = ERROR_SUCCESS then begin
    BufSize := MAX_PATH;
    RegQueryValueEx(hReg, 'CommonFilesDir', nil, @dwType, @pBuf, @BufSize);
    if (dwType = REG_SZ) then ShowMessage(string(PChar(@pBuf)));
    RegCloseKey(hReg);
  end;
end;
0
 
nem2k4Author Commented:
Thanks, I'll try that... what do I use in place of 'Software\Microsoft\Windows\CurrentVersion' though? :)
0
 
nem2k4Author Commented:
(and 'CommonFilesDir' ?)
0
 
shaneholmesCommented:
You may be able to use an empty string "", try that

Shane
0
 
shaneholmesCommented:
CommonFilesDir is what you are looking for.

This is the key to you query, cause if your gonna query for something, ya have to know what your querying for, in this case, the name which holds the value your looking for.

Again, since i've never dealt in to that part of the Registry, i dont have a clue where in that Key (HKEY_PERFORMANCE_DATA) it exists.

There are a lot of experts on in the morning, so you may want to wait until then to see if any will jump in here and help you with this issue.

Shane


0
 
shaneholmesCommented:
Im sorry, i should explain more....

"CommonFilesDir" should be relaced with what you are looking for


Shane
0
 
nem2k4Author Commented:
Using this code:



procedure TForm1.SpeedButton1Click(Sender: TObject);
var
  hReg: HKEY;
  dwType, BufSize: DWORD;
  pBuf: array[0..MAX_PATH] of Char;
begin
  if RegOpenKey(HKEY_PERFORMANCE_DATA, '', hReg) = ERROR_SUCCESS then begin
    BufSize := MAX_PATH;
    RegQueryValueEx(hReg, 'CommonFilesDir', nil, @dwType, @pBuf, @BufSize);
    if (dwType = REG_SZ) then ShowMessage(string(PChar(@pBuf)));
    RegCloseKey(hReg);
  end else
    showmessage('unsuccessful');
end;


I just get the message "unsuccessful".
0
 
nem2k4Author Commented:
Yeah, that's the problem.. I don't know the exact names of what the names of the things I am looking for either.
0
 
shaneholmesCommented:
Yeah, thats why i was saying, wait till morning, maybe some of the other experts will no some of the names of the things your looking for. Im still looking myself though...

Shane
0
 
shaneholmesCommented:
0
 
nem2k4Author Commented:
craig_capel's stuff down the bottom looks promising, but according to him it doesn't quite work?

Perhaps using the code you posted, we can use "\\compname\System\System Up Time" as the key value?

The other stuff isn't suitable cuz you have to have a seperate program run on startup etc, my app needs to be self-contained.
0
 
nem2k4Author Commented:
some thing like:

procedure TForm1.SpeedButton1Click(Sender: TObject);
var
  hReg: HKEY;
  dwType, BufSize: DWORD;
  pBuf: array[0..MAX_PATH] of Char;
begin
  if RegOpenKey(HKEY_PERFORMANCE_DATA, 'System', hReg) = ERROR_SUCCESS then begin
    BufSize := MAX_PATH;
    RegQueryValueEx(hReg, 'System Up Time', nil, @dwType, @pBuf, @BufSize);
    if (dwType = REG_SZ) then ShowMessage(string(PChar(@pBuf)));
    RegCloseKey(hReg);
  end else
    showmessage('unsuccessful');
end;


? (doesn't work, but maybe with some tweaking..)
0
 
shaneholmesCommented:

Some thing like this below, but if that worked, that would only give us the key to open, we would still need to know the name  of the Value, in order to extract its data

procedure TForm1.SpeedButton1Click(Sender: TObject);
var
  hReg: HKEY;
  dwType, BufSize: DWORD;
  pBuf: array[0..MAX_PATH] of Char;
begin
  if RegOpenKey(HKEY_PERFORMANCE_DATA, '\compname\System\System Up Time', hReg) = ERROR_SUCCESS then begin
    BufSize := MAX_PATH;
    RegQueryValueEx(hReg, 'NAME OF VALUE HERE', nil, @dwType, @pBuf, @BufSize);
    if (dwType = REG_SZ) then ShowMessage(string(PChar(@pBuf)));
    RegCloseKey(hReg);
  end else
    showmessage('unsuccessful');
end;


unless its this...


procedure TForm1.SpeedButton1Click(Sender: TObject);
var
  hReg: HKEY;
  dwType, BufSize: DWORD;
  pBuf: array[0..MAX_PATH] of Char;
begin
  if RegOpenKey(HKEY_PERFORMANCE_DATA, '\compname\System', hReg) = ERROR_SUCCESS then begin
    BufSize := MAX_PATH;
    RegQueryValueEx(hReg, 'System Up Time', nil, @dwType, @pBuf, @BufSize);
    if (dwType = REG_SZ) then ShowMessage(string(PChar(@pBuf)));
    RegCloseKey(hReg);
  end else
    showmessage('unsuccessful');

Shane
end;
0
 
nem2k4Author Commented:
2nd one doesn't work..
0
 
nem2k4Author Commented:
That works well Lee_Nover, only one thing that bothers me about it - it seems to return the uptime 10 seconds shorter than what it should be (I'm comparing this uptime method you gave to the Windows Uptime application ( http://www.rundegren.com/software/windowsuptime/ ) which seems to be the standard.
0
 
nem2k4Author Commented:
(Sorry to be picky but my users are.. well.. even more picky!)
0
 
Lee_NoverCommented:
just tested .. both display the same value .. with an offset of ~0,5 sec because of the apps timers being out of sync
and are there any records of that app displaying uptimes beyond 50 days ?
0
 
nem2k4Author Commented:
Hmm.. is there any reason why you use

dt:=IncMilliSecond(dt, GetTickCount);

instead of

dt:=GetTickCount;

?
0
 
Lee_NoverCommented:
ofcourse .. left of the decimal are days ! check what IncMillisecond does
0
 
nem2k4Author Commented:
Sorry, I was just trying to work out why the uptimes differ for this app and Windows Uptime for my computer.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.