我无法使用 SetDynamicTimeZoneInformation 禁用夏令时

发布于 2024-12-03 12:21:02 字数 2826 浏览 1 评论 0原文

我使用 SetDynamicTimeZoneInformation 函数设置时区信息(启用/禁用夏令时),在 Vista/Win7 或更高版本下,您可能会看到下面的代码片段。
现在,代码似乎工作正常,时区信息已正确更新,但我对 DynamicDaylightTimeDisabled 标志有一个奇怪的问题。如果更改日光选项,则时间跳跃会更改一小时;但当我将 DynamicDaylightTimeDisabled 设置为 true 时,Vista/Win7 时区设置对话框中的“自动调整夏令时时钟”复选框仍处于选中状态。

那么,我做错了什么?谢谢。

type
  TRegTZI = record // a TZI registry value is 44 bytes in this order
    Bias, // 4 bytes
    StdBias, // 4 bytes
    DltBias: integer; // 4 bytes
    StdDate, // 16 bytes
    DltDate: TSystemTime; // 16 bytes
  end;

  TTZIData = record
    TZName: string;
    Display, Dlt, Std: string;
    RegTZI: TRegTZI;
  end;


implementation

    function TZIDtatToWinTDZI(ATZI: TTZIData; DDTDisabled: boolean): TIME_DYNAMIC_ZONE_INFORMATION;
    var
      WinTDZI: TIME_DYNAMIC_ZONE_INFORMATION;
    begin
      WinTDZI.Bias := ATZI.RegTZI.Bias;
      WinTDZI.StandardBias := ATZI.RegTZI.StdBias;
      WinTDZI.DaylightBias := ATZI.RegTZI.DltBias;
      if not DDTDisabled then
      begin
        WinTDZI.StandardDate := ATZI.RegTZI.StdDate;
        WinTDZI.DaylightDate := ATZI.RegTZI.DltDate;
      end;
      StringToWideChar(ATZI.Std, @WinTDZI.StandardName[0], 32);
      StringToWideChar(ATZI.Dlt, @WinTDZI.DaylightName[0], 32);
      StringToWideChar(ATZI.TZName, @WinTDZI.TimeZoneKeyName[0], 128);
      WinTDZI.DynamicDaylightTimeDisabled := DDTDisabled;
      Result := WinTDZI;
    end;

    function GetTZIDataByName(TZKeyName: string; var ATZI: TTZIData): boolean;
    var
      Reg: TRegistry;
      BiRecSize: integer; 
    begin
      Result := False;
      Reg := TRegistry.Create;
      try
        Reg.RootKey := HKEY_LOCAL_MACHINE;
        if Reg.OpenKey('Software\Microsoft\Windows NT\CurrentVersion\Time Zones\' + TZKeyName, False) then
        begin
          Result := True;
          ATZI.TZName := TZKeyName;
          if Reg.ValueExists('Display') then ATZI.Display := Reg.ReadString('Display');
          if Reg.ValueExists('Dlt') then ATZI.Dlt := Reg.ReadString('Dlt');
          if Reg.ValueExists('Std') then ATZI.Std := Reg.ReadString('Std');
          if Reg.ValueExists('TZI') then BiRecSize := Reg.ReadBinaryData('TZI', ATZI.RegTZI, SizeOf(ATZI.RegTZI));
          Reg.CloseKey;
        end;
      finally
        Reg.free;
      end;
    end;


    function Vista_SetTimeZone(TZKeyName: string; AutoAdjustEnabled: boolean;
      var ErrStr: string): boolean;
    var
      ATZI: TTZIData;
      WinTDZI: TIME_DYNAMIC_ZONE_INFORMATION;
    begin
      if GetTZIDataByName(TZKeyName, ATZI) then
      begin
        WinTDZI := TZIDtatToWinTDZI(ATZI, not AutoAdjustEnabled);
        Result := SetDynamicTimeZoneInformation (WinTDZI) <> 0;
        if Result then
          SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0);
      end;
    end;

I use SetDynamicTimeZoneInformation function to set the time zone information (with enable/disable daylight saving time), under Vista/Win7 or up, you may see code snippets below.
Now, the code seems to work okay, time zone information is updated correctly, but I have an weird issue with DynamicDaylightTimeDisabled flag. The time jumps is changed by one hour if the daylight option is changed; but when I set DynamicDaylightTimeDisabled to true, the checkbox "Automatically adjust clock for Daylight Saving Time" from Vista/Win7 Time Zone Settings dialog is still checked.

So, what I do wrong? Thanks.

type
  TRegTZI = record // a TZI registry value is 44 bytes in this order
    Bias, // 4 bytes
    StdBias, // 4 bytes
    DltBias: integer; // 4 bytes
    StdDate, // 16 bytes
    DltDate: TSystemTime; // 16 bytes
  end;

  TTZIData = record
    TZName: string;
    Display, Dlt, Std: string;
    RegTZI: TRegTZI;
  end;


implementation

    function TZIDtatToWinTDZI(ATZI: TTZIData; DDTDisabled: boolean): TIME_DYNAMIC_ZONE_INFORMATION;
    var
      WinTDZI: TIME_DYNAMIC_ZONE_INFORMATION;
    begin
      WinTDZI.Bias := ATZI.RegTZI.Bias;
      WinTDZI.StandardBias := ATZI.RegTZI.StdBias;
      WinTDZI.DaylightBias := ATZI.RegTZI.DltBias;
      if not DDTDisabled then
      begin
        WinTDZI.StandardDate := ATZI.RegTZI.StdDate;
        WinTDZI.DaylightDate := ATZI.RegTZI.DltDate;
      end;
      StringToWideChar(ATZI.Std, @WinTDZI.StandardName[0], 32);
      StringToWideChar(ATZI.Dlt, @WinTDZI.DaylightName[0], 32);
      StringToWideChar(ATZI.TZName, @WinTDZI.TimeZoneKeyName[0], 128);
      WinTDZI.DynamicDaylightTimeDisabled := DDTDisabled;
      Result := WinTDZI;
    end;

    function GetTZIDataByName(TZKeyName: string; var ATZI: TTZIData): boolean;
    var
      Reg: TRegistry;
      BiRecSize: integer; 
    begin
      Result := False;
      Reg := TRegistry.Create;
      try
        Reg.RootKey := HKEY_LOCAL_MACHINE;
        if Reg.OpenKey('Software\Microsoft\Windows NT\CurrentVersion\Time Zones\' + TZKeyName, False) then
        begin
          Result := True;
          ATZI.TZName := TZKeyName;
          if Reg.ValueExists('Display') then ATZI.Display := Reg.ReadString('Display');
          if Reg.ValueExists('Dlt') then ATZI.Dlt := Reg.ReadString('Dlt');
          if Reg.ValueExists('Std') then ATZI.Std := Reg.ReadString('Std');
          if Reg.ValueExists('TZI') then BiRecSize := Reg.ReadBinaryData('TZI', ATZI.RegTZI, SizeOf(ATZI.RegTZI));
          Reg.CloseKey;
        end;
      finally
        Reg.free;
      end;
    end;


    function Vista_SetTimeZone(TZKeyName: string; AutoAdjustEnabled: boolean;
      var ErrStr: string): boolean;
    var
      ATZI: TTZIData;
      WinTDZI: TIME_DYNAMIC_ZONE_INFORMATION;
    begin
      if GetTZIDataByName(TZKeyName, ATZI) then
      begin
        WinTDZI := TZIDtatToWinTDZI(ATZI, not AutoAdjustEnabled);
        Result := SetDynamicTimeZoneInformation (WinTDZI) <> 0;
        if Result then
          SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0);
      end;
    end;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文