diff --git a/src/windows/native/java/util/TimeZone_md.c b/src/windows/native/java/util/TimeZone_md.c index 90fb1eed7e3bb61d21971f604d459b59fc0c39b1..cb5f17c01749aac569211989a1c9b0b7ca5ce849 100644 --- a/src/windows/native/java/util/TimeZone_md.c +++ b/src/windows/native/java/util/TimeZone_md.c @@ -28,6 +28,7 @@ #include #include "jvm.h" #include "TimeZone_md.h" +#include "jdk_util.h" #define VALUE_UNKNOWN 0 #define VALUE_KEY 1 @@ -49,6 +50,20 @@ typedef struct _TziValue { SYSTEMTIME dstDate; } TziValue; +#if _WIN32_WINNT < 0x0600 /* < _WIN32_WINNT_VISTA */ +typedef struct _TIME_DYNAMIC_ZONE_INFORMATION { + LONG Bias; + WCHAR StandardName[32]; + SYSTEMTIME StandardDate; + LONG StandardBias; + WCHAR DaylightName[32]; + SYSTEMTIME DaylightDate; + LONG DaylightBias; + WCHAR TimeZoneKeyName[128]; + BOOLEAN DynamicDaylightTimeDisabled; +} DYNAMIC_TIME_ZONE_INFORMATION, *PDYNAMIC_TIME_ZONE_INFORMATION; +#endif + /* * Registry key names */ @@ -142,6 +157,33 @@ static void customZoneName(LONG bias, char *buffer) { } } +/* + * Use NO_DYNAMIC_TIME_ZONE_INFO as the return value indicating that no + * dynamic time zone information is available. + */ +#define NO_DYNAMIC_TIME_ZONE_INFO (-128) + +static int getDynamicTimeZoneInfo(PDYNAMIC_TIME_ZONE_INFORMATION pdtzi) { + DWORD timeType = NO_DYNAMIC_TIME_ZONE_INFO; + HMODULE dllHandle; + + /* + * Dynamically load the dll to call GetDynamicTimeZoneInformation. + */ + dllHandle = JDK_LoadSystemLibrary("Kernel32.dll"); + if (dllHandle != NULL) { + typedef DWORD (WINAPI *GetDynamicTimezoneInfoType)(PDYNAMIC_TIME_ZONE_INFORMATION); + GetDynamicTimezoneInfoType getDynamicTimeZoneInfoFunc = + (GetDynamicTimezoneInfoType) GetProcAddress(dllHandle, + "GetDynamicTimeZoneInformation"); + + if (getDynamicTimeZoneInfo != NULL) { + timeType = getDynamicTimeZoneInfoFunc(pdtzi); + } + } + return timeType; +} + /* * Gets the current time zone entry in the "Time Zones" registry. */ @@ -161,22 +203,95 @@ static int getWinTimeZone(char *winZoneName, char *winMapID) WCHAR *stdNamePtr = tzi.StandardName; DWORD valueSize; DWORD timeType; - int isVista; + int isVistaOrLater; /* - * Get the current time zone setting of the platform. + * Determine if this is a Vista or later. */ - timeType = GetTimeZoneInformation(&tzi); - if (timeType == TIME_ZONE_ID_INVALID) { - goto err; + ver.dwOSVersionInfoSize = sizeof(ver); + GetVersionEx(&ver); + isVistaOrLater = (ver.dwMajorVersion >= 6); + + if (isVistaOrLater) { + DYNAMIC_TIME_ZONE_INFORMATION dtzi; + DWORD bufSize; + DWORD val; + + /* + * Get the dynamic time zone information, if available, so that time + * zone redirection can be supported. (see JDK-7044727) + */ + timeType = getDynamicTimeZoneInfo(&dtzi); + if (timeType == TIME_ZONE_ID_INVALID) { + goto err; + } + + if (timeType != NO_DYNAMIC_TIME_ZONE_INFO) { + /* + * Make sure TimeZoneKeyName is available from the API call. If + * DynamicDaylightTime is disabled, return a custom time zone name + * based on the GMT offset. Otherwise, return the TimeZoneKeyName + * value. + */ + if (dtzi.TimeZoneKeyName[0] != 0) { + if (dtzi.DynamicDaylightTimeDisabled) { + customZoneName(dtzi.Bias, winZoneName); + return VALUE_GMTOFFSET; + } + wcstombs(winZoneName, dtzi.TimeZoneKeyName, MAX_ZONE_CHAR); + return VALUE_KEY; + } + + /* + * If TimeZoneKeyName is not available, check whether StandardName + * is available to fall back to the older API GetTimeZoneInformation. + * If not, directly read the value from registry keys. + */ + if (dtzi.StandardName[0] == 0) { + ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_CURRENT_TZ_KEY, 0, + KEY_READ, (PHKEY)&hKey); + if (ret != ERROR_SUCCESS) { + goto err; + } + + /* + * Determine if auto-daylight time adjustment is turned off. + */ + bufSize = sizeof(val); + ret = RegQueryValueExA(hKey, "DynamicDaylightTimeDisabled", NULL, + &valueType, (LPBYTE) &val, &bufSize); + if (ret != ERROR_SUCCESS) { + goto err; + } + /* + * Return a custom time zone name if auto-daylight time + * adjustment is disabled. + */ + if (val == 1) { + customZoneName(dtzi.Bias, winZoneName); + (void) RegCloseKey(hKey); + return VALUE_GMTOFFSET; + } + + bufSize = MAX_ZONE_CHAR; + ret = RegQueryValueExA(hKey, "TimeZoneKeyName",NULL, + &valueType, (LPBYTE)winZoneName, &bufSize); + if (ret != ERROR_SUCCESS) { + goto err; + } + (void) RegCloseKey(hKey); + return VALUE_KEY; + } + } } /* - * Determine if this is an NT system. + * Fall back to GetTimeZoneInformation */ - ver.dwOSVersionInfoSize = sizeof(ver); - GetVersionEx(&ver); - isVista = ver.dwMajorVersion >= 6; + timeType = GetTimeZoneInformation(&tzi); + if (timeType == TIME_ZONE_ID_INVALID) { + goto err; + } ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_CURRENT_TZ_KEY, 0, KEY_READ, (PHKEY)&hKey); @@ -187,23 +302,23 @@ static int getWinTimeZone(char *winZoneName, char *winMapID) /* * Determine if auto-daylight time adjustment is turned off. */ - valueType = 0; bufSize = sizeof(val); - ret = RegQueryValueExA(hKey, "DisableAutoDaylightTimeSet", - NULL, &valueType, (LPBYTE) &val, &bufSize); - /* - * Vista uses the different key name. - */ + ret = RegQueryValueExA(hKey, "DynamicDaylightTimeDisabled", NULL, + &valueType, (LPBYTE) &val, &bufSize); if (ret != ERROR_SUCCESS) { + /* + * Try the old key name. + */ bufSize = sizeof(val); - ret = RegQueryValueExA(hKey, "DynamicDaylightTimeDisabled", - NULL, &valueType, (LPBYTE) &val, &bufSize); + ret = RegQueryValueExA(hKey, "DisableAutoDaylightTimeSet", NULL, + &valueType, (LPBYTE) &val, &bufSize); } if (ret == ERROR_SUCCESS) { - int daylightSavingsUpdateDisabledOther = val == 1 && tzi.DaylightDate.wMonth != 0; - int daylightSavingsUpdateDisabledVista = val == 1; - int daylightSavingsUpdateDisabled = isVista ? daylightSavingsUpdateDisabledVista : daylightSavingsUpdateDisabledOther; + int daylightSavingsUpdateDisabledOther = (val == 1 && tzi.DaylightDate.wMonth != 0); + int daylightSavingsUpdateDisabledVista = (val == 1); + int daylightSavingsUpdateDisabled + = (isVistaOrLater ? daylightSavingsUpdateDisabledVista : daylightSavingsUpdateDisabledOther); if (daylightSavingsUpdateDisabled) { (void) RegCloseKey(hKey); @@ -212,29 +327,13 @@ static int getWinTimeZone(char *winZoneName, char *winMapID) } } - /* - * Vista has the key for the current "Time Zones" entry. - */ - if (isVista) { - valueType = 0; - bufSize = MAX_ZONE_CHAR; - ret = RegQueryValueExA(hKey, "TimeZoneKeyName", NULL, - &valueType, (LPBYTE) winZoneName, &bufSize); - if (ret != ERROR_SUCCESS) { - goto err; - } - (void) RegCloseKey(hKey); - return VALUE_KEY; - } - /* * Win32 problem: If the length of the standard time name is equal * to (or probably longer than) 32 in the registry, * GetTimeZoneInformation() on NT returns a null string as its * standard time name. We need to work around this problem by * getting the same information from the TimeZoneInformation - * registry. The function on Win98 seems to return its key name. - * We can't do anything in that case. + * registry. */ if (tzi.StandardName[0] == 0) { bufSize = sizeof(stdNameInReg);