Signed-off-by: Daniel Lehman dlehman25@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_ */
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=48259
Your paranoid android.
=== wxppro (32 bit report) ===
kernelbase: time: Timeout