0
votes

I have a delphi program that set Time Zone Information of windows to specific start and end dates. it works perfectly in windows 7 , vista and Server 2008. but not in earlier windows versions such as XP and Server 2003. I'm curious if I have mistakes in the code or it is an XP problem ?

Here is my code:

program SetTimeZoneInfo;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Messages,
  windows;

const
  SE_TIME_ZONE_NAME = 'SeTimeZonePrivilege';
  SE_SYSTEMTIME_NAME = 'SeSystemtimePrivilege';

function NTSetPrivilege(sPrivilege: string; bEnabled: Boolean): Boolean;
var
  hToken: THandle;
  TokenPriv: TOKEN_PRIVILEGES;
  PrevTokenPriv: TOKEN_PRIVILEGES;
  ReturnLength: Cardinal;
begin
  Result := True;
  if not (Win32Platform = VER_PLATFORM_WIN32_NT) then Exit;

  // obtain the processes token
  if OpenProcessToken(GetCurrentProcess(),
    TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken) then
  begin
    try
      // Get the locally unique identifier (LUID) .
      if LookupPrivilegeValue(nil, PChar(sPrivilege),
        TokenPriv.Privileges[0].Luid) then
      begin
        TokenPriv.PrivilegeCount := 1; // one privilege to set

        case bEnabled of
          True: TokenPriv.Privileges[0].Attributes  := SE_PRIVILEGE_ENABLED;
          False: TokenPriv.Privileges[0].Attributes := 0;
        end;

        ReturnLength := 0; // replaces a var parameter
        PrevTokenPriv := TokenPriv;

        // enable or disable the privilege

        AdjustTokenPrivileges(hToken, False, TokenPriv, SizeOf(PrevTokenPriv),
          PrevTokenPriv, ReturnLength);
      end;
    finally
      CloseHandle(hToken);
    end;
  end;
  // test the return value of AdjustTokenPrivileges.
  Result := GetLastError = ERROR_SUCCESS;
  if not Result then
    raise Exception.Create(SysErrorMessage(GetLastError));
end;

var
  tzi: TTimeZoneInformation;
  lpwdResult, LHResult: Cardinal;
begin
  if Win32MajorVersion >= 6 then
  begin
    Writeln('NTSetPrivilege SE_TIME_ZONE_NAME enabled ? ' + BoolToStr(NTSetPrivilege(SE_TIME_ZONE_NAME, True), True));
  end;
  Writeln('NTSetPrivilege SE_TIME_ZONE_NAME enabled ? ' + BoolToStr(NTSetPrivilege(SE_SYSTEMTIME_NAME, True), True));

  tzi.Bias:= -210;

  tzi.DaylightDate.wYear:= 2012;
  tzi.DaylightDate.wMonth:= 3;
  tzi.DaylightDate.wDay:= 20;
  tzi.DaylightDate.wHour:= 23;
  tzi.DaylightDate.wMinute:= 59;
  tzi.DaylightDate.wSecond:= 59;
  tzi.DaylightBias:= -60;

  tzi.StandardDate.wYear:= 2012;
  tzi.StandardDate.wMonth:= 9;
  tzi.StandardDate.wDay:= 20;
  tzi.DaylightDate.wHour:= 23;
  tzi.DaylightDate.wMinute:= 59;
  tzi.DaylightDate.wSecond:= 59;
  tzi.StandardBias:= 0;

  if not SetTimeZoneInformation(tzi) then
      Writeln('SetTimeZoneInformation Error Message: '+ SysErrorMessage(GetLastError))
  else
    Writeln('SetTimeZoneInformation : Success');

  LHResult:= SendMessageTimeout(
                      HWND_BROADCAST,   // reciever window handle
                      WM_SETTINGCHANGE, // message
                      0,                // WParam
                      0,                // LParam
                      SMTO_NORMAL,      // return if reciever hange
                      5,                // timeout in seconds
                      lpwdResult        // result
                      );
  if LHResult = 0 then
    Writeln('SendMessageTimeout Error Message: '+ SysErrorMessage(GetLastError))
  else
    Writeln('SendMessageTimeout : Success');

  if Win32MajorVersion >= 6 then
    Writeln('NTSetPrivilege SE_TIME_ZONE_NAME disabled ? ' + BoolToStr(NTSetPrivilege(SE_TIME_ZONE_NAME, False), True));
  Writeln('NTSetPrivilege SE_TIME_ZONE_NAME disabled ? ' + BoolToStr(NTSetPrivilege(SE_SYSTEMTIME_NAME, False), True));
  Readln;
end.
1
Describe how it fails. "it doesn't work" is not helpful. - David Heffernan
Also, your error checking is completely incorrect. You have to call GetLastError immediately after calling each API function. In NTSetPrivilege you have 3 calls to API functions but only one call to GetLastError. What's more you failed to check the return value of AdjustTokenPrivileges so you cannot know whether or not it failed. - David Heffernan
Reading down the code you have a line that reads if Win32MajorVersion >= 6 then. That means that you only attempt to acquire the SE_TIME_ZONE_NAME priv for Vista and up. Why do you do that? - David Heffernan
We need more than that. Which API call fails. And what is the error code associated with that failure. You are running the code, we aren't. You can highlight the precise point in the code where an API call fails. We can't. - David Heffernan
David, "it doesn't work" means that it does not set timezone info, Bias, DST start and DST end dates - mjalil

1 Answers

0
votes

When the Windows is new version, use: SetDynamicTimeZoneInformation. When it is old (Ex: XP), use SetTimeZoneInformation as you did. Tell me if it solved the problem. I also have to do something similar. Thanks. Rodrigo Pimenta Carvalho