【发布时间】:2011-06-29 13:19:43
【问题描述】:
如何在 Windows 2008/2003 机器上获取上次启动/重启/重启的日期和时间?
我从命令提示符知道我们可以使用“网络统计”,但是如何通过 Delphi 来实现呢?
谢谢。
【问题讨论】:
如何在 Windows 2008/2003 机器上获取上次启动/重启/重启的日期和时间?
我从命令提示符知道我们可以使用“网络统计”,但是如何通过 Delphi 来实现呢?
谢谢。
【问题讨论】:
您可以使用Win32_OperatingSystem WMI 类的LastBootUpTime 属性,它返回Date and time the operating system was last restarted(注意:该属性的返回值是UTC 格式)。
查看此示例应用
{$APPTYPE CONSOLE}
uses
SysUtils,
ActiveX,
Variants,
ComObj;
//Universal Time (UTC) format of YYYYMMDDHHMMSS.MMMMMM(+-)OOO.
//20091231000000.000000+000
function UtcToDateTime(const V : OleVariant): TDateTime;
var
Dt : OleVariant;
begin
Result:=0;
if VarIsNull(V) then exit;
Dt:=CreateOleObject('WbemScripting.SWbemDateTime');
Dt.Value := V;
Result:=Dt.GetVarDate;
end;
procedure GetWin32_OperatingSystemInfo;
const
WbemUser ='';
WbemPassword ='';
WbemComputer ='localhost';
wbemFlagForwardOnly = $00000020;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObjectSet: OLEVariant;
FWbemObject : OLEVariant;
oEnum : IEnumvariant;
iValue : LongWord;
begin;
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword);
FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_OperatingSystem','WQL',wbemFlagForwardOnly);
oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
if oEnum.Next(1, FWbemObject, iValue) = 0 then
begin
Writeln(Format('Last BootUp Time %s',[FWbemObject.LastBootUpTime]));// In utc format
Writeln(Format('Last BootUp Time %s',[formatDateTime('dd-mm-yyyy hh:nn:ss',UtcToDateTime(FWbemObject.LastBootUpTime))]));// Datetime
end;
end;
begin
try
CoInitialize(nil);
try
GetWin32_OperatingSystemInfo;
finally
CoUninitialize;
end;
except
on E:Exception do
Writeln(E.Classname, ':', E.Message);
end;
Writeln('Press Enter to exit');
Readln;
end.
【讨论】:
LastBootUpTime,但我知道你会想发布答案:) 当我前段时间浏览the reference 时,我不相信WMI 有多少秘密。跨度>
systeminfo | find "System Boot Time:" 进行比较(从 CMD.exe 运行)
这是一个完整的命令行应用程序,可以满足您的要求。 我已对此进行了修改,以避免在不依赖外部函数调用的情况下出现 GetTickCount 溢出问题。
示例输出:
Windows was last rebooted at: 06/29/2011 9:22:47 AM
玩得开心!
program lastboottime;
{$APPTYPE CONSOLE}
uses
SysUtils,
Windows;
function UptimeInDays: double;
const
c_SecondsInADay = 86400;
var
cnt, freq: Int64;
begin
QueryPerformanceCounter(cnt);
QueryPerformanceFrequency(freq);
Result := (cnt / freq) / c_SecondsInADay;
end;
function LastBootTime: TDateTime;
begin
Result := Now() - UptimeInDays;
end;
begin
try
WriteLn('Windows was last rebooted at: ' + DateTimeToStr(LastBootTime));
ReadLn;
except on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
【讨论】:
GetTickCount 函数(请参阅MSDN)返回自系统启动以来经过的毫秒数,因此将其除以 1000 得到秒,除以 60 000 得到分钟等。
我链接的主题也包含这一点:
要获取自计算机启动以来经过的时间,请在注册表项 HKEY_PERFORMANCE_DATA 的性能数据中检索系统运行时间计数器。返回的值是一个 8 字节的值。有关详细信息,请参阅性能计数器。
【讨论】:
GetTickCount 返回一个 32 位无符号整数,其最大值为 4294967295。解释为毫秒数,这等于略小于 50 天。也就是说,当计算机已经运行了 50 天时,tick count-approach 会错误地认为计算机刚刚启动。
GetTickCount64 的原因,但与正确答案非常接近。
这里有一段代码,如果可用则使用GetTickCount64,如果不可用则回退到GetTickCount,以计算系统启动的日期和时间。这不是一个完美的解决方案,因为 GetTickCount64 仅在 Vista+ 上受支持:如果您使用的是旧版 Windows,则计数器每 49 天返回 0。
program Project29;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows;
type
TGetTickCount64 = function : Int64; stdcall;
var
H_K32: HMODULE;
Tick64Proc: TGetTickCount64;
function BootTime: TDateTime;
var UpTime: Int64;
Seconds, Minutes, Hours: Int64;
begin
if H_K32 = 0 then
begin
H_K32 := LoadLibrary(kernel32);
if H_K32 = 0 then
RaiseLastOSError
else
begin
Tick64Proc := GetProcAddress(H_K32, 'GetTickCount64');
end;
end;
if Assigned(Tick64Proc) then
UpTime := Tick64Proc
else
UpTime := GetTickCount;
Result := Now - EncodeTime(0, 0, 0, 1) * UpTime;
end;
begin
WriteLn(DateTimeToStr(BootTime));
ReadLn;
end.
【讨论】: