| /* |
| ******************************************************************************** |
| * Copyright (C) 2005-2006, International Business Machines |
| * Corporation and others. All Rights Reserved. |
| ******************************************************************************** |
| * |
| * File WINTZ.CPP |
| * |
| ******************************************************************************** |
| */ |
| |
| #include "unicode/utypes.h" |
| |
| #ifdef U_WINDOWS |
| |
| #include "wintz.h" |
| |
| #include "cmemory.h" |
| #include "cstring.h" |
| |
| #include "unicode/ustring.h" |
| |
| # define WIN32_LEAN_AND_MEAN |
| # define VC_EXTRALEAN |
| # define NOUSER |
| # define NOSERVICE |
| # define NOIME |
| # define NOMCX |
| #include <windows.h> |
| |
| #define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) |
| #define NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type)) |
| #define DELETE_ARRAY(array) uprv_free((void *) (array)) |
| |
| #define ICUID_STACK_BUFFER_SIZE 32 |
| |
| /* The layout of the Tzi value in the registry */ |
| typedef struct |
| { |
| int32_t bias; |
| int32_t standardBias; |
| int32_t daylightBias; |
| SYSTEMTIME standardDate; |
| SYSTEMTIME daylightDate; |
| } TZI; |
| |
| typedef struct |
| { |
| const char *icuid; |
| const char *winid; |
| } WindowsICUMap; |
| |
| typedef struct { |
| const char* winid; |
| const char* altwinid; |
| } WindowsZoneRemap; |
| |
| /** |
| * 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_TIME_REGKEY[] = " Standard Time"; |
| static const char TZI_REGKEY[] = "TZI"; |
| static const char STD_REGKEY[] = "Std"; |
| |
| /** |
| * HKLM subkeys used to probe for the flavor of Windows. Note that we |
| * specifically check for the "GMT" zone subkey; this is present on |
| * NT, but on XP has become "GMT Standard Time". We need to |
| * discriminate between these cases. |
| */ |
| static const char* const WIN_TYPE_PROBE_REGKEY[] = { |
| /* WIN_9X_ME_TYPE */ |
| "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones", |
| |
| /* WIN_NT_TYPE */ |
| "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\GMT" |
| |
| /* otherwise: WIN_2K_XP_TYPE */ |
| }; |
| |
| /** |
| * The time zone root subkeys (under HKLM) for different flavors of |
| * Windows. |
| */ |
| static const char* const TZ_REGKEY[] = { |
| /* WIN_9X_ME_TYPE */ |
| "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones\\", |
| |
| /* WIN_NT_TYPE | WIN_2K_XP_TYPE */ |
| "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\" |
| }; |
| |
| /** |
| * Flavor of Windows, from our perspective. Not a real OS version, |
| * but rather the flavor of the layout of the time zone information in |
| * the registry. |
| */ |
| enum { |
| WIN_9X_ME_TYPE = 0, |
| WIN_NT_TYPE = 1, |
| WIN_2K_XP_TYPE = 2 |
| }; |
| |
| /* |
| * TODO: Sort on ICU ID? |
| * TODO: This data should come from ICU/CLDR... |
| */ |
| static const WindowsICUMap ZONE_MAP[] = { |
| {"Etc/GMT+12", "Dateline"}, /* S (GMT-12:00) International Date Line West */ |
| |
| {"Pacific/Apia", "Samoa"}, /* S (GMT-11:00) Midway Island, Samoa */ |
| |
| {"Pacific/Honolulu", "Hawaiian"}, /* S (GMT-10:00) Hawaii */ |
| |
| {"America/Anchorage", "Alaskan"}, /* D (GMT-09:00) Alaska */ |
| |
| {"America/Los_Angeles", "Pacific"}, /* D (GMT-08:00) Pacific Time (US & Canada); Tijuana */ |
| |
| {"America/Phoenix", "US Mountain"}, /* S (GMT-07:00) Arizona */ |
| {"America/Denver", "Mountain"}, /* D (GMT-07:00) Mountain Time (US & Canada) */ |
| {"America/Chihuahua", "Mexico Standard Time 2"}, /* D (GMT-07:00) Chihuahua, La Paz, Mazatlan */ |
| |
| {"America/Managua", "Central America"}, /* S (GMT-06:00) Central America */ |
| {"America/Regina", "Canada Central"}, /* S (GMT-06:00) Saskatchewan */ |
| {"America/Mexico_City", "Mexico"}, /* D (GMT-06:00) Guadalajara, Mexico City, Monterrey */ |
| {"America/Chicago", "Central"}, /* D (GMT-06:00) Central Time (US & Canada) */ |
| |
| {"America/Indianapolis", "US Eastern"}, /* S (GMT-05:00) Indiana (East) */ |
| {"America/Bogota", "SA Pacific"}, /* S (GMT-05:00) Bogota, Lima, Quito */ |
| {"America/New_York", "Eastern"}, /* D (GMT-05:00) Eastern Time (US & Canada) */ |
| |
| {"America/Caracas", "SA Western"}, /* S (GMT-04:00) Caracas, La Paz */ |
| {"America/Santiago", "Pacific SA"}, /* D (GMT-04:00) Santiago */ |
| {"America/Halifax", "Atlantic"}, /* D (GMT-04:00) Atlantic Time (Canada) */ |
| |
| {"America/St_Johns", "Newfoundland"}, /* D (GMT-03:30) Newfoundland */ |
| |
| {"America/Buenos_Aires", "SA Eastern"}, /* S (GMT-03:00) Buenos Aires, Georgetown */ |
| {"America/Godthab", "Greenland"}, /* D (GMT-03:00) Greenland */ |
| {"America/Sao_Paulo", "E. South America"}, /* D (GMT-03:00) Brasilia */ |
| |
| {"America/Noronha", "Mid-Atlantic"}, /* D (GMT-02:00) Mid-Atlantic */ |
| |
| {"Atlantic/Cape_Verde", "Cape Verde"}, /* S (GMT-01:00) Cape Verde Is. */ |
| {"Atlantic/Azores", "Azores"}, /* D (GMT-01:00) Azores */ |
| |
| {"Africa/Casablanca", "Greenwich"}, /* S (GMT) Casablanca, Monrovia */ |
| {"Europe/London", "GMT"}, /* D (GMT) Greenwich Mean Time : Dublin, Edinburgh, Lisbon, London */ |
| |
| {"Africa/Lagos", "W. Central Africa"}, /* S (GMT+01:00) West Central Africa */ |
| {"Europe/Berlin", "W. Europe"}, /* D (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna */ |
| {"Europe/Paris", "Romance"}, /* D (GMT+01:00) Brussels, Copenhagen, Madrid, Paris */ |
| {"Europe/Sarajevo", "Central European"}, /* D (GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb */ |
| {"Europe/Belgrade", "Central Europe"}, /* D (GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague */ |
| |
| {"Africa/Johannesburg", "South Africa"}, /* S (GMT+02:00) Harare, Pretoria */ |
| {"Asia/Jerusalem", "Israel"}, /* S (GMT+02:00) Jerusalem */ |
| {"Europe/Istanbul", "GTB"}, /* D (GMT+02:00) Athens, Istanbul, Minsk */ |
| {"Europe/Helsinki", "FLE"}, /* D (GMT+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius */ |
| {"Africa/Cairo", "Egypt"}, /* D (GMT+02:00) Cairo */ |
| {"Europe/Bucharest", "E. Europe"}, /* D (GMT+02:00) Bucharest */ |
| |
| {"Africa/Nairobi", "E. Africa"}, /* S (GMT+03:00) Nairobi */ |
| {"Asia/Riyadh", "Arab"}, /* S (GMT+03:00) Kuwait, Riyadh */ |
| {"Europe/Moscow", "Russian"}, /* D (GMT+03:00) Moscow, St. Petersburg, Volgograd */ |
| {"Asia/Baghdad", "Arabic"}, /* D (GMT+03:00) Baghdad */ |
| |
| {"Asia/Tehran", "Iran"}, /* D (GMT+03:30) Tehran */ |
| |
| {"Asia/Muscat", "Arabian"}, /* S (GMT+04:00) Abu Dhabi, Muscat */ |
| {"Asia/Tbilisi", "Caucasus"}, /* D (GMT+04:00) Baku, Tbilisi, Yerevan */ |
| |
| {"Asia/Kabul", "Afghanistan"}, /* S (GMT+04:30) Kabul */ |
| |
| {"Asia/Karachi", "West Asia"}, /* S (GMT+05:00) Islamabad, Karachi, Tashkent */ |
| {"Asia/Yekaterinburg", "Ekaterinburg"}, /* D (GMT+05:00) Ekaterinburg */ |
| |
| {"Asia/Calcutta", "India"}, /* S (GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi */ |
| |
| {"Asia/Katmandu", "Nepal"}, /* S (GMT+05:45) Kathmandu */ |
| |
| {"Asia/Colombo", "Sri Lanka"}, /* S (GMT+06:00) Sri Jayawardenepura */ |
| {"Asia/Dhaka", "Central Asia"}, /* S (GMT+06:00) Astana, Dhaka */ |
| {"Asia/Novosibirsk", "N. Central Asia"}, /* D (GMT+06:00) Almaty, Novosibirsk */ |
| |
| {"Asia/Rangoon", "Myanmar"}, /* S (GMT+06:30) Rangoon */ |
| |
| {"Asia/Bangkok", "SE Asia"}, /* S (GMT+07:00) Bangkok, Hanoi, Jakarta */ |
| {"Asia/Krasnoyarsk", "North Asia"}, /* D (GMT+07:00) Krasnoyarsk */ |
| |
| {"Australia/Perth", "W. Australia"}, /* S (GMT+08:00) Perth */ |
| {"Asia/Taipei", "Taipei"}, /* S (GMT+08:00) Taipei */ |
| {"Asia/Singapore", "Singapore"}, /* S (GMT+08:00) Kuala Lumpur, Singapore */ |
| {"Asia/Hong_Kong", "China"}, /* S (GMT+08:00) Beijing, Chongqing, Hong Kong, Urumqi */ |
| {"Asia/Irkutsk", "North Asia East"}, /* D (GMT+08:00) Irkutsk, Ulaan Bataar */ |
| |
| {"Asia/Tokyo", "Tokyo"}, /* S (GMT+09:00) Osaka, Sapporo, Tokyo */ |
| {"Asia/Seoul", "Korea"}, /* S (GMT+09:00) Seoul */ |
| {"Asia/Yakutsk", "Yakutsk"}, /* D (GMT+09:00) Yakutsk */ |
| |
| {"Australia/Darwin", "AUS Central"}, /* S (GMT+09:30) Darwin */ |
| {"Australia/Adelaide", "Cen. Australia"}, /* D (GMT+09:30) Adelaide */ |
| |
| {"Pacific/Guam", "West Pacific"}, /* S (GMT+10:00) Guam, Port Moresby */ |
| {"Australia/Brisbane", "E. Australia"}, /* S (GMT+10:00) Brisbane */ |
| {"Asia/Vladivostok", "Vladivostok"}, /* D (GMT+10:00) Vladivostok */ |
| {"Australia/Hobart", "Tasmania"}, /* D (GMT+10:00) Hobart */ |
| {"Australia/Sydney", "AUS Eastern"}, /* D (GMT+10:00) Canberra, Melbourne, Sydney */ |
| |
| {"Asia/Magadan", "Central Pacific"}, /* S (GMT+11:00) Magadan, Solomon Is., New Caledonia */ |
| |
| {"Pacific/Fiji", "Fiji"}, /* S (GMT+12:00) Fiji, Kamchatka, Marshall Is. */ |
| {"Pacific/Auckland", "New Zealand"}, /* D (GMT+12:00) Auckland, Wellington */ |
| |
| {"Pacific/Tongatapu", "Tonga"}, /* S (GMT+13:00) Nuku'alofa */ |
| NULL, NULL |
| }; |
| |
| /** |
| * If a lookup fails, we attempt to remap certain Windows ids to |
| * alternate Windows ids. If the alternate listed here begins with |
| * '-', we use it as is (without the '-'). If it begins with '+', we |
| * append a " Standard Time" if appropriate. |
| */ |
| static const WindowsZoneRemap ZONE_REMAP[] = { |
| "Central European", "-Warsaw", |
| "Central Europe", "-Prague Bratislava", |
| "China", "-Beijing", |
| |
| "Greenwich", "+GMT", |
| "GTB", "+GFT", |
| "Arab", "+Saudi Arabia", |
| "SE Asia", "+Bangkok", |
| "AUS Eastern", "+Sydney", |
| NULL, NULL, |
| }; |
| |
| static int32_t fWinType = -1; |
| |
| static int32_t detectWindowsType() |
| { |
| int32_t winType; |
| LONG result; |
| HKEY hkey; |
| |
| /* Detect the version of windows by trying to open a sequence of |
| probe keys. We don't use the OS version API because what we |
| really want to know is how the registry is laid out. |
| Specifically, is it 9x/Me or not, and is it "GMT" or "GMT |
| Standard Time". */ |
| for (winType = 0; winType < 2; winType += 1) { |
| result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, |
| WIN_TYPE_PROBE_REGKEY[winType], |
| 0, |
| KEY_QUERY_VALUE, |
| &hkey); |
| RegCloseKey(hkey); |
| |
| if (result == ERROR_SUCCESS) { |
| break; |
| } |
| } |
| |
| return winType; |
| } |
| |
| /* |
| * TODO: Binary search sorted ZONE_MAP... |
| * (u_detectWindowsTimeZone() needs them sorted by offset...) |
| */ |
| static const char *findWindowsZoneID(const UChar *icuid, int32_t length) |
| { |
| char stackBuffer[ICUID_STACK_BUFFER_SIZE]; |
| char *buffer = stackBuffer; |
| const char *result = NULL; |
| int i; |
| |
| /* |
| * NOTE: >= because length doesn't include |
| * trailing null. |
| */ |
| if (length >= ICUID_STACK_BUFFER_SIZE) { |
| buffer = NEW_ARRAY(char, length + 1); |
| } |
| |
| u_UCharsToChars(icuid, buffer, length); |
| buffer[length] = '\0'; |
| |
| for (i = 0; ZONE_MAP[i].icuid != NULL; i += 1) { |
| if (uprv_strcmp(buffer, ZONE_MAP[i].icuid) == 0) { |
| result = ZONE_MAP[i].winid; |
| break; |
| } |
| } |
| |
| if (buffer != stackBuffer) { |
| DELETE_ARRAY(buffer); |
| } |
| |
| return result; |
| } |
| |
| static LONG openTZRegKey(HKEY *hkey, const char *winid) |
| { |
| char subKeyName[96]; /* TODO: why 96?? */ |
| char *name; |
| LONG result; |
| |
| /* TODO: This isn't thread safe, but it's probably good enough. */ |
| if (fWinType < 0) { |
| fWinType = detectWindowsType(); |
| } |
| |
| uprv_strcpy(subKeyName, TZ_REGKEY[(fWinType == WIN_9X_ME_TYPE) ? 0 : 1]); |
| name = &subKeyName[strlen(subKeyName)]; |
| uprv_strcat(subKeyName, winid); |
| |
| if (fWinType != WIN_9X_ME_TYPE && |
| (winid[strlen(winid) - 1] != '2') && |
| !(fWinType == WIN_NT_TYPE && strcmp(winid, "GMT") == 0)) { |
| uprv_strcat(subKeyName, STANDARD_TIME_REGKEY); |
| } |
| |
| result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, |
| subKeyName, |
| 0, |
| KEY_QUERY_VALUE, |
| hkey); |
| |
| if (result != ERROR_SUCCESS) { |
| int i; |
| |
| /* If the primary lookup fails, try to remap the Windows zone |
| ID, according to the remapping table. */ |
| for (i=0; ZONE_REMAP[i].winid; i++) { |
| if (uprv_strcmp(winid, ZONE_REMAP[i].winid) == 0) { |
| uprv_strcpy(name, ZONE_REMAP[i].altwinid + 1); |
| if (*(ZONE_REMAP[i].altwinid) == '+' && fWinType != WIN_9X_ME_TYPE) { |
| uprv_strcat(subKeyName, STANDARD_TIME_REGKEY); |
| } |
| return RegOpenKeyEx(HKEY_LOCAL_MACHINE, |
| subKeyName, |
| 0, |
| KEY_QUERY_VALUE, |
| hkey); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| static LONG getTZI(const char *winid, TZI *tzi) |
| { |
| DWORD cbData = sizeof(TZI); |
| LONG result; |
| HKEY hkey; |
| |
| result = openTZRegKey(&hkey, winid); |
| |
| if (result == ERROR_SUCCESS) { |
| result = RegQueryValueEx(hkey, |
| TZI_REGKEY, |
| NULL, |
| NULL, |
| (LPBYTE)tzi, |
| &cbData); |
| |
| } |
| |
| RegCloseKey(hkey); |
| |
| return result; |
| } |
| |
| U_CAPI UBool U_EXPORT2 |
| uprv_getWindowsTimeZoneInfo(TIME_ZONE_INFORMATION *zoneInfo, const UChar *icuid, int32_t length) |
| { |
| const char *winid; |
| TZI tzi; |
| LONG result; |
| |
| winid = findWindowsZoneID(icuid, length); |
| |
| if (winid != NULL) { |
| result = getTZI(winid, &tzi); |
| |
| if (result == ERROR_SUCCESS) { |
| zoneInfo->Bias = tzi.bias; |
| zoneInfo->DaylightBias = tzi.daylightBias; |
| zoneInfo->StandardBias = tzi.standardBias; |
| zoneInfo->DaylightDate = tzi.daylightDate; |
| zoneInfo->StandardDate = tzi.standardDate; |
| |
| return TRUE; |
| } |
| } |
| |
| return FALSE; |
| } |
| |
| /* |
| This code attempts to detect the Windows time zone, as set in the |
| Windows Date and Time control panel. It attempts to work on |
| multiple flavors of Windows (9x, Me, NT, 2000, XP) and on localized |
| installs. It works by directly interrogating the registry and |
| comparing the data there with the data returned by the |
| GetTimeZoneInformation API, along with some other strategies. The |
| registry contains time zone data under one of two keys (depending on |
| the flavor of Windows): |
| |
| HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones\ |
| HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\ |
| |
| Under this key are several subkeys, one for each time zone. These |
| subkeys are named "Pacific" on Win9x/Me and "Pacific Standard Time" |
| on WinNT/2k/XP. There are some other wrinkles; see the code for |
| details. The subkey name is NOT LOCALIZED, allowing us to support |
| localized installs. |
| |
| Under the subkey are data values. We care about: |
| |
| Std Standard time display name, localized |
| TZI Binary block of data |
| |
| The TZI data is of particular interest. It contains the offset, two |
| more offsets for standard and daylight time, and the start and end |
| rules. This is the same data returned by the GetTimeZoneInformation |
| API. The API may modify the data on the way out, so we have to be |
| careful, but essentially we do a binary comparison against the TZI |
| blocks of various registry keys. When we find a match, we know what |
| time zone Windows is set to. Since the registry key is not |
| localized, we can then translate the key through a simple table |
| lookup into the corresponding ICU time zone. |
| |
| This strategy doesn't always work because there are zones which |
| share an offset and rules, so more than one TZI block will match. |
| For example, both Tokyo and Seoul are at GMT+9 with no DST rules; |
| their TZI blocks are identical. For these cases, we fall back to a |
| name lookup. We attempt to match the display name as stored in the |
| registry for the current zone to the display name stored in the |
| registry for various Windows zones. By comparing the registry data |
| directly we avoid conversion complications. |
| |
| Author: Alan Liu |
| Since: ICU 2.6 |
| Based on original code by Carl Brown <cbrown@xnetinc.com> |
| */ |
| |
| /** |
| * Main Windows time zone detection function. Returns the Windows |
| * time zone, translated to an ICU time zone, or NULL upon failure. |
| */ |
| U_CAPI const char* U_EXPORT2 |
| uprv_detectWindowsTimeZone() { |
| LONG result; |
| HKEY hkey; |
| TZI tziKey; |
| TZI tziReg; |
| TIME_ZONE_INFORMATION apiTZI; |
| int firstMatch, lastMatch; |
| int j; |
| |
| /* 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. */ |
| uprv_memset(&apiTZI, 0, sizeof(apiTZI)); |
| uprv_memset(&tziKey, 0, sizeof(tziKey)); |
| uprv_memset(&tziReg, 0, sizeof(tziReg)); |
| GetTimeZoneInformation(&apiTZI); |
| tziKey.bias = apiTZI.Bias; |
| uprv_memcpy((char *)&tziKey.standardDate, (char*)&apiTZI.StandardDate, |
| sizeof(apiTZI.StandardDate)); |
| uprv_memcpy((char *)&tziKey.daylightDate, (char*)&apiTZI.DaylightDate, |
| sizeof(apiTZI.DaylightDate)); |
| |
| /* For each zone that can be identified by Offset+Rules, see if we |
| have a match. Continue scanning after finding a match, |
| recording the index of the first and the last match. We have |
| to do this because some zones are not unique under |
| Offset+Rules. */ |
| firstMatch = -1; |
| lastMatch = -1; |
| for (j=0; ZONE_MAP[j].icuid; j++) { |
| result = getTZI(ZONE_MAP[j].winid, &tziReg); |
| |
| if (result == ERROR_SUCCESS) { |
| /* Assume that offsets are grouped together, and bail out |
| when we've scanned everything with a matching |
| offset. */ |
| if (firstMatch >= 0 && tziKey.bias != tziReg.bias) { |
| break; |
| } |
| |
| /* 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) { |
| if (firstMatch < 0) { |
| firstMatch = j; |
| } |
| |
| lastMatch = j; |
| } |
| } |
| } |
| |
| /* This should never happen; if it does it means our table doesn't |
| match Windows AT ALL, perhaps because this is post-XP? */ |
| if (firstMatch < 0) { |
| return NULL; |
| } |
| |
| if (firstMatch != lastMatch) { |
| char stdName[32]; |
| DWORD stdNameSize; |
| char stdRegName[64]; |
| DWORD stdRegNameSize; |
| |
| /* Offset+Rules lookup yielded >= 2 matches. Try to match the |
| localized display name. Get the name from the registry |
| (not the API). This avoids conversion issues. Use the |
| standard name, since Windows modifies the daylight name to |
| match the standard name if there is no DST. */ |
| if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, |
| CURRENT_ZONE_REGKEY, |
| 0, |
| KEY_QUERY_VALUE, |
| &hkey) == ERROR_SUCCESS) |
| { |
| stdNameSize = sizeof(stdName); |
| result = RegQueryValueEx(hkey, |
| (LPTSTR)STANDARD_NAME_REGKEY, |
| NULL, |
| NULL, |
| (LPBYTE)stdName, |
| &stdNameSize); |
| RegCloseKey(hkey); |
| |
| /* |
| * Scan through the Windows time zone data in the registry |
| * again (just the range of zones with matching TZIs) and |
| * look for a standard display name match. |
| */ |
| for (j = firstMatch; j <= lastMatch; j += 1) { |
| stdRegNameSize = sizeof(stdRegName); |
| result = openTZRegKey(&hkey, ZONE_MAP[j].winid); |
| |
| if (result == ERROR_SUCCESS) { |
| result = RegQueryValueEx(hkey, |
| (LPTSTR)STD_REGKEY, |
| NULL, |
| NULL, |
| (LPBYTE)stdRegName, |
| &stdRegNameSize); |
| } |
| |
| RegCloseKey(hkey); |
| |
| if (result == ERROR_SUCCESS && |
| stdRegNameSize == stdNameSize && |
| uprv_memcmp(stdName, stdRegName, stdNameSize) == 0) |
| { |
| firstMatch = j; /* record the match */ |
| break; |
| } |
| } |
| } else { |
| RegCloseKey(hkey); /* should never get here */ |
| } |
| } |
| |
| return ZONE_MAP[firstMatch].icuid; |
| } |
| |
| #endif /* #ifdef U_WINDOWS */ |