Datum und Uhrzeit ändern


Auch wenn es im Beispielprogramm keine Rolle spielt; erwähnenswert ist das Thema sicher. Datum und Uhrzeit kann man mit den beiden Funktionen SetSystemTime (UTC-Zeit) und SetLocalTime ändern. Beide Funktionen erwarten als Parameter eine TSystemTime-Variable, die man vorher mit den neuen Werten "füttern" sollte. Beispielsweise

var
  st : TSystemTime;
begin
  st.wYear         := 2003;
  st.wMonth        := 1;
  st.wDay          := 1;
  st.wHour         := 1;
  st.wMinute       := 0;
  st.wSecond       := 0;
  st.wMilliseconds := 0;
if(SetLocalTime(st)) then MessageBox(0,'Zeit geändert','SetLocalTime',0); end;



Die Rechtefrage unter Windows NT/2000/XP

Die Rechtefrage ist der eigentliche Grund dieses Kapitels. Wenn man sich die alte "win32.hlp" ansieht, die Delphi beiliegt, dann steht dort folgendes:

 Win32 Programmer´s Reference 

The SetSystemTime function fails if the calling process does not have the SE_SYSTEMTIME_NAME privilege. This privilege is disabled by default. Use the AdjustTokenPrivileges function to enable this privilege and again to disable it after the time has been set.

Sinngemäß also: "Wenn der aufrufende Prozess (das Programm z.B.) nicht das Recht SE_SYSTEMTIME_NAME besitzt, scheitert der Aufruf der Funktion und damit das Ändern von Datum und Uhrzeit. Es wird empfohlen, das Recht zu aktivieren, die Funktion auszuführen und das Recht dann wieder zu deaktivieren." Vergleicht man diese Aussage mit neueren Ausgaben des Platform SDK, so liest man:

 Platform SDK 

The SetSystemTime function enables the SE_SYSTEMTIME_NAME privilege before changing the system time. This privilege is disabled by default.

Hier heißt es zwar auch, dass das Recht SE_SYSTEMTIME_NAME standardmäßig deaktiviert ist. Es steht aber auch da, dass die Funktion dieses Recht wohl selbst holen kann (enables the ... privilege). Das steht im Widerspruch zur Aussage der alten Hilfedatei. Ich bin allerdings geneigt, den neuen Quellen eher zu glauben. Ein Test unter Windows XP ergab nämlich einen ganz anderen Ansatzpunkt.

Doch zuerst führen wir den Ratschlag der alten Hilfedatei aus. Die folgende Funktion stammt aus einem Forum und wurde von mir lediglich etwas erweitert, damit sie auch unter 9x-Plattformen benutzt werden kann:

function SetPrivilege(const pszPrivilege: LPCSTR;
  bEnablePrivilege: boolean): boolean;
var
  wv    : TOSVersionInfo;
  Token : THandle;
  tkp   : TTokenPrivileges;
begin
  wv.dwOSVersionInfoSize := sizeof(TOSVersionInfo);
  GetVersionEx(wv);
// da unter 9x jeder alles darf, setzen wir das // Ergebnis in dem Fall auf TRUE Result := (wv.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS);
// jetzt der echte Code für NT-Plattformen if(wv.dwPlatformId = VER_PLATFORM_WIN32_NT) then begin if(not OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY,Token)) then exit;
try if(not LookupPrivilegeValue(nil, pszPrivilege, tkp.Privileges[0].Luid)) then Exit;
tkp.PrivilegeCount := 1;
if(bEnablePrivilege) then tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED else tkp.Privileges[0].Attributes := 0;
Result := AdjustTokenPrivileges(Token, false, tkp, 0, PTokenPrivileges(nil)^, PDWord(nil)^); finally CloseHandle(Token); end; end; end;

Bevor wir also die Zeit und/oder das Datum ändern können, müssen wir uns das dazu erforderliche Recht SE_SYSTEMTIME_NAME holen, was im Code so aussieht:

const
  SE_SYSTEMTIME_NAME = 'SeSystemtimePrivilege';
{ ... }
if(SetPrivilege(SE_SYSTEMTIME_NAME,true)) then SetLocalTime(st);


So würde das auch funktionieren, wenn ... tja ...

Sagen wir so: bei einem Test mit Benutzerrechten wurde die Zeit auch mit der eben erfolgten Anweisung nicht geändert. Des Rätsels Lösung war eine Einstellung der lokalen Sicherheitsrichtlinien von Windows XP. Hier finden Sie unter "Lokale Richtlinien/Zuweisen von Benutzerrechten" den Punkt "Ändern der Systemzeit", für den standardmäßig nur die Administratoren und Hauptbenutzer eingetragen sind. Geben Sie hier zusätzlich Ihren Benutzernamen an, oder ergänzen Sie die Gruppe, der Sie als Benutzer angehören, dann können Sie auch Datum und Uhrzeit ändern.

Und das klappt dann auch, ohne dass man das Recht SE_SYSTEMTIME_NAME vorher explizit setzen muss. Zumindest war das bei meinem Test unter Windows XP so. Und damit wäre ich wieder bei meiner Behauptung, dass sich die Funktion "SetSystemTime" das Recht ggf. selbst holt (so wie es auch im PSDK gesagt wird). Und da keinerlei Einschränkungen genannt werden, dürfte es bei Windows 2000 und NT ähnlich sein.