diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 4118d29b3db..87e31cf4574 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -655,8 +655,8 @@ @ stdcall GetDriveTypeW(wstr) # @ stub GetDurationFormat # @ stub GetDurationFormatEx -@ stdcall GetDynamicTimeZoneInformation(ptr) -@ stdcall GetDynamicTimeZoneInformationEffectiveYears(ptr ptr ptr) +@ stdcall -import GetDynamicTimeZoneInformation(ptr) +@ stdcall -import GetDynamicTimeZoneInformationEffectiveYears(ptr ptr ptr) @ stdcall -ret64 -arch=i386,x86_64 GetEnabledXStateFeatures() @ stdcall -import GetEnvironmentStrings() @ stdcall -import GetEnvironmentStringsA() @@ -866,8 +866,8 @@ @ stdcall GetTimeFormatA(long long ptr str ptr long) @ stdcall GetTimeFormatEx(wstr long ptr wstr ptr long) @ stdcall GetTimeFormatW(long long ptr wstr ptr long) -@ stdcall GetTimeZoneInformation(ptr) -@ stdcall GetTimeZoneInformationForYear(long ptr ptr) +@ stdcall -import GetTimeZoneInformation(ptr) +@ stdcall -import GetTimeZoneInformationForYear(long ptr ptr) # @ stub GetUILanguageInfo @ stdcall -arch=x86_64 GetUmsCompletionListEvent(ptr ptr) # @ stub -arch=x86_64 GetUmsSystemThreadInformation @@ -1467,7 +1467,7 @@ @ stdcall SetThreadpoolThreadMinimum(ptr long) ntdll.TpSetPoolMinThreads @ stdcall SetThreadpoolTimer(ptr ptr long long) ntdll.TpSetTimer @ stdcall SetThreadpoolWait(ptr long ptr) ntdll.TpSetWait -@ stdcall SetTimeZoneInformation(ptr) +@ stdcall -import SetTimeZoneInformation(ptr) @ stub SetTimerQueueTimer @ stdcall -arch=x86_64 SetUmsThreadInformation(ptr long ptr long) @ stdcall -import SetUnhandledExceptionFilter(ptr) @@ -1496,7 +1496,7 @@ @ stdcall -import SwitchToFiber(ptr) @ stdcall -import SwitchToThread() @ stdcall -import SystemTimeToFileTime(ptr ptr) -@ stdcall SystemTimeToTzSpecificLocalTime (ptr ptr ptr) +@ stdcall -import SystemTimeToTzSpecificLocalTime (ptr ptr ptr) # @ stub SystemTimeToTzSpecificLocalTimeEx @ stdcall TerminateJobObject(long long) @ stdcall -import TerminateProcess(long long) @@ -1519,7 +1519,7 @@ @ stdcall TryAcquireSRWLockShared(ptr) ntdll.RtlTryAcquireSRWLockShared @ stdcall TryEnterCriticalSection(ptr) ntdll.RtlTryEnterCriticalSection @ stdcall -import TrySubmitThreadpoolCallback(ptr ptr ptr) -@ stdcall TzSpecificLocalTimeToSystemTime(ptr ptr ptr) +@ stdcall -import TzSpecificLocalTimeToSystemTime(ptr ptr ptr) # @ stub TzSpecificLocalTimeToSystemTimeEx # @ stub -arch=x86_64 uaw_lstrcmpW # @ stub -arch=x86_64 uaw_lstrcmpiW diff --git a/dlls/kernel32/kernel_main.c b/dlls/kernel32/kernel_main.c index be355fe724f..cdbb4b9a386 100644 --- a/dlls/kernel32/kernel_main.c +++ b/dlls/kernel32/kernel_main.c @@ -89,9 +89,6 @@ static BOOL process_attach( HMODULE module ) NtQuerySystemInformation( SystemBasicInformation, &system_info, sizeof(system_info), NULL ); - /* Setup registry timezone information */ - TIMEZONE_InitRegistry(); - /* Setup computer name */ COMPUTERNAME_Init(); diff --git a/dlls/kernel32/kernel_private.h b/dlls/kernel32/kernel_private.h index 797b8809bdb..d845623265f 100644 --- a/dlls/kernel32/kernel_private.h +++ b/dlls/kernel32/kernel_private.h @@ -72,9 +72,6 @@ extern void ENV_CopyStartupInformation(void) DECLSPEC_HIDDEN; /* computername.c */ extern void COMPUTERNAME_Init(void) DECLSPEC_HIDDEN; -/* time.c */ -extern void TIMEZONE_InitRegistry(void) DECLSPEC_HIDDEN; - /* oldconfig.c */ extern void convert_old_config(void) DECLSPEC_HIDDEN; diff --git a/dlls/kernel32/time.c b/dlls/kernel32/time.c index 716230aa7a2..4ebdabf18c1 100644 --- a/dlls/kernel32/time.c +++ b/dlls/kernel32/time.c @@ -61,11 +61,6 @@ static inline void longlong_to_filetime( LONGLONG t, FILETIME *ft ) ft->dwHighDateTime = (DWORD)(t >> 32); } -static inline LONGLONG filetime_to_longlong( const FILETIME *ft ) -{ - return (((LONGLONG)ft->dwHighDateTime) << 32) + ft->dwLowDateTime; -} - #define TICKSPERSEC 10000000 #define TICKSPERMSEC 10000 @@ -97,390 +92,6 @@ static inline ULONGLONG monotonic_counter(void) return counter.QuadPart; } -static const WCHAR mui_stdW[] = { 'M','U','I','_','S','t','d',0 }; -static const WCHAR mui_dltW[] = { 'M','U','I','_','D','l','t',0 }; - -static const int MonthLengths[2][12] = -{ - { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, - { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } -}; - -static inline BOOL IsLeapYear(int Year) -{ - return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0); -} - -/*********************************************************************** - * TIME_DayLightCompareDate - * - * Compares two dates without looking at the year. - * - * PARAMS - * date [in] The local time to compare. - * compareDate [in] The daylight savings begin or end date. - * - * RETURNS - * - * -1 if date < compareDate - * 0 if date == compareDate - * 1 if date > compareDate - * -2 if an error occurs - */ -static int TIME_DayLightCompareDate( const SYSTEMTIME *date, - const SYSTEMTIME *compareDate ) -{ - int limit_day, dayinsecs; - - if (date->wMonth < compareDate->wMonth) - return -1; /* We are in a month before the date limit. */ - - if (date->wMonth > compareDate->wMonth) - return 1; /* We are in a month after the date limit. */ - - /* if year is 0 then date is in day-of-week format, otherwise - * it's absolute date. - */ - if (compareDate->wYear == 0) - { - WORD First; - /* compareDate->wDay is interpreted as number of the week in the month - * 5 means: the last week in the month */ - int weekofmonth = compareDate->wDay; - /* calculate the day of the first DayOfWeek in the month */ - First = ( 6 + compareDate->wDayOfWeek - date->wDayOfWeek + date->wDay - ) % 7 + 1; - limit_day = First + 7 * (weekofmonth - 1); - /* check needed for the 5th weekday of the month */ - if(limit_day > MonthLengths[date->wMonth==2 && IsLeapYear(date->wYear)] - [date->wMonth - 1]) - limit_day -= 7; - } - else - { - limit_day = compareDate->wDay; - } - - /* convert to seconds */ - limit_day = ((limit_day * 24 + compareDate->wHour) * 60 + - compareDate->wMinute ) * 60; - dayinsecs = ((date->wDay * 24 + date->wHour) * 60 + - date->wMinute ) * 60 + date->wSecond; - /* and compare */ - return dayinsecs < limit_day ? -1 : - dayinsecs > limit_day ? 1 : - 0; /* date is equal to the date limit. */ -} - -/*********************************************************************** - * TIME_CompTimeZoneID - * - * Computes the local time bias for a given time and time zone. - * - * PARAMS - * pTZinfo [in] The time zone data. - * time [in] The system or local time. - * islocal [in] it is local time. - * - * RETURNS - * TIME_ZONE_ID_INVALID An error occurred - * TIME_ZONE_ID_UNKNOWN There are no transition time known - * TIME_ZONE_ID_STANDARD Current time is standard time - * TIME_ZONE_ID_DAYLIGHT Current time is daylight savings time - */ -static DWORD TIME_CompTimeZoneID ( const TIME_ZONE_INFORMATION *pTZinfo, - LONGLONG time, BOOL islocal ) -{ - int ret, year; - BOOL beforeStandardDate, afterDaylightDate; - DWORD retval = TIME_ZONE_ID_INVALID; - SYSTEMTIME SysTime; - FILETIME ft; - - if (pTZinfo->DaylightDate.wMonth != 0) - { - /* if year is 0 then date is in day-of-week format, otherwise - * it's absolute date. - */ - if (pTZinfo->StandardDate.wMonth == 0 || - (pTZinfo->StandardDate.wYear == 0 && - (pTZinfo->StandardDate.wDay<1 || - pTZinfo->StandardDate.wDay>5 || - pTZinfo->DaylightDate.wDay<1 || - pTZinfo->DaylightDate.wDay>5))) - { - SetLastError(ERROR_INVALID_PARAMETER); - return TIME_ZONE_ID_INVALID; - } - - if (!islocal) - time -= pTZinfo->Bias * (LONGLONG)600000000; - - longlong_to_filetime( time, &ft ); - FileTimeToSystemTime( &ft, &SysTime ); - year = SysTime.wYear; - - if (!islocal) { - time -= pTZinfo->DaylightBias * (LONGLONG)600000000; - longlong_to_filetime( time, &ft ); - FileTimeToSystemTime( &ft, &SysTime ); - } - - /* check for daylight savings */ - if(year == SysTime.wYear) { - ret = TIME_DayLightCompareDate( &SysTime, &pTZinfo->StandardDate); - if (ret == -2) - return TIME_ZONE_ID_INVALID; - - beforeStandardDate = ret < 0; - } else - beforeStandardDate = SysTime.wYear < year; - - if (!islocal) { - time -= ( pTZinfo->StandardBias - pTZinfo->DaylightBias ) * (LONGLONG)600000000; - longlong_to_filetime( time, &ft ); - FileTimeToSystemTime( &ft, &SysTime ); - } - - if(year == SysTime.wYear) { - ret = TIME_DayLightCompareDate( &SysTime, &pTZinfo->DaylightDate ); - if (ret == -2) - return TIME_ZONE_ID_INVALID; - - afterDaylightDate = ret >= 0; - } else - afterDaylightDate = SysTime.wYear > year; - - retval = TIME_ZONE_ID_STANDARD; - if( pTZinfo->DaylightDate.wMonth < pTZinfo->StandardDate.wMonth ) { - /* Northern hemisphere */ - if( beforeStandardDate && afterDaylightDate ) - retval = TIME_ZONE_ID_DAYLIGHT; - } else /* Down south */ - if( beforeStandardDate || afterDaylightDate ) - retval = TIME_ZONE_ID_DAYLIGHT; - } else - /* No transition date */ - retval = TIME_ZONE_ID_UNKNOWN; - - return retval; -} - -/*********************************************************************** - * TIME_TimeZoneID - * - * Calculates whether daylight savings is on now. - * - * PARAMS - * pTzi [in] Timezone info. - * - * RETURNS - * TIME_ZONE_ID_INVALID An error occurred - * TIME_ZONE_ID_UNKNOWN There are no transition time known - * TIME_ZONE_ID_STANDARD Current time is standard time - * TIME_ZONE_ID_DAYLIGHT Current time is daylight savings time - */ -static DWORD TIME_ZoneID( const TIME_ZONE_INFORMATION *pTzi ) -{ - LARGE_INTEGER now; - - NtQuerySystemTime( &now ); - return TIME_CompTimeZoneID( pTzi, now.QuadPart, FALSE ); -} - -/*********************************************************************** - * TIME_GetTimezoneBias - * - * Calculates the local time bias for a given time zone. - * - * PARAMS - * pTZinfo [in] The time zone data. - * time [in] The system or local time. - * islocal [in] It is local time. - * pBias [out] The calculated bias in minutes. - * - * RETURNS - * TRUE when the time zone bias was calculated. - */ -static BOOL TIME_GetTimezoneBias( const TIME_ZONE_INFORMATION *pTZinfo, - LONGLONG time, BOOL islocal, LONG *pBias ) -{ - LONG bias = pTZinfo->Bias; - DWORD tzid = TIME_CompTimeZoneID( pTZinfo, time, islocal ); - - if( tzid == TIME_ZONE_ID_INVALID) - return FALSE; - if (tzid == TIME_ZONE_ID_DAYLIGHT) - bias += pTZinfo->DaylightBias; - else if (tzid == TIME_ZONE_ID_STANDARD) - bias += pTZinfo->StandardBias; - *pBias = bias; - 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[] = { '\\','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 }; - 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 ); - if (!set_ntstatus( NtOpenKey( &time_zones_key, KEY_READ, &attr ))) return FALSE; - - attr.RootDirectory = time_zones_key; - RtlInitUnicodeString( &nameW, key_name ); - status = NtOpenKey( result, KEY_READ, &attr ); - - NtClose( time_zones_key ); - return set_ntstatus( status ); -} - -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; - - if (count > sizeof(buf) - sizeof(KEY_VALUE_PARTIAL_INFORMATION)) - return FALSE; - - RtlInitUnicodeString(&nameW, name); - - if (!set_ntstatus( NtQueryValueKey(hkey, &nameW, KeyValuePartialInformation, - buf, sizeof(buf), &count))) - 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 (RegLoadMUIStringW( time_zone_key, mui_stdW, tzinfo->StandardName, sizeof(tzinfo->StandardName), NULL, 0, DIR_System ) && - !reg_query_value( time_zone_key, stdW, REG_SZ, tzinfo->StandardName, sizeof(tzinfo->StandardName) )) - { - NtClose( time_zone_key ); - return FALSE; - } - - if (RegLoadMUIStringW( time_zone_key, mui_dltW, tzinfo->DaylightName, sizeof(tzinfo->DaylightName), NULL, 0, DIR_System ) && - !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; -} - /*********************************************************************** * GetSystemTimeAdjustment (KERNEL32.@) @@ -529,164 +140,6 @@ BOOL WINAPI SetSystemTimeAdjustment( DWORD dwTimeAdjustment, BOOL bTimeAdjustmen return TRUE; } -/*********************************************************************** - * GetTimeZoneInformation (KERNEL32.@) - * - * Get information about the current local time zone. - * - * PARAMS - * tzinfo [out] Destination for time zone information. - * - * RETURNS - * TIME_ZONE_ID_INVALID An error occurred - * TIME_ZONE_ID_UNKNOWN There are no transition time known - * TIME_ZONE_ID_STANDARD Current time is standard time - * TIME_ZONE_ID_DAYLIGHT Current time is daylight savings time - */ -DWORD WINAPI GetTimeZoneInformation( LPTIME_ZONE_INFORMATION ret ) -{ - DYNAMIC_TIME_ZONE_INFORMATION tzinfo; - DWORD time_zone_id; - - TRACE("(%p)\n", ret); - time_zone_id = GetDynamicTimeZoneInformation( &tzinfo ); - memcpy( ret, &tzinfo, sizeof(*ret) ); - return time_zone_id; -} - -/*********************************************************************** - * GetTimeZoneInformationForYear (KERNEL32.@) - */ -BOOL WINAPI GetTimeZoneInformationForYear( USHORT wYear, - PDYNAMIC_TIME_ZONE_INFORMATION pdtzi, LPTIME_ZONE_INFORMATION ptzi ) -{ - DYNAMIC_TIME_ZONE_INFORMATION local_dtzi, result; - - TRACE("(%u,%p)\n", wYear, ptzi); - 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. - * - * PARAMS - * tzinfo [in] The new time zone. - * - * RETURNS - * Success: TRUE. The time zone was updated with the settings from tzinfo. - * Failure: FALSE. - */ -BOOL WINAPI SetTimeZoneInformation( const TIME_ZONE_INFORMATION *tzinfo ) -{ - TRACE("(%p)\n", tzinfo); - return set_ntstatus( RtlSetTimeZoneInformation( (const RTL_TIME_ZONE_INFORMATION *)tzinfo )); -} - -/*********************************************************************** - * SystemTimeToTzSpecificLocalTime (KERNEL32.@) - * - * Convert a utc system time to a local time in a given time zone. - * - * PARAMS - * lpTimeZoneInformation [in] The desired time zone. - * lpUniversalTime [in] The utc time to base local time on. - * lpLocalTime [out] The local time in the time zone. - * - * RETURNS - * Success: TRUE. lpLocalTime contains the converted time - * Failure: FALSE. - */ - -BOOL WINAPI SystemTimeToTzSpecificLocalTime( - const TIME_ZONE_INFORMATION *lpTimeZoneInformation, - const SYSTEMTIME *lpUniversalTime, LPSYSTEMTIME lpLocalTime ) -{ - FILETIME ft; - LONG lBias; - LONGLONG llTime; - TIME_ZONE_INFORMATION tzinfo; - - if (lpTimeZoneInformation != NULL) - { - tzinfo = *lpTimeZoneInformation; - } - else - { - RtlQueryTimeZoneInformation((RTL_TIME_ZONE_INFORMATION *)&tzinfo); - } - - if (!SystemTimeToFileTime(lpUniversalTime, &ft)) - return FALSE; - llTime = filetime_to_longlong( &ft ); - if (!TIME_GetTimezoneBias(&tzinfo, llTime, FALSE, &lBias)) - return FALSE; - /* convert minutes to 100-nanoseconds-ticks */ - llTime -= (LONGLONG)lBias * 600000000; - longlong_to_filetime( llTime, &ft ); - - return FileTimeToSystemTime(&ft, lpLocalTime); -} - - -/*********************************************************************** - * TzSpecificLocalTimeToSystemTime (KERNEL32.@) - * - * Converts a local time to a time in utc. - * - * PARAMS - * lpTimeZoneInformation [in] The desired time zone. - * lpLocalTime [in] The local time. - * lpUniversalTime [out] The calculated utc time. - * - * RETURNS - * Success: TRUE. lpUniversalTime contains the converted time. - * Failure: FALSE. - */ -BOOL WINAPI TzSpecificLocalTimeToSystemTime( - const TIME_ZONE_INFORMATION *lpTimeZoneInformation, - const SYSTEMTIME *lpLocalTime, LPSYSTEMTIME lpUniversalTime) -{ - FILETIME ft; - LONG lBias; - LONGLONG t; - TIME_ZONE_INFORMATION tzinfo; - - if (lpTimeZoneInformation != NULL) - { - tzinfo = *lpTimeZoneInformation; - } - else - { - RtlQueryTimeZoneInformation((RTL_TIME_ZONE_INFORMATION *)&tzinfo); - } - - if (!SystemTimeToFileTime(lpLocalTime, &ft)) - return FALSE; - t = filetime_to_longlong( &ft ); - if (!TIME_GetTimezoneBias(&tzinfo, t, TRUE, &lBias)) - return FALSE; - /* convert minutes to 100-nanoseconds-ticks */ - t += (LONGLONG)lBias * 600000000; - longlong_to_filetime( t, &ft ); - return FileTimeToSystemTime(&ft, lpUniversalTime); -} - - /********************************************************************* * TIME_ClockTimeToFileTime (olorin@fandra.org, 20-Sep-1998) * @@ -705,46 +158,6 @@ static void TIME_ClockTimeToFileTime(clock_t unix_time, LPFILETIME filetime) filetime->dwHighDateTime = (DWORD)(secs >> 32); } -/*********************************************************************** - * TIMEZONE_InitRegistry - * - * Update registry contents on startup if the user timezone has changed. - * This simulates the action of the Windows control panel. - */ -void TIMEZONE_InitRegistry(void) -{ - static const WCHAR timezoneInformationW[] = { - 'M','a','c','h','i','n','e','\\','S','y','s','t','e','m','\\', - 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', - 'C','o','n','t','r','o','l','\\', - 'T','i','m','e','Z','o','n','e','I','n','f','o','r','m','a','t','i','o','n','\0' - }; - static const WCHAR standardNameW[] = {'S','t','a','n','d','a','r','d','N','a','m','e','\0'}; - static const WCHAR timezoneKeyNameW[] = {'T','i','m','e','Z','o','n','e','K','e','y','N','a','m','e','\0'}; - DYNAMIC_TIME_ZONE_INFORMATION tzinfo; - UNICODE_STRING name; - OBJECT_ATTRIBUTES attr; - HANDLE hkey; - DWORD tzid; - - tzid = GetDynamicTimeZoneInformation(&tzinfo); - if (tzid == TIME_ZONE_ID_INVALID) return; - - RtlInitUnicodeString(&name, timezoneInformationW); - InitializeObjectAttributes(&attr, &name, 0, 0, NULL); - if (NtCreateKey(&hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL) != STATUS_SUCCESS) return; - - RtlInitUnicodeString(&name, standardNameW); - NtSetValueKey(hkey, &name, 0, REG_SZ, tzinfo.StandardName, - (strlenW(tzinfo.StandardName) + 1) * sizeof(WCHAR)); - - RtlInitUnicodeString(&name, timezoneKeyNameW); - NtSetValueKey(hkey, &name, 0, REG_SZ, tzinfo.TimeZoneKeyName, - (strlenW(tzinfo.TimeZoneKeyName) + 1) * sizeof(WCHAR)); - - NtClose( hkey ); -} - /********************************************************************* * GetProcessTimes (KERNEL32.@) * @@ -842,10 +255,7 @@ int WINAPI SetCalendarInfoA(LCID Locale, CALID Calendar, CALTYPE CalType, LPCSTR BOOL WINAPI GetDaylightFlag(void) { TIME_ZONE_INFORMATION tzinfo; - - TRACE("()\n"); - RtlQueryTimeZoneInformation((RTL_TIME_ZONE_INFORMATION *)&tzinfo); - return (TIME_ZoneID(&tzinfo) == TIME_ZONE_ID_DAYLIGHT); + return GetTimeZoneInformation( &tzinfo) == TIME_ZONE_ID_DAYLIGHT; } /*********************************************************************** @@ -979,35 +389,6 @@ BOOL WINAPI GetSystemTimes(LPFILETIME lpIdleTime, LPFILETIME lpKernelTime, LPFIL return TRUE; } -/*********************************************************************** - * GetDynamicTimeZoneInformation (KERNEL32.@) - */ -DWORD WINAPI GetDynamicTimeZoneInformation(DYNAMIC_TIME_ZONE_INFORMATION *tzinfo) -{ - HANDLE time_zone_key; - - TRACE("(%p)\n", tzinfo); - if (!set_ntstatus( RtlQueryDynamicTimeZoneInformation( (RTL_DYNAMIC_TIME_ZONE_INFORMATION*)tzinfo ))) - return TIME_ZONE_ID_INVALID; - - if (!TIME_GetSpecificTimeZoneKey( tzinfo->TimeZoneKeyName, &time_zone_key )) - return TIME_ZONE_ID_INVALID; - RegLoadMUIStringW( time_zone_key, mui_stdW, tzinfo->StandardName, sizeof(tzinfo->StandardName), NULL, 0, DIR_System ); - RegLoadMUIStringW( time_zone_key, mui_dltW, tzinfo->DaylightName, sizeof(tzinfo->DaylightName), NULL, 0, DIR_System ); - NtClose( time_zone_key ); - - return TIME_ZoneID( (TIME_ZONE_INFORMATION*)tzinfo ); -} - -/*********************************************************************** - * GetDynamicTimeZoneInformationEffectiveYears (KERNEL32.@) - */ -DWORD WINAPI GetDynamicTimeZoneInformationEffectiveYears(DYNAMIC_TIME_ZONE_INFORMATION *tzinfo, DWORD *first_year, DWORD *last_year) -{ - FIXME("(%p, %p, %p): stub!\n", tzinfo, first_year, last_year); - return ERROR_FILE_NOT_FOUND; -} - /*********************************************************************** * QueryProcessCycleTime (KERNEL32.@) */ diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index 64f587a4551..61215107e4a 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -486,8 +486,8 @@ @ stdcall GetDriveTypeA(str) kernel32.GetDriveTypeA @ stdcall GetDriveTypeW(wstr) kernel32.GetDriveTypeW # @ stub GetDurationFormatEx -@ stdcall GetDynamicTimeZoneInformation(ptr) kernel32.GetDynamicTimeZoneInformation -@ stdcall GetDynamicTimeZoneInformationEffectiveYears(ptr ptr ptr) kernel32.GetDynamicTimeZoneInformationEffectiveYears +@ stdcall GetDynamicTimeZoneInformation(ptr) +@ stdcall GetDynamicTimeZoneInformationEffectiveYears(ptr ptr ptr) # @ stub GetEffectivePackageStatusForUser # @ stub GetEightBitStringToUnicodeSizeRoutine # @ stub GetEightBitStringToUnicodeStringRoutine @@ -730,8 +730,8 @@ @ stdcall GetTimeFormatA(long long ptr str ptr long) kernel32.GetTimeFormatA @ stdcall GetTimeFormatEx(wstr long ptr wstr ptr long) kernel32.GetTimeFormatEx @ stdcall GetTimeFormatW(long long ptr wstr ptr long) kernel32.GetTimeFormatW -@ stdcall GetTimeZoneInformation(ptr) kernel32.GetTimeZoneInformation -@ stdcall GetTimeZoneInformationForYear(long ptr ptr) kernel32.GetTimeZoneInformationForYear +@ stdcall GetTimeZoneInformation(ptr) +@ stdcall GetTimeZoneInformationForYear(long ptr ptr) @ stdcall GetTokenInformation(long long ptr long ptr) @ stdcall GetTraceEnableFlags(int64) ntdll.EtwGetTraceEnableFlags @ stdcall GetTraceEnableLevel(int64) ntdll.EtwGetTraceEnableLevel @@ -1499,7 +1499,7 @@ # @ stub SetThreadpoolTimerEx @ stdcall SetThreadpoolWait(ptr long ptr) ntdll.TpSetWait # @ stub SetThreadpoolWaitEx -@ stdcall SetTimeZoneInformation(ptr) kernel32.SetTimeZoneInformation +@ stdcall SetTimeZoneInformation(ptr) @ stdcall SetTokenInformation(long long ptr long) @ stdcall SetUnhandledExceptionFilter(ptr) @ stdcall SetUserGeoID(long) @@ -1591,7 +1591,7 @@ @ stdcall SwitchToFiber(ptr) @ stdcall SwitchToThread() @ stdcall SystemTimeToFileTime(ptr ptr) -@ stdcall SystemTimeToTzSpecificLocalTime(ptr ptr ptr) kernel32.SystemTimeToTzSpecificLocalTime +@ stdcall SystemTimeToTzSpecificLocalTime(ptr ptr ptr) @ stub SystemTimeToTzSpecificLocalTimeEx @ stdcall TerminateProcess(long long) # @ stub TerminateProcessOnMemoryExhaustion @@ -1609,7 +1609,7 @@ @ stdcall TryAcquireSRWLockShared(ptr) ntdll.RtlTryAcquireSRWLockShared @ stdcall TryEnterCriticalSection(ptr) ntdll.RtlTryEnterCriticalSection @ stdcall TrySubmitThreadpoolCallback(ptr ptr ptr) -@ stdcall TzSpecificLocalTimeToSystemTime(ptr ptr ptr) kernel32.TzSpecificLocalTimeToSystemTime +@ stdcall TzSpecificLocalTimeToSystemTime(ptr ptr ptr) @ stub TzSpecificLocalTimeToSystemTimeEx @ stdcall UnhandledExceptionFilter(ptr) @ stdcall UnlockFile(long long long long long) diff --git a/dlls/kernelbase/locale.c b/dlls/kernelbase/locale.c index b6769bf3d0a..444affa6a38 100644 --- a/dlls/kernelbase/locale.c +++ b/dlls/kernelbase/locale.c @@ -542,6 +542,7 @@ static NLSTABLEINFO nls_info; static UINT mac_cp = 10000; static HKEY intl_key; static HKEY nls_key; +static HKEY tz_key; static CPTABLEINFO codepages[128]; static unsigned int nb_codepages; @@ -564,6 +565,7 @@ void init_locale(void) USHORT *ansi_ptr, *oem_ptr, *casemap_ptr; LCID lcid = GetUserDefaultLCID(); WCHAR bufferW[80]; + DYNAMIC_TIME_ZONE_INFORMATION timezone; GEOID geoid = GEOID_NOT_AVAILABLE; DWORD count, dispos, i; SIZE_T size; @@ -591,9 +593,22 @@ void init_locale(void) RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\Nls", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &nls_key, NULL ); + RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", + 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &tz_key, NULL ); RegCreateKeyExW( HKEY_CURRENT_USER, L"Control Panel\\International", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &intl_key, NULL ); + if (GetDynamicTimeZoneInformation( &timezone ) != TIME_ZONE_ID_INVALID && + !RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\TimeZoneInformation", + 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL )) + { + RegSetValueExW( hkey, L"StandardName", 0, REG_SZ, (BYTE *)timezone.StandardName, + (lstrlenW(timezone.StandardName) + 1) * sizeof(WCHAR) ); + RegSetValueExW( hkey, L"TimeZoneKeyName", 0, REG_SZ, (BYTE *)timezone.TimeZoneKeyName, + (lstrlenW(timezone.TimeZoneKeyName) + 1) * sizeof(WCHAR) ); + RegCloseKey( hkey ); + } + if (!RegCreateKeyExW( intl_key, L"Geo", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &dispos )) { if (dispos == REG_CREATED_NEW_KEY) @@ -2257,6 +2272,91 @@ static const struct geoinfo *get_geoinfo_ptr( GEOID geoid ) } +static int compare_tzdate( const TIME_FIELDS *tf, const SYSTEMTIME *compare ) +{ + static const int month_lengths[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + int first, last, limit, dayinsecs; + + if (tf->Month < compare->wMonth) return -1; /* We are in a month before the date limit. */ + if (tf->Month > compare->wMonth) return 1; /* We are in a month after the date limit. */ + + /* if year is 0 then date is in day-of-week format, otherwise + * it's absolute date. + */ + if (!compare->wYear) + { + /* wDay is interpreted as number of the week in the month + * 5 means: the last week in the month */ + /* calculate the day of the first DayOfWeek in the month */ + first = (6 + compare->wDayOfWeek - tf->Weekday + tf->Day) % 7 + 1; + /* check needed for the 5th weekday of the month */ + last = month_lengths[tf->Month - 1] + + (tf->Month == 2 && (!(tf->Year % 4) && (tf->Year % 100 || !(tf->Year % 400)))); + limit = first + 7 * (compare->wDay - 1); + if (limit > last) limit -= 7; + } + else limit = compare->wDay; + + limit = ((limit * 24 + compare->wHour) * 60 + compare->wMinute) * 60; + dayinsecs = ((tf->Day * 24 + tf->Hour) * 60 + tf->Minute) * 60 + tf->Second; + return dayinsecs - limit; +} + + +static DWORD get_timezone_id( const TIME_ZONE_INFORMATION *info, LARGE_INTEGER time, BOOL is_local ) +{ + int year; + BOOL before_standard_date, after_daylight_date; + LARGE_INTEGER t2; + TIME_FIELDS tf; + + if (!info->DaylightDate.wMonth) return TIME_ZONE_ID_UNKNOWN; + + /* if year is 0 then date is in day-of-week format, otherwise it's absolute date */ + if (info->StandardDate.wMonth == 0 || + (info->StandardDate.wYear == 0 && + (info->StandardDate.wDay < 1 || info->StandardDate.wDay > 5 || + info->DaylightDate.wDay < 1 || info->DaylightDate.wDay > 5))) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return TIME_ZONE_ID_INVALID; + } + + if (!is_local) time.QuadPart -= info->Bias * (LONGLONG)600000000; + RtlTimeToTimeFields( &time, &tf ); + year = tf.Year; + if (!is_local) + { + t2.QuadPart = time.QuadPart - info->DaylightBias * (LONGLONG)600000000; + RtlTimeToTimeFields( &t2, &tf ); + } + if (tf.Year == year) + before_standard_date = compare_tzdate( &tf, &info->StandardDate ) < 0; + else + before_standard_date = tf.Year < year; + + if (!is_local) + { + t2.QuadPart = time.QuadPart - info->StandardBias * (LONGLONG)600000000; + RtlTimeToTimeFields( &t2, &tf ); + } + if (tf.Year == year) + after_daylight_date = compare_tzdate( &tf, &info->DaylightDate ) >= 0; + else + after_daylight_date = tf.Year > year; + + if (info->DaylightDate.wMonth < info->StandardDate.wMonth) /* Northern hemisphere */ + { + if (before_standard_date && after_daylight_date) return TIME_ZONE_ID_DAYLIGHT; + } + else /* Down south */ + { + if (before_standard_date || after_daylight_date) return TIME_ZONE_ID_DAYLIGHT; + } + return TIME_ZONE_ID_STANDARD; +} + + /* Note: the Internal_ functions are not documented. The number of parameters * should be correct, but their exact meaning may not. */ @@ -3509,6 +3609,59 @@ INT WINAPI DECLSPEC_HOTPATCH GetCalendarInfoEx( const WCHAR *locale, CALID calen } +/*********************************************************************** + * GetDynamicTimeZoneInformation (kernelbase.@) + */ +DWORD WINAPI DECLSPEC_HOTPATCH GetDynamicTimeZoneInformation( DYNAMIC_TIME_ZONE_INFORMATION *info ) +{ + HKEY key; + LARGE_INTEGER now; + + if (!set_ntstatus( RtlQueryDynamicTimeZoneInformation( (RTL_DYNAMIC_TIME_ZONE_INFORMATION *)info ))) + return TIME_ZONE_ID_INVALID; + + if (!RegOpenKeyExW( tz_key, info->TimeZoneKeyName, 0, KEY_ALL_ACCESS, &key )) + { + RegLoadMUIStringW( key, L"MUI_Std", info->StandardName, + sizeof(info->StandardName), NULL, 0, system_dir ); + RegLoadMUIStringW( key, L"MUI_Dlt", info->DaylightName, + sizeof(info->DaylightName), NULL, 0, system_dir ); + RegCloseKey( key ); + } + else return TIME_ZONE_ID_INVALID; + + NtQuerySystemTime( &now ); + return get_timezone_id( (TIME_ZONE_INFORMATION *)info, now, FALSE ); +} + + +/****************************************************************************** + * GetDynamicTimeZoneInformationEffectiveYears (kernelbase.@) + */ +DWORD WINAPI DECLSPEC_HOTPATCH GetDynamicTimeZoneInformationEffectiveYears( const DYNAMIC_TIME_ZONE_INFORMATION *info, + DWORD *first, DWORD *last ) +{ + HKEY key, dst_key = 0; + DWORD type, count, ret = ERROR_FILE_NOT_FOUND; + + if (RegOpenKeyExW( tz_key, info->TimeZoneKeyName, 0, KEY_ALL_ACCESS, &key )) return ret; + + if (RegOpenKeyExW( key, L"Dynamic DST", 0, KEY_ALL_ACCESS, &dst_key )) goto done; + count = sizeof(DWORD); + if (RegQueryValueExW( dst_key, L"FirstEntry", NULL, &type, (BYTE *)first, &count )) goto done; + if (type != REG_DWORD) goto done; + count = sizeof(DWORD); + if (RegQueryValueExW( dst_key, L"LastEntry", NULL, &type, (BYTE *)last, &count )) goto done; + if (type != REG_DWORD) goto done; + ret = 0; + +done: + RegCloseKey( dst_key ); + RegCloseKey( key ); + return ret; +} + + /****************************************************************************** * GetGeoInfoW (kernelbase.@) */ @@ -3942,6 +4095,95 @@ LANGID WINAPI DECLSPEC_HOTPATCH GetSystemDefaultUILanguage(void) } +/*********************************************************************** + * GetTimeZoneInformation (kernelbase.@) + */ +DWORD WINAPI DECLSPEC_HOTPATCH GetTimeZoneInformation( TIME_ZONE_INFORMATION *info ) +{ + DYNAMIC_TIME_ZONE_INFORMATION tzinfo; + DWORD ret = GetDynamicTimeZoneInformation( &tzinfo ); + + memcpy( info, &tzinfo, sizeof(*info) ); + return ret; +} + + +/*********************************************************************** + * GetTimeZoneInformationForYear (kernelbase.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH GetTimeZoneInformationForYear( USHORT year, + DYNAMIC_TIME_ZONE_INFORMATION *dynamic, + TIME_ZONE_INFORMATION *info ) +{ + DYNAMIC_TIME_ZONE_INFORMATION local_info; + HKEY key = 0, dst_key; + DWORD count; + LRESULT ret; + struct + { + LONG bias; + LONG std_bias; + LONG dlt_bias; + SYSTEMTIME std_date; + SYSTEMTIME dlt_date; + } data; + + TRACE( "(%u,%p)\n", year, info ); + + if (!dynamic) + { + if (GetDynamicTimeZoneInformation( &local_info ) == TIME_ZONE_ID_INVALID) return FALSE; + dynamic = &local_info; + } + + if ((ret = RegOpenKeyExW( tz_key, dynamic->TimeZoneKeyName, 0, KEY_ALL_ACCESS, &key ))) goto done; + if (RegLoadMUIStringW( key, L"MUI_Std", info->StandardName, + sizeof(info->StandardName), NULL, 0, system_dir )) + { + count = sizeof(info->StandardName); + if ((ret = RegQueryValueExW( key, L"Std", NULL, NULL, (BYTE *)info->StandardName, &count ))) + goto done; + } + if (RegLoadMUIStringW( key, L"MUI_Dlt", info->DaylightName, + sizeof(info->DaylightName), NULL, 0, system_dir )) + { + count = sizeof(info->DaylightName); + if ((ret = RegQueryValueExW( key, L"Dlt", NULL, NULL, (BYTE *)info->DaylightName, &count ))) + goto done; + } + + ret = ERROR_FILE_NOT_FOUND; + if (!dynamic->DynamicDaylightTimeDisabled && + !RegOpenKeyExW( key, L"Dynamic DST", 0, KEY_ALL_ACCESS, &dst_key )) + { + WCHAR yearW[16]; + swprintf( yearW, ARRAY_SIZE(yearW), L"%u", year ); + count = sizeof(data); + ret = RegQueryValueExW( dst_key, yearW, NULL, NULL, (BYTE *)&data, &count ); + RegCloseKey( dst_key ); + } + if (ret) + { + count = sizeof(data); + ret = RegQueryValueExW( key, L"TZI", NULL, NULL, (BYTE *)&data, &count ); + } + + if (!ret) + { + info->Bias = data.bias; + info->StandardBias = data.std_bias; + info->DaylightBias = data.dlt_bias; + info->StandardDate = data.std_date; + info->DaylightDate = data.dlt_date; + } + +done: + RegCloseKey( key ); + if (ret) SetLastError( ret ); + return !ret; +} + + /*********************************************************************** * GetUserDefaultLCID (kernelbase.@) */ @@ -4701,6 +4943,15 @@ INT WINAPI /* DECLSPEC_HOTPATCH */ SetCalendarInfoW( LCID lcid, CALID calendar, } +/*********************************************************************** + * SetTimeZoneInformation (kernelbase.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH SetTimeZoneInformation( const TIME_ZONE_INFORMATION *info ) +{ + return set_ntstatus( RtlSetTimeZoneInformation( (const RTL_TIME_ZONE_INFORMATION *)info )); +} + + /****************************************************************************** * SetUserGeoID (kernelbase.@) */ @@ -4726,6 +4977,76 @@ BOOL WINAPI DECLSPEC_HOTPATCH SetUserGeoID( GEOID id ) } +/*********************************************************************** + * SystemTimeToTzSpecificLocalTime (kernelbase.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH SystemTimeToTzSpecificLocalTime( const TIME_ZONE_INFORMATION *info, + const SYSTEMTIME *system, + SYSTEMTIME *local ) +{ + TIME_ZONE_INFORMATION tzinfo; + LARGE_INTEGER ft; + + if (!info) + { + RtlQueryTimeZoneInformation( (RTL_TIME_ZONE_INFORMATION *)&tzinfo ); + info = &tzinfo; + } + + if (!SystemTimeToFileTime( system, (FILETIME *)&ft )) return FALSE; + switch (get_timezone_id( info, ft, FALSE )) + { + case TIME_ZONE_ID_UNKNOWN: + ft.QuadPart -= info->Bias * (LONGLONG)600000000; + break; + case TIME_ZONE_ID_STANDARD: + ft.QuadPart -= (info->Bias + info->StandardBias) * (LONGLONG)600000000; + break; + case TIME_ZONE_ID_DAYLIGHT: + ft.QuadPart -= (info->Bias + info->DaylightBias) * (LONGLONG)600000000; + break; + default: + return FALSE; + } + return FileTimeToSystemTime( (FILETIME *)&ft, local ); +} + + +/*********************************************************************** + * TzSpecificLocalTimeToSystemTime (kernelbase.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH TzSpecificLocalTimeToSystemTime( const TIME_ZONE_INFORMATION *info, + const SYSTEMTIME *local, + SYSTEMTIME *system ) +{ + TIME_ZONE_INFORMATION tzinfo; + LARGE_INTEGER ft; + + if (!info) + { + RtlQueryTimeZoneInformation( (RTL_TIME_ZONE_INFORMATION *)&tzinfo ); + info = &tzinfo; + } + + if (!SystemTimeToFileTime( local, (FILETIME *)&ft )) return FALSE; + switch (get_timezone_id( info, ft, TRUE )) + { + case TIME_ZONE_ID_UNKNOWN: + ft.QuadPart += info->Bias * (LONGLONG)600000000; + break; + case TIME_ZONE_ID_STANDARD: + ft.QuadPart += (info->Bias + info->StandardBias) * (LONGLONG)600000000; + break; + case TIME_ZONE_ID_DAYLIGHT: + ft.QuadPart += (info->Bias + info->DaylightBias) * (LONGLONG)600000000; + break; + default: + return FALSE; + } + return FileTimeToSystemTime( (FILETIME *)&ft, system ); +} + + /*********************************************************************** * VerLanguageNameA (kernelbase.@) */