[PATCH] advapi32: Implement EnumDynamicTimeZoneInformation.

Daniel Lehman dlehman25 at gmail.com
Tue Feb 26 01:54:04 CST 2019


Signed-off-by: Daniel Lehman <dlehman25 at gmail.com>
---
 dlls/advapi32/advapi32.spec                   |   2 +-
 .../api-ms-win-core-timezone-l1-1-0.spec      |   2 +-
 dlls/kernelbase/kernelbase.spec               |   2 +-
 dlls/kernelbase/main.c                        | 115 ++++++++++++
 dlls/kernelbase/tests/Makefile.in             |   4 +-
 dlls/kernelbase/tests/time.c                  | 168 ++++++++++++++++++
 include/timezoneapi.h                         |  32 ++++
 7 files changed, 321 insertions(+), 4 deletions(-)
 create mode 100644 dlls/kernelbase/tests/time.c
 create mode 100644 include/timezoneapi.h

diff --git a/dlls/advapi32/advapi32.spec b/dlls/advapi32/advapi32.spec
index e870a5d3e2..038467ec1d 100644
--- a/dlls/advapi32/advapi32.spec
+++ b/dlls/advapi32/advapi32.spec
@@ -272,7 +272,7 @@
 # @ stub EncryptionDisable
 @ stdcall EnumDependentServicesA(long long ptr long ptr ptr)
 @ stdcall EnumDependentServicesW(long long ptr long ptr ptr)
-# @ stub EnumDynamicTimeZoneInformation
+@ stdcall EnumDynamicTimeZoneInformation(long ptr) kernelbase.EnumDynamicTimeZoneInformation
 @ stub EnumServiceGroupA
 @ stub EnumServiceGroupW
 @ stdcall EnumServicesStatusA (long long long ptr long ptr ptr ptr)
diff --git a/dlls/api-ms-win-core-timezone-l1-1-0/api-ms-win-core-timezone-l1-1-0.spec b/dlls/api-ms-win-core-timezone-l1-1-0/api-ms-win-core-timezone-l1-1-0.spec
index 3e38d70596..0f42eda5d8 100644
--- a/dlls/api-ms-win-core-timezone-l1-1-0/api-ms-win-core-timezone-l1-1-0.spec
+++ b/dlls/api-ms-win-core-timezone-l1-1-0/api-ms-win-core-timezone-l1-1-0.spec
@@ -1,4 +1,4 @@
-@ stub EnumDynamicTimeZoneInformation
+@ stdcall EnumDynamicTimeZoneInformation(long ptr) kernelbase.EnumDynamicTimeZoneInformation
 @ stdcall FileTimeToSystemTime(ptr ptr) kernel32.FileTimeToSystemTime
 @ stdcall GetDynamicTimeZoneInformation(ptr) kernel32.GetDynamicTimeZoneInformation
 @ stdcall GetDynamicTimeZoneInformationEffectiveYears(ptr ptr ptr) kernel32.GetDynamicTimeZoneInformationEffectiveYears
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec
index 45b375ce2f..bea57303df 100644
--- a/dlls/kernelbase/kernelbase.spec
+++ b/dlls/kernelbase/kernelbase.spec
@@ -297,7 +297,7 @@
 @ stdcall EnumDateFormatsExW(ptr long long) kernel32.EnumDateFormatsExW
 @ stdcall EnumDateFormatsW(ptr long long) kernel32.EnumDateFormatsW
 # @ stub EnumDeviceDrivers
-# @ stub EnumDynamicTimeZoneInformation
+@ stdcall EnumDynamicTimeZoneInformation(long ptr)
 @ stdcall EnumLanguageGroupLocalesW(ptr long long ptr) kernel32.EnumLanguageGroupLocalesW
 # @ stub EnumPageFilesA
 # @ stub EnumPageFilesW
diff --git a/dlls/kernelbase/main.c b/dlls/kernelbase/main.c
index 5192dfb3f2..2823e977c0 100644
--- a/dlls/kernelbase/main.c
+++ b/dlls/kernelbase/main.c
@@ -125,3 +125,118 @@ BOOL WINAPI WaitOnAddress(volatile void *addr, void *cmp, SIZE_T size, DWORD tim
 
     return TRUE;
 }
+
+static NTSTATUS reg_query_value(HKEY hkey, const WCHAR *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;
+
+    RtlInitUnicodeString( &nameW, name );
+    if ((status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
+                                   buf, sizeof(buf), &count )))
+        return status;
+
+    if (info->Type != type)
+        return ERROR_DATATYPE_MISMATCH;
+
+    memcpy( data, info->Data, info->DataLength );
+    return STATUS_SUCCESS;
+}
+
+/******************************************************************************
+ *           EnumDynamicTimeZoneInformation   (KERNELBASE.@)
+ */
+DWORD WINAPI EnumDynamicTimeZoneInformation(const DWORD index,
+    DYNAMIC_TIME_ZONE_INFORMATION *dtzi)
+{
+    static const WCHAR Time_ZonesW[] = { '\\','R','E','G','I','S','T','R','Y','\\',
+        '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 };
+    static const WCHAR stdW[] = {'S','t','d',0};
+    static const WCHAR dltW[] = {'D','l','t',0};
+    static const WCHAR tziW[] = {'T','Z','I',0};
+    char node_buf[sizeof(KEY_NODE_INFORMATION) + ARRAY_SIZE(dtzi->TimeZoneKeyName)];
+    KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)node_buf;
+    HANDLE time_zones_key, sub_key;
+    OBJECT_ATTRIBUTES attr;
+    UNICODE_STRING nameW;
+    DWORD size;
+    NTSTATUS status;
+    struct tz_reg_data
+    {
+        LONG bias;
+        LONG std_bias;
+        LONG dlt_bias;
+        SYSTEMTIME std_date;
+        SYSTEMTIME dlt_date;
+    } tz_data;
+
+    if (!dtzi)
+        return ERROR_INVALID_PARAMETER;
+
+    attr.Length = sizeof(attr);
+    attr.RootDirectory = 0;
+    attr.ObjectName = &nameW;
+    attr.Attributes = 0;
+    attr.SecurityDescriptor = NULL;
+    attr.SecurityQualityOfService = NULL;
+    RtlInitUnicodeString( &nameW, Time_ZonesW );
+    status = NtOpenKeyEx( &time_zones_key, KEY_READ, &attr, KEY_ENUMERATE_SUB_KEYS );
+    if (status) return RtlNtStatusToDosError( status );
+
+    status = NtEnumerateKey( time_zones_key, index, KeyNodeInformation,
+                             node_buf, sizeof(node_buf), &size );
+    if (status)
+    {
+        NtClose( time_zones_key );
+        return RtlNtStatusToDosError( status );
+    }
+
+    attr.RootDirectory = time_zones_key;
+    info->Name[info->NameLength / sizeof(WCHAR)] = 0;
+    RtlInitUnicodeString( &nameW, info->Name );
+    status = NtOpenKeyEx( &sub_key, KEY_READ, &attr, KEY_QUERY_VALUE );
+    if (status)
+    {
+        NtClose( time_zones_key );
+        return RtlNtStatusToDosError( status );
+    }
+
+    status = reg_query_value( sub_key, stdW, REG_SZ,
+                              dtzi->StandardName, sizeof(dtzi->StandardName) );
+    if (status)
+        goto done;
+
+    status = reg_query_value( sub_key, dltW, REG_SZ,
+                              dtzi->DaylightName, sizeof(dtzi->DaylightName) );
+    if (status)
+        goto done;
+
+    status = reg_query_value( sub_key, tziW, REG_BINARY, &tz_data, sizeof(tz_data) );
+    if (status)
+        goto done;
+
+    dtzi->Bias = tz_data.bias;
+    dtzi->StandardBias = tz_data.std_bias;
+    dtzi->DaylightBias = tz_data.dlt_bias;
+    memcpy( &dtzi->StandardDate, &tz_data.std_date, sizeof(tz_data.std_date) );
+    memcpy( &dtzi->DaylightDate, &tz_data.dlt_date, sizeof(tz_data.dlt_date) );
+    lstrcpyW( dtzi->TimeZoneKeyName, info->Name );
+    dtzi->DynamicDaylightTimeDisabled = FALSE;
+
+    status = STATUS_SUCCESS;
+
+done:
+    NtClose( sub_key );
+    NtClose( time_zones_key );
+
+    SetLastError( RtlNtStatusToDosError( status ) );
+    return 0;
+}
diff --git a/dlls/kernelbase/tests/Makefile.in b/dlls/kernelbase/tests/Makefile.in
index 22e4a17a58..19d7792f86 100644
--- a/dlls/kernelbase/tests/Makefile.in
+++ b/dlls/kernelbase/tests/Makefile.in
@@ -1,5 +1,7 @@
 TESTDLL   = kernelbase.dll
+IMPORTS   = advapi32
 
 C_SRCS = \
 	path.c \
-	sync.c
+	sync.c \
+	time.c
diff --git a/dlls/kernelbase/tests/time.c b/dlls/kernelbase/tests/time.c
new file mode 100644
index 0000000000..de61c5795b
--- /dev/null
+++ b/dlls/kernelbase/tests/time.c
@@ -0,0 +1,168 @@
+/*
+ * Time tests
+ *
+ * Copyright 2019 Daniel Lehman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+#include <windef.h>
+#include <winbase.h>
+#include <winreg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <winerror.h>
+
+#include "wine/test.h"
+
+static DWORD (WINAPI *pEnumDynamicTimeZoneInformation)(const DWORD,
+                                                       DYNAMIC_TIME_ZONE_INFORMATION*);
+
+static const char *printSystemTime(const SYSTEMTIME *st)
+{
+    static int index;
+    static char buf[2][64];
+
+    index++;
+    index %= ARRAY_SIZE(buf);
+    snprintf(buf[index], ARRAY_SIZE(buf[0]), "%02d-%02d-%04d %02d:%02d:%02d.%03d",
+             st->wMonth, st->wDay, st->wYear,
+             st->wHour, st->wMinute, st->wSecond, st->wMilliseconds);
+    return buf[index];
+}
+
+static void test_EnumDynamicTimeZoneInformation(void)
+{
+    HKEY hkey;
+    WCHAR stdname[32];
+    WCHAR dltname[32];
+    WCHAR keyname[128];
+    DWORD index, gle, ret, size;
+    static const WCHAR stdW[] = {'S','t','d',0};
+    static const WCHAR dltW[] = {'D','l','t',0};
+    static const WCHAR tziW[] = {'T','Z','I',0};
+    static const WCHAR volgogradW[] = {'V','o','l','g','o','g','r','a','d'};
+    DYNAMIC_TIME_ZONE_INFORMATION bogus_dtzi;
+    DYNAMIC_TIME_ZONE_INFORMATION dtzi;
+    struct tz_reg_data
+    {
+        LONG bias;
+        LONG std_bias;
+        LONG dlt_bias;
+        SYSTEMTIME std_date;
+        SYSTEMTIME dlt_date;
+    } tz_data;
+
+    if (!pEnumDynamicTimeZoneInformation)
+    {
+        win_skip("EnumDynamicTimeZoneInformation is not supported.\n");
+        return;
+    }
+
+    SetLastError(0xdeadbeef);
+    ret = pEnumDynamicTimeZoneInformation(0, NULL);
+    gle = GetLastError();
+    ok(gle == 0xdeadbeef, "got 0x%x\n", gle);
+    ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret);
+
+    memset(&bogus_dtzi, 0xcc, sizeof(bogus_dtzi));
+    memset(&dtzi, 0xcc, sizeof(dtzi));
+    SetLastError(0xdeadbeef);
+    ret = pEnumDynamicTimeZoneInformation(-1, &dtzi);
+    gle = GetLastError();
+    ok(gle == 0xdeadbeef, "got 0x%x\n", gle);
+    ok(ret == ERROR_NO_MORE_ITEMS, "got %d\n", ret);
+    ok(!memcmp(&dtzi, &bogus_dtzi, sizeof(dtzi)), "mismatch\n");
+
+    ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
+            "Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 0,
+            KEY_ENUMERATE_SUB_KEYS, &hkey);
+    ok(ret == ERROR_SUCCESS, "got %d\n", ret);
+
+    index = 0;
+    while (!(ret = RegEnumKeyW(hkey, index, keyname, sizeof(keyname))))
+    {
+        memset(&dtzi, 0xcc, sizeof(dtzi));
+        SetLastError(0xdeadbeef);
+        ret = pEnumDynamicTimeZoneInformation(index, &dtzi);
+        gle = GetLastError();
+        ok(gle == ERROR_SUCCESS ||
+           (!memcmp(keyname, volgogradW, sizeof(volgogradW)) && gle == ERROR_MUI_FILE_NOT_FOUND),
+           "got 0x%x for %s\n", gle, wine_dbgstr_w(keyname));
+        ok(!ret, "got %d\n", ret);
+
+        ok(!dtzi.DynamicDaylightTimeDisabled, "got %d\n", dtzi.DynamicDaylightTimeDisabled);
+
+        ok(!lstrcmpW(dtzi.TimeZoneKeyName, keyname), "expected %s, got %s\n",
+            wine_dbgstr_w(dtzi.TimeZoneKeyName), wine_dbgstr_w(keyname));
+
+        size = sizeof(stdname);
+        ret = RegGetValueW(hkey, keyname, stdW, RRF_RT_REG_SZ, NULL, stdname, &size);
+        ok(ret == ERROR_SUCCESS, "got %d\n", ret);
+        ok(!memcmp(&dtzi.StandardName, stdname, size) ||
+            broken(!memcmp(stdname, volgogradW, sizeof(volgogradW))), /* Windows 10 */
+            "expected %s, got %s\n", wine_dbgstr_w(dtzi.StandardName), wine_dbgstr_w(stdname));
+
+        size = sizeof(dltname);
+        ret = RegGetValueW(hkey, keyname, dltW, RRF_RT_REG_SZ, NULL, dltname, &size);
+        ok(ret == ERROR_SUCCESS, "got %d\n", ret);
+        ok(!memcmp(&dtzi.DaylightName, dltname, size) ||
+            broken(!memcmp(stdname, volgogradW, sizeof(volgogradW))), /* Windows 10 */
+            "expected %s, got %s\n", wine_dbgstr_w(dtzi.DaylightName), wine_dbgstr_w(dltname));
+
+        size = sizeof(tz_data);
+        ret = RegGetValueW(hkey, keyname, tziW, RRF_RT_REG_BINARY, NULL, &tz_data, &size);
+        ok(ret == ERROR_SUCCESS, "got %d\n", ret);
+
+        ok(dtzi.Bias == tz_data.bias, "expected %d, got %d\n",
+            dtzi.Bias, tz_data.bias);
+        ok(dtzi.StandardBias == tz_data.std_bias, "expected %d, got %d\n",
+            dtzi.StandardBias, tz_data.std_bias);
+        ok(dtzi.DaylightBias == tz_data.dlt_bias, "expected %d, got %d\n",
+            dtzi.DaylightBias, tz_data.dlt_bias);
+
+        ok(!memcmp(&dtzi.StandardDate, &tz_data.std_date, sizeof(dtzi.StandardDate)),
+            "expected %s, got %s\n",
+            printSystemTime(&dtzi.StandardDate), printSystemTime(&tz_data.std_date));
+
+        ok(!memcmp(&dtzi.DaylightDate, &tz_data.dlt_date, sizeof(dtzi.DaylightDate)),
+            "expected %s, got %s\n",
+            printSystemTime(&dtzi.DaylightDate), printSystemTime(&tz_data.dlt_date));
+
+        index++;
+    }
+    ok(ret == ERROR_NO_MORE_ITEMS, "got %d\n", ret);
+
+    memset(&dtzi, 0xcc, sizeof(dtzi));
+    SetLastError(0xdeadbeef);
+    ret = pEnumDynamicTimeZoneInformation(index, &dtzi);
+    gle = GetLastError();
+    ok(gle == 0xdeadbeef, "got 0x%x\n", gle);
+    ok(ret == ERROR_NO_MORE_ITEMS, "got %d\n", ret);
+    ok(!memcmp(&dtzi, &bogus_dtzi, sizeof(dtzi)), "mismatch\n");
+
+    RegCloseKey(hkey);
+}
+
+START_TEST(time)
+{
+    HMODULE hmod;
+
+    hmod = LoadLibraryA("kernelbase.dll");
+    pEnumDynamicTimeZoneInformation = (void *)GetProcAddress(hmod, "EnumDynamicTimeZoneInformation");
+
+    test_EnumDynamicTimeZoneInformation();
+}
diff --git a/include/timezoneapi.h b/include/timezoneapi.h
new file mode 100644
index 0000000000..0bba897718
--- /dev/null
+++ b/include/timezoneapi.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 Daniel Lehman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _APISETTIMEZONE_
+#define _APISETTIMEZONE_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+WINBASEAPI DWORD WINAPI EnumDynamicTimeZoneInformation(const DWORD, DYNAMIC_TIME_ZONE_INFORMATION *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* _APISETTIMEZONE_ */
-- 
2.17.1




More information about the wine-devel mailing list