[PATCH v4] advapi32: Implement EnumDynamicTimeZoneInformation.

Daniel Lehman dlehman25 at gmail.com
Fri May 24 23:21:35 CDT 2019


Signed-off-by: Daniel Lehman <dlehman25 at gmail.com>

---
v4:
- move to advapi32
v3:
- fix subject line
v2:
- return MUI strings (borrows from kernel32:TIME_GetSpecificTimeZoneInfo)
- current test bots with languages are on Vista, which doesn't support EnumDynamicTimeZoneInformation
  tested manually with Spanish locale on Windows 10 1809
---
 dlls/advapi32/advapi32.spec                   |   2 +-
 dlls/advapi32/registry.c                      |  64 ++++++++
 dlls/advapi32/tests/registry.c                | 154 ++++++++++++++++++
 .../api-ms-win-core-timezone-l1-1-0.spec      |   2 +-
 dlls/kernelbase/kernelbase.spec               |   2 +-
 include/timezoneapi.h                         |  32 ++++
 6 files changed, 253 insertions(+), 3 deletions(-)
 create mode 100644 include/timezoneapi.h

diff --git a/dlls/advapi32/advapi32.spec b/dlls/advapi32/advapi32.spec
index 91d6750658..a97161fa27 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) EnumDynamicTimeZoneInformation
 @ stub EnumServiceGroupA
 @ stub EnumServiceGroupW
 @ stdcall EnumServicesStatusA (long long long ptr long ptr ptr ptr)
diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c
index f889d3b0e5..c7c5b033a1 100644
--- a/dlls/advapi32/registry.c
+++ b/dlls/advapi32/registry.c
@@ -3578,3 +3578,67 @@ LSTATUS WINAPI RegLoadAppKeyW(const WCHAR *file, HKEY *result, REGSAM sam, DWORD
     *result = (HKEY)0xdeadbeef;
     return ERROR_SUCCESS;
 }
+
+/******************************************************************************
+ *           EnumDynamicTimeZoneInformation   (ADVAPI32.@)
+ */
+DWORD WINAPI EnumDynamicTimeZoneInformation(const DWORD index,
+    DYNAMIC_TIME_ZONE_INFORMATION *dtzi)
+{
+    static const WCHAR mui_stdW[] = { 'M','U','I','_','S','t','d',0 };
+    static const WCHAR mui_dltW[] = { 'M','U','I','_','D','l','t',0 };
+    WCHAR keyname[ARRAY_SIZE(dtzi->TimeZoneKeyName)];
+    HKEY time_zones_key, sub_key;
+    WCHAR sysdir[MAX_PATH];
+    LSTATUS ret;
+    DWORD size;
+    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;
+
+    ret = RegOpenKeyExA( HKEY_LOCAL_MACHINE,
+                "Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 0,
+                KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE, &time_zones_key );
+    if (ret) return ret;
+
+    sub_key = NULL;
+    ret = RegEnumKeyW( time_zones_key, index, keyname, ARRAY_SIZE(keyname) );
+    if (ret) goto cleanup;
+
+    ret = RegOpenKeyExW( time_zones_key, keyname, 0, KEY_QUERY_VALUE, &sub_key );
+    if (ret) goto cleanup;
+
+    GetSystemDirectoryW(sysdir, ARRAY_SIZE(sysdir));
+    size = sizeof(dtzi->StandardName);
+    ret = RegLoadMUIStringW( sub_key, mui_stdW, dtzi->StandardName, size, NULL, 0, sysdir );
+    if (ret) goto cleanup;
+
+    size = sizeof(dtzi->DaylightName);
+    ret = RegLoadMUIStringW( sub_key, mui_dltW, dtzi->DaylightName, size, NULL, 0, sysdir );
+    if (ret) goto cleanup;
+
+    size = sizeof(tz_data);
+    ret = RegQueryValueExA( sub_key, "TZI", NULL, NULL, (BYTE*)&tz_data, &size );
+    if (ret) goto cleanup;
+
+    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, keyname );
+    dtzi->DynamicDaylightTimeDisabled = FALSE;
+
+cleanup:
+    if (sub_key) RegCloseKey( sub_key );
+    RegCloseKey( time_zones_key );
+    return ret;
+}
diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c
index c178e39f85..9c5150853f 100644
--- a/dlls/advapi32/tests/registry.c
+++ b/dlls/advapi32/tests/registry.c
@@ -42,6 +42,7 @@ static const char * sTestpath2 = "%FOO%\\subdir1";
 static const DWORD ptr_size = 8 * sizeof(void*);
 
 static DWORD (WINAPI *pRegGetValueA)(HKEY,LPCSTR,LPCSTR,DWORD,LPDWORD,PVOID,LPDWORD);
+static DWORD (WINAPI *pRegGetValueW)(HKEY,LPCWSTR,LPCWSTR,DWORD,LPDWORD,PVOID,LPDWORD);
 static LONG (WINAPI *pRegCopyTreeA)(HKEY,const char *,HKEY);
 static LONG (WINAPI *pRegDeleteTreeA)(HKEY,const char *);
 static DWORD (WINAPI *pRegDeleteKeyExA)(HKEY,LPCSTR,REGSAM,DWORD);
@@ -53,6 +54,8 @@ static LONG (WINAPI *pRegDeleteKeyValueA)(HKEY,LPCSTR,LPCSTR);
 static LONG (WINAPI *pRegSetKeyValueW)(HKEY,LPCWSTR,LPCWSTR,DWORD,const void*,DWORD);
 static LONG (WINAPI *pRegLoadMUIStringA)(HKEY,LPCSTR,LPSTR,DWORD,LPDWORD,DWORD,LPCSTR);
 static LONG (WINAPI *pRegLoadMUIStringW)(HKEY,LPCWSTR,LPWSTR,DWORD,LPDWORD,DWORD,LPCWSTR);
+static DWORD (WINAPI *pEnumDynamicTimeZoneInformation)(const DWORD,
+                                                       DYNAMIC_TIME_ZONE_INFORMATION*);
 
 static BOOL limited_user;
 
@@ -128,6 +131,18 @@ static const char *wine_debugstr_an( const char *str, int n )
     return res;
 }
 
+static const char *dbgstr_SYSTEMTIME(const SYSTEMTIME *st)
+{
+    static int index;
+    static char buf[2][64];
+
+    index %= ARRAY_SIZE(buf);
+    sprintf(buf[index], "%02d-%02d-%04d %02d:%02d:%02d.%03d",
+            st->wMonth, st->wDay, st->wYear,
+            st->wHour, st->wMinute, st->wSecond, st->wMilliseconds);
+    return buf[index++];
+}
+
 #define ADVAPI32_GET_PROC(func) \
     p ## func = (void*)GetProcAddress(hadvapi32, #func)
 
@@ -139,6 +154,7 @@ static void InitFunctionPtrs(void)
 
     /* This function was introduced with Windows 2003 SP1 */
     ADVAPI32_GET_PROC(RegGetValueA);
+    ADVAPI32_GET_PROC(RegGetValueW);
     ADVAPI32_GET_PROC(RegCopyTreeA);
     ADVAPI32_GET_PROC(RegDeleteTreeA);
     ADVAPI32_GET_PROC(RegDeleteKeyExA);
@@ -146,6 +162,7 @@ static void InitFunctionPtrs(void)
     ADVAPI32_GET_PROC(RegSetKeyValueW);
     ADVAPI32_GET_PROC(RegLoadMUIStringA);
     ADVAPI32_GET_PROC(RegLoadMUIStringW);
+    ADVAPI32_GET_PROC(EnumDynamicTimeZoneInformation);
 
     pIsWow64Process = (void *)GetProcAddress( hkernel32, "IsWow64Process" );
     pRtlFormatCurrentUserKeyPath = (void *)GetProcAddress( hntdll, "RtlFormatCurrentUserKeyPath" );
@@ -3958,6 +3975,142 @@ static void test_RegLoadMUIString(void)
     SetCurrentDirectoryW(curdirW);
 }
 
+static void test_EnumDynamicTimeZoneInformation(void)
+{
+    LSTATUS status;
+    HKEY key, subkey;
+    WCHAR name[32];
+    WCHAR keyname[128];
+    WCHAR sysdir[MAX_PATH];
+    DWORD index, ret, gle, size;
+    DYNAMIC_TIME_ZONE_INFORMATION bogus_dtzi, dtzi;
+    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 mui_stdW[] = {'M','U','I','_','S','t','d',0};
+    static const WCHAR mui_dltW[] = {'M','U','I','_','D','l','t',0};
+    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;
+    }
+
+    if (pRegLoadMUIStringW)
+        GetSystemDirectoryW(sysdir, ARRAY_SIZE(sysdir));
+
+    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");
+
+    status = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
+            "Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 0,
+            KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE, &key);
+    ok(status == ERROR_SUCCESS, "got %d\n", status);
+    index = 0;
+    while (!(status = RegEnumKeyW(key, index, keyname, ARRAY_SIZE(keyname))))
+    {
+        subkey = NULL;
+        status = RegOpenKeyExW(key, keyname, 0, KEY_QUERY_VALUE, &subkey);
+        ok(status == ERROR_SUCCESS, "got %d\n", status);
+
+        memset(&dtzi, 0xcc, sizeof(dtzi));
+        SetLastError(0xdeadbeef);
+        ret = pEnumDynamicTimeZoneInformation(index, &dtzi);
+        gle = GetLastError();
+        /* recently added time zones may not have MUI strings */
+        ok(gle == ERROR_SUCCESS ||
+           gle == ERROR_RESOURCE_TYPE_NOT_FOUND /* Win10 1809 32-bit */ ||
+           gle == ERROR_MUI_FILE_NOT_FOUND /* Win10 1809 64-bit */,
+            "got 0x%x\n", gle);
+        ok(ret == ERROR_SUCCESS, "got %d\n", ret);
+        ok(!lstrcmpW(dtzi.TimeZoneKeyName, keyname), "expected %s, got %s\n",
+            wine_dbgstr_w(keyname), wine_dbgstr_w(dtzi.TimeZoneKeyName));
+
+        if (gle == ERROR_SUCCESS)
+        {
+            size = sizeof(name);
+            memset(name, 0, sizeof(name));
+            if (pRegLoadMUIStringW)
+                status = pRegLoadMUIStringW(subkey, mui_stdW, name, size, &size, 0, sysdir);
+            else
+                status = pRegGetValueW(subkey, NULL, stdW, RRF_RT_REG_SZ, NULL, name, &size);
+            ok(status == ERROR_SUCCESS, "status %d name %s\n", status, wine_dbgstr_w(name));
+            ok(!memcmp(&dtzi.StandardName, name, size),
+                "expected %s, got %s\n", wine_dbgstr_w(name), wine_dbgstr_w(dtzi.StandardName));
+
+            size = sizeof(name);
+            memset(name, 0, sizeof(name));
+            if (pRegLoadMUIStringW)
+                status = pRegLoadMUIStringW(subkey, mui_dltW, name, size, &size, 0, sysdir);
+            else
+                status = pRegGetValueW(subkey, NULL, dltW, RRF_RT_REG_SZ, NULL, name, &size);
+            ok(status == ERROR_SUCCESS, "status %d name %s\n", status, wine_dbgstr_w(name));
+            ok(!memcmp(&dtzi.DaylightName, name, size),
+                "expected %s, got %s\n", wine_dbgstr_w(name), wine_dbgstr_w(dtzi.DaylightName));
+        }
+        else
+        {
+            ok(!dtzi.StandardName[0], "expected empty StandardName\n");
+            ok(!dtzi.DaylightName[0], "expected empty DaylightName\n");
+        }
+
+        ok(!dtzi.DynamicDaylightTimeDisabled, "got %d\n", dtzi.DynamicDaylightTimeDisabled);
+
+        size = sizeof(tz_data);
+        status = pRegGetValueW(key, keyname, tziW, RRF_RT_REG_BINARY, NULL, &tz_data, &size);
+        ok(status == ERROR_SUCCESS, "got %d\n", status);
+
+        ok(dtzi.Bias == tz_data.bias, "expected %d, got %d\n",
+            tz_data.bias, dtzi.Bias);
+        ok(dtzi.StandardBias == tz_data.std_bias, "expected %d, got %d\n",
+            tz_data.std_bias, dtzi.StandardBias);
+        ok(dtzi.DaylightBias == tz_data.dlt_bias, "expected %d, got %d\n",
+            tz_data.dlt_bias, dtzi.DaylightBias);
+
+        ok(!memcmp(&dtzi.StandardDate, &tz_data.std_date, sizeof(dtzi.StandardDate)),
+            "expected %s, got %s\n",
+            dbgstr_SYSTEMTIME(&tz_data.std_date), dbgstr_SYSTEMTIME(&dtzi.StandardDate));
+
+        ok(!memcmp(&dtzi.DaylightDate, &tz_data.dlt_date, sizeof(dtzi.DaylightDate)),
+            "expected %s, got %s\n",
+            dbgstr_SYSTEMTIME(&tz_data.dlt_date), dbgstr_SYSTEMTIME(&dtzi.DaylightDate));
+
+        RegCloseKey(subkey);
+        index++;
+    }
+    ok(status == ERROR_NO_MORE_ITEMS, "got %d\n", status);
+
+    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(key);
+}
+
 START_TEST(registry)
 {
     /* Load pointers for functions that are not available in all Windows versions */
@@ -3995,6 +4148,7 @@ START_TEST(registry)
     test_RegNotifyChangeKeyValue();
     test_RegQueryValueExPerformanceData();
     test_RegLoadMUIString();
+    test_EnumDynamicTimeZoneInformation();
 
     /* cleanup */
     delete_key( hkey_main );
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..b25d121ad1 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) advapi32.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 24d7b1772b..d592920a54 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) advapi32.EnumDynamicTimeZoneInformation
 @ stdcall EnumLanguageGroupLocalesW(ptr long long ptr) kernel32.EnumLanguageGroupLocalesW
 # @ stub EnumPageFilesA
 # @ stub EnumPageFilesW
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