[2/2] kernel32: Implement GetTimeZoneInformationForYear.

Vincent Povirk madewokherd at gmail.com
Fri Jan 29 14:31:27 CST 2016


From: Vincent Povirk <vincent at codeweavers.com>

Signed-off-by: Vincent Povirk <vincent at codeweavers.com>
---
 dlls/kernel32/kernel32.spec |   2 +-
 dlls/kernel32/tests/time.c  |   2 +-
 dlls/kernel32/time.c        | 196 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 198 insertions(+), 2 deletions(-)

diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
index 9171558..b0a6361 100644
--- a/dlls/kernel32/kernel32.spec
+++ b/dlls/kernel32/kernel32.spec
@@ -860,7 +860,7 @@
 @ stdcall GetTimeFormatEx(wstr long ptr wstr ptr long)
 @ stdcall GetTimeFormatW(long long ptr wstr ptr long)
 @ stdcall GetTimeZoneInformation(ptr)
-# @ stub GetTimeZoneInformationForYear
+@ stdcall GetTimeZoneInformationForYear(long ptr ptr)
 @ stdcall GetThreadUILanguage()
 # @ stub GetUILanguageInfo
 # @ stub -arch=x86_64 GetUmsCompletionListEvent
diff --git a/dlls/kernel32/tests/time.c b/dlls/kernel32/tests/time.c
index cd100f2..53af39c 100644
--- a/dlls/kernel32/tests/time.c
+++ b/dlls/kernel32/tests/time.c
@@ -921,7 +921,7 @@ static void test_GetTimeZoneInformationForYear(void)
 
     if (!pGetTimeZoneInformationForYear || !pGetDynamicTimeZoneInformation)
     {
-        todo_wine win_skip("GetTimeZoneInformationForYear not available\n");
+        win_skip("GetTimeZoneInformationForYear not available\n");
         return;
     }
 
diff --git a/dlls/kernel32/time.c b/dlls/kernel32/time.c
index ac39fde..18204b3 100644
--- a/dlls/kernel32/time.c
+++ b/dlls/kernel32/time.c
@@ -282,6 +282,178 @@ static BOOL TIME_GetTimezoneBias( const TIME_ZONE_INFORMATION *pTZinfo,
     return TRUE;
 }
 
+/***********************************************************************
+ *  TIME_GetSpecificTimeZoneKey
+ *
+ *  Opens the registry key for the time zone with the given name.
+ *
+ * PARAMS
+ *  key_name   [in]  The time zone name.
+ *  result     [out] The open registry key handle.
+ *
+ * RETURNS
+ *  TRUE if successful.
+ */
+static BOOL TIME_GetSpecificTimeZoneKey( const WCHAR *key_name, HANDLE *result )
+{
+    static const WCHAR Time_ZonesW[] = { 'M','a','c','h','i','n','e','\\',
+        'S','o','f','t','w','a','r','e','\\',
+        'M','i','c','r','o','s','o','f','t','\\',
+        'W','i','n','d','o','w','s',' ','N','T','\\',
+        'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
+        'T','i','m','e',' ','Z','o','n','e','s',0 };
+    HANDLE time_zones_key;
+    OBJECT_ATTRIBUTES attr;
+    UNICODE_STRING nameW;
+    NTSTATUS status;
+
+    attr.Length = sizeof(attr);
+    attr.RootDirectory = 0;
+    attr.ObjectName = &nameW;
+    attr.Attributes = 0;
+    attr.SecurityDescriptor = NULL;
+    attr.SecurityQualityOfService = NULL;
+    RtlInitUnicodeString( &nameW, Time_ZonesW );
+    status = NtOpenKey( &time_zones_key, KEY_READ, &attr );
+    if (status)
+    {
+        WARN("Unable to open the time zones key\n");
+        SetLastError( RtlNtStatusToDosError(status) );
+        return FALSE;
+    }
+
+    attr.RootDirectory = time_zones_key;
+    RtlInitUnicodeString( &nameW, key_name );
+    status = NtOpenKey( result, KEY_READ, &attr );
+
+    NtClose( time_zones_key );
+
+    if (status)
+    {
+        SetLastError( RtlNtStatusToDosError(status) );
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static BOOL reg_query_value(HKEY hkey, LPCWSTR name, DWORD type, void *data, DWORD count)
+{
+    UNICODE_STRING nameW;
+    char buf[256];
+    KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buf;
+    NTSTATUS status;
+
+    if (count > sizeof(buf) - sizeof(KEY_VALUE_PARTIAL_INFORMATION))
+        return FALSE;
+
+    RtlInitUnicodeString(&nameW, name);
+
+    if ((status = NtQueryValueKey(hkey, &nameW, KeyValuePartialInformation,
+                                  buf, sizeof(buf), &count)))
+    {
+        SetLastError( RtlNtStatusToDosError(status) );
+        return FALSE;
+    }
+
+    if (info->Type != type)
+    {
+        SetLastError( ERROR_DATATYPE_MISMATCH );
+        return FALSE;
+    }
+
+    memcpy(data, info->Data, info->DataLength);
+    return TRUE;
+}
+
+/***********************************************************************
+ *  TIME_GetSpecificTimeZoneInfo
+ *
+ *  Returns time zone information for the given time zone and year.
+ *
+ * PARAMS
+ *  key_name   [in]  The time zone name.
+ *  year       [in]  The year, if Dynamic DST is used.
+ *  dynamic    [in]  Whether to use Dynamic DST.
+ *  result     [out] The time zone information.
+ *
+ * RETURNS
+ *  TRUE if successful.
+ */
+static BOOL TIME_GetSpecificTimeZoneInfo( const WCHAR *key_name, WORD year,
+    BOOL dynamic, DYNAMIC_TIME_ZONE_INFORMATION *tzinfo )
+{
+    static const WCHAR Dynamic_DstW[] = { 'D','y','n','a','m','i','c',' ','D','S','T',0 };
+    static const WCHAR fmtW[] = { '%','d',0 };
+    static const WCHAR stdW[] = { 'S','t','d',0 };
+    static const WCHAR dltW[] = { 'D','l','t',0 };
+    static const WCHAR tziW[] = { 'T','Z','I',0 };
+    HANDLE time_zone_key, dynamic_dst_key;
+    OBJECT_ATTRIBUTES attr;
+    UNICODE_STRING nameW;
+    WCHAR yearW[16];
+    BOOL got_reg_data = FALSE;
+    struct tz_reg_data
+    {
+        LONG bias;
+        LONG std_bias;
+        LONG dlt_bias;
+        SYSTEMTIME std_date;
+        SYSTEMTIME dlt_date;
+    } tz_data;
+
+    if (!TIME_GetSpecificTimeZoneKey( key_name, &time_zone_key ))
+        return FALSE;
+
+    if (!reg_query_value( time_zone_key, stdW, REG_SZ, tzinfo->StandardName, sizeof(tzinfo->StandardName)) ||
+        !reg_query_value( time_zone_key, dltW, REG_SZ, tzinfo->DaylightName, sizeof(tzinfo->DaylightName)))
+    {
+        NtClose( time_zone_key );
+        return FALSE;
+    }
+
+    lstrcpyW(tzinfo->TimeZoneKeyName, key_name);
+
+    if (dynamic)
+    {
+        attr.Length = sizeof(attr);
+        attr.RootDirectory = time_zone_key;
+        attr.ObjectName = &nameW;
+        attr.Attributes = 0;
+        attr.SecurityDescriptor = NULL;
+        attr.SecurityQualityOfService = NULL;
+        RtlInitUnicodeString( &nameW, Dynamic_DstW );
+        if (!NtOpenKey( &dynamic_dst_key, KEY_READ, &attr ))
+        {
+            sprintfW( yearW, fmtW, year );
+            got_reg_data = reg_query_value( dynamic_dst_key, yearW, REG_BINARY, &tz_data, sizeof(tz_data) );
+
+            NtClose( dynamic_dst_key );
+        }
+    }
+
+    if (!got_reg_data)
+    {
+        if (!reg_query_value( time_zone_key, tziW, REG_BINARY, &tz_data, sizeof(tz_data) ))
+        {
+            NtClose( time_zone_key );
+            return FALSE;
+        }
+    }
+
+    tzinfo->Bias = tz_data.bias;
+    tzinfo->StandardBias = tz_data.std_bias;
+    tzinfo->DaylightBias = tz_data.dlt_bias;
+    tzinfo->StandardDate = tz_data.std_date;
+    tzinfo->DaylightDate = tz_data.dlt_date;
+
+    tzinfo->DynamicDaylightTimeDisabled = !dynamic;
+
+    NtClose( time_zone_key );
+
+    return TRUE;
+}
+
 
 /***********************************************************************
  *              SetLocalTime            (KERNEL32.@)
@@ -418,6 +590,30 @@ DWORD WINAPI GetTimeZoneInformation( LPTIME_ZONE_INFORMATION tzinfo )
 }
 
 /***********************************************************************
+ *              GetTimeZoneInformationForYear  (KERNEL32.@)
+ */
+BOOL WINAPI GetTimeZoneInformationForYear( USHORT wYear,
+    PDYNAMIC_TIME_ZONE_INFORMATION pdtzi, LPTIME_ZONE_INFORMATION ptzi )
+{
+    DYNAMIC_TIME_ZONE_INFORMATION local_dtzi, result;
+
+    if (!pdtzi)
+    {
+        if (GetDynamicTimeZoneInformation(&local_dtzi) == TIME_ZONE_ID_INVALID)
+            return FALSE;
+        pdtzi = &local_dtzi;
+    }
+
+    if (!TIME_GetSpecificTimeZoneInfo(pdtzi->TimeZoneKeyName, wYear,
+            !pdtzi->DynamicDaylightTimeDisabled, &result))
+        return FALSE;
+
+    memcpy(ptzi, &result, sizeof(*ptzi));
+
+    return TRUE;
+}
+
+/***********************************************************************
  *              SetTimeZoneInformation  (KERNEL32.@)
  *
  *  Change the settings of the current local time zone.
-- 
2.5.0




More information about the wine-patches mailing list