/*
********************************************************************************
-* Copyright (C) 2005-2011, International Business Machines
+* Copyright (C) 2005-2015, International Business Machines
* Corporation and others. All Rights Reserved.
********************************************************************************
*
#if U_PLATFORM_HAS_WIN32_API
#include "wintz.h"
-
#include "cmemory.h"
#include "cstring.h"
-#include "unicode/ustring.h"
#include "unicode/ures.h"
+#include "unicode/ustring.h"
# define WIN32_LEAN_AND_MEAN
# define VC_EXTRALEAN
# define NOMCX
#include <windows.h>
-#define MAX_LENGTH_ID 32
+#define MAX_LENGTH_ID 40
/* The layout of the Tzi value in the registry */
typedef struct
* Various registry keys and key fragments.
*/
static const char CURRENT_ZONE_REGKEY[] = "SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation\\";
-static const char STANDARD_NAME_REGKEY[] = "StandardName";
+/* static const char STANDARD_NAME_REGKEY[] = "StandardName"; Currently unused constant */
static const char STANDARD_TIME_REGKEY[] = " Standard Time";
static const char TZI_REGKEY[] = "TZI";
static const char STD_REGKEY[] = "Std";
{
/* subKeyName needs to be long enough for the longest TZ_REGKEY, plus the longest Windows
* tzid (current or obsolete), plus an appended STANDARD_TIME_REGKEY, plus a 0 terminator.
- * Currently this is 111, but the code had 110. Make it 128 for some wiggle room. */
+ * At its max point this was 111, but the code had 110. Make it 128 for some wiggle room. */
char subKeyName[128];
char *name;
LONG result;
return result;
}
+static LONG getTZKeyName(char* tzKeyName, int32_t length) {
+ HKEY hkey;
+ LONG result = FALSE;
+ DWORD cbData = length;
+
+ if(ERROR_SUCCESS == RegOpenKeyExA(
+ HKEY_LOCAL_MACHINE,
+ CURRENT_ZONE_REGKEY,
+ 0,
+ KEY_QUERY_VALUE,
+ &hkey))
+ {
+ result = RegQueryValueExA(
+ hkey,
+ "TimeZoneKeyName",
+ NULL,
+ NULL,
+ (LPBYTE)tzKeyName,
+ &cbData);
+ }
+
+ return result;
+}
+
/*
This code attempts to detect the Windows time zone, as set in the
Windows Date and Time control panel. It attempts to work on
UErrorCode status = U_ZERO_ERROR;
UResourceBundle* bundle = NULL;
char* icuid = NULL;
- UChar apiStd[MAX_LENGTH_ID];
char apiStdName[MAX_LENGTH_ID];
- char regStdName[MAX_LENGTH_ID];
+ char regStdName[MAX_LENGTH_ID];
char tmpid[MAX_LENGTH_ID];
- int32_t apiStdLength = 0;
int32_t len;
+ int id;
+ int errorCode;
+ UChar ISOcodeW[3]; /* 2 letter iso code in UTF-16*/
+ char ISOcodeA[3]; /* 2 letter iso code in ansi */
LONG result;
TZI tziKey;
TZI tziReg;
TIME_ZONE_INFORMATION apiTZI;
+ BOOL isVistaOrHigher;
+ BOOL tryPreVistaFallback;
+ OSVERSIONINFO osVerInfo;
+
/* Obtain TIME_ZONE_INFORMATION from the API, and then convert it
to TZI. We could also interrogate the registry directly; we do
this below if needed. */
/* Convert the wchar_t* standard name to char* */
uprv_memset(apiStdName, 0, sizeof(apiStdName));
- u_strFromWCS(apiStd, MAX_LENGTH_ID, &apiStdLength, apiTZI.StandardName, -1, &status);
- u_austrncpy(apiStdName, apiStd, apiStdLength);
+ wcstombs(apiStdName, apiTZI.StandardName, MAX_LENGTH_ID);
tmpid[0] = 0;
+ id = GetUserGeoID(GEOCLASS_NATION);
+ errorCode = GetGeoInfoW(id,GEO_ISO2,ISOcodeW,3,0);
+ u_strToUTF8(ISOcodeA, 3, NULL, ISOcodeW, 3, &status);
+
bundle = ures_openDirect(NULL, "windowsZones", &status);
ures_getByKey(bundle, "mapTimezones", bundle, &status);
- /* Note: We get the winid not from static tables but from resource bundle. */
- while (U_SUCCESS(status) && ures_hasNext(bundle)) {
- UBool idFound = FALSE;
- const char* winid;
- UResourceBundle* winTZ = ures_getNextResource(bundle, NULL, &status);
- if (U_FAILURE(status)) {
- break;
+ /*
+ Windows Vista+ provides us with a "TimeZoneKeyName" that is not localized
+ and can be used to directly map a name in our bundle. Try to use that first
+ if we're on Vista or higher
+ */
+ uprv_memset(&osVerInfo, 0, sizeof(osVerInfo));
+ osVerInfo.dwOSVersionInfoSize = sizeof(osVerInfo);
+ GetVersionEx(&osVerInfo);
+ isVistaOrHigher = osVerInfo.dwMajorVersion >= 6; /* actually includes Windows Server 2008 as well, but don't worry about it */
+ tryPreVistaFallback = TRUE;
+ if(isVistaOrHigher) {
+ result = getTZKeyName(regStdName, sizeof(regStdName));
+ if(ERROR_SUCCESS == result) {
+ UResourceBundle* winTZ = ures_getByKey(bundle, regStdName, NULL, &status);
+ if(U_SUCCESS(status)) {
+ const UChar* icuTZ = NULL;
+ if (errorCode != 0) {
+ icuTZ = ures_getStringByKey(winTZ, ISOcodeA, &len, &status);
+ }
+ if (errorCode==0 || icuTZ==NULL) {
+ /* fallback to default "001" and reset status */
+ status = U_ZERO_ERROR;
+ icuTZ = ures_getStringByKey(winTZ, "001", &len, &status);
+ }
+
+ if(U_SUCCESS(status)) {
+ int index=0;
+ while (! (*icuTZ == '\0' || *icuTZ ==' ')) {
+ tmpid[index++]=(char)(*icuTZ++); /* safe to assume 'char' is ASCII compatible on windows */
+ }
+ tmpid[index]='\0';
+ tryPreVistaFallback = FALSE;
+ }
+ }
+ ures_close(winTZ);
}
- winid = ures_getKey(winTZ);
- result = getTZI(winid, &tziReg);
+ }
- if (result == ERROR_SUCCESS) {
- /* Windows alters the DaylightBias in some situations.
- Using the bias and the rules suffices, so overwrite
- these unreliable fields. */
- tziKey.standardBias = tziReg.standardBias;
- tziKey.daylightBias = tziReg.daylightBias;
-
- if (uprv_memcmp((char *)&tziKey, (char*)&tziReg, sizeof(tziKey)) == 0) {
- const UChar* icuTZ = ures_getStringByKey(winTZ, "001", &len, &status);
- if (U_SUCCESS(status)) {
- /* Get the standard name from the registry key to compare with
- the one from Windows API call. */
- uprv_memset(regStdName, 0, sizeof(regStdName));
- result = getSTDName(winid, regStdName, sizeof(regStdName));
- if (result == ERROR_SUCCESS) {
- if (uprv_strcmp(apiStdName, regStdName) == 0) {
- idFound = TRUE;
- }
+ if(tryPreVistaFallback) {
+
+ /* Note: We get the winid not from static tables but from resource bundle. */
+ while (U_SUCCESS(status) && ures_hasNext(bundle)) {
+ UBool idFound = FALSE;
+ const char* winid;
+ UResourceBundle* winTZ = ures_getNextResource(bundle, NULL, &status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ winid = ures_getKey(winTZ);
+ result = getTZI(winid, &tziReg);
+
+ if (result == ERROR_SUCCESS) {
+ /* Windows alters the DaylightBias in some situations.
+ Using the bias and the rules suffices, so overwrite
+ these unreliable fields. */
+ tziKey.standardBias = tziReg.standardBias;
+ tziKey.daylightBias = tziReg.daylightBias;
+
+ if (uprv_memcmp((char *)&tziKey, (char*)&tziReg, sizeof(tziKey)) == 0) {
+ const UChar* icuTZ = NULL;
+ if (errorCode != 0) {
+ icuTZ = ures_getStringByKey(winTZ, ISOcodeA, &len, &status);
}
+ if (errorCode==0 || icuTZ==NULL) {
+ /* fallback to default "001" and reset status */
+ status = U_ZERO_ERROR;
+ icuTZ = ures_getStringByKey(winTZ, "001", &len, &status);
+ }
+
+ if (U_SUCCESS(status)) {
+ /* Get the standard name from the registry key to compare with
+ the one from Windows API call. */
+ uprv_memset(regStdName, 0, sizeof(regStdName));
+ result = getSTDName(winid, regStdName, sizeof(regStdName));
+ if (result == ERROR_SUCCESS) {
+ if (uprv_strcmp(apiStdName, regStdName) == 0) {
+ idFound = TRUE;
+ }
+ }
- /* tmpid buffer holds the ICU timezone ID corresponding to the timezone ID from Windows.
- * If none is found, tmpid buffer will contain a fallback ID (i.e. the time zone ID matching
- * the current time zone information)
- */
- if (idFound || tmpid[0] == 0) {
- uprv_memset(tmpid, 0, sizeof(tmpid));
- u_austrncpy(tmpid, icuTZ, len);
+ /* tmpid buffer holds the ICU timezone ID corresponding to the timezone ID from Windows.
+ * If none is found, tmpid buffer will contain a fallback ID (i.e. the time zone ID matching
+ * the current time zone information)
+ */
+ if (idFound || tmpid[0] == 0) {
+ /* if icuTZ has more than one city, take only the first (i.e. terminate icuTZ at first space) */
+ int index=0;
+ while (! (*icuTZ == '\0' || *icuTZ ==' ')) {
+ tmpid[index++]=(char)(*icuTZ++); /* safe to assume 'char' is ASCII compatible on windows */
+ }
+ tmpid[index]='\0';
+ }
}
}
}
- }
- ures_close(winTZ);
- if (idFound) {
- break;
+ ures_close(winTZ);
+ if (idFound) {
+ break;
+ }
}
}
}
ures_close(bundle);
-
+
return icuid;
}