]> git.saurik.com Git - apple/icu.git/blob - icuSources/common/wintz.c
ICU-8.11.tar.gz
[apple/icu.git] / icuSources / common / wintz.c
1 /*
2 ********************************************************************************
3 * Copyright (C) 2005-2006, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 ********************************************************************************
6 *
7 * File WINTZ.CPP
8 *
9 ********************************************************************************
10 */
11
12 #include "unicode/utypes.h"
13
14 #ifdef U_WINDOWS
15
16 #include "wintz.h"
17
18 #include "cmemory.h"
19 #include "cstring.h"
20
21 #include "unicode/ustring.h"
22
23 # define WIN32_LEAN_AND_MEAN
24 # define VC_EXTRALEAN
25 # define NOUSER
26 # define NOSERVICE
27 # define NOIME
28 # define NOMCX
29 #include <windows.h>
30
31 #define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
32 #define NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type))
33 #define DELETE_ARRAY(array) uprv_free((void *) (array))
34
35 #define ICUID_STACK_BUFFER_SIZE 32
36
37 /* The layout of the Tzi value in the registry */
38 typedef struct
39 {
40 int32_t bias;
41 int32_t standardBias;
42 int32_t daylightBias;
43 SYSTEMTIME standardDate;
44 SYSTEMTIME daylightDate;
45 } TZI;
46
47 typedef struct
48 {
49 const char *icuid;
50 const char *winid;
51 } WindowsICUMap;
52
53 typedef struct {
54 const char* winid;
55 const char* altwinid;
56 } WindowsZoneRemap;
57
58 /**
59 * Various registry keys and key fragments.
60 */
61 static const char CURRENT_ZONE_REGKEY[] = "SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation\\";
62 static const char STANDARD_NAME_REGKEY[] = "StandardName";
63 static const char STANDARD_TIME_REGKEY[] = " Standard Time";
64 static const char TZI_REGKEY[] = "TZI";
65 static const char STD_REGKEY[] = "Std";
66
67 /**
68 * HKLM subkeys used to probe for the flavor of Windows. Note that we
69 * specifically check for the "GMT" zone subkey; this is present on
70 * NT, but on XP has become "GMT Standard Time". We need to
71 * discriminate between these cases.
72 */
73 static const char* const WIN_TYPE_PROBE_REGKEY[] = {
74 /* WIN_9X_ME_TYPE */
75 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones",
76
77 /* WIN_NT_TYPE */
78 "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\GMT"
79
80 /* otherwise: WIN_2K_XP_TYPE */
81 };
82
83 /**
84 * The time zone root subkeys (under HKLM) for different flavors of
85 * Windows.
86 */
87 static const char* const TZ_REGKEY[] = {
88 /* WIN_9X_ME_TYPE */
89 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones\\",
90
91 /* WIN_NT_TYPE | WIN_2K_XP_TYPE */
92 "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\"
93 };
94
95 /**
96 * Flavor of Windows, from our perspective. Not a real OS version,
97 * but rather the flavor of the layout of the time zone information in
98 * the registry.
99 */
100 enum {
101 WIN_9X_ME_TYPE = 0,
102 WIN_NT_TYPE = 1,
103 WIN_2K_XP_TYPE = 2
104 };
105
106 /*
107 * TODO: Sort on ICU ID?
108 * TODO: This data should come from ICU/CLDR...
109 */
110 static const WindowsICUMap ZONE_MAP[] = {
111 {"Etc/GMT+12", "Dateline"}, /* S (GMT-12:00) International Date Line West */
112
113 {"Pacific/Apia", "Samoa"}, /* S (GMT-11:00) Midway Island, Samoa */
114
115 {"Pacific/Honolulu", "Hawaiian"}, /* S (GMT-10:00) Hawaii */
116
117 {"America/Anchorage", "Alaskan"}, /* D (GMT-09:00) Alaska */
118
119 {"America/Los_Angeles", "Pacific"}, /* D (GMT-08:00) Pacific Time (US & Canada); Tijuana */
120
121 {"America/Phoenix", "US Mountain"}, /* S (GMT-07:00) Arizona */
122 {"America/Denver", "Mountain"}, /* D (GMT-07:00) Mountain Time (US & Canada) */
123 {"America/Chihuahua", "Mexico Standard Time 2"}, /* D (GMT-07:00) Chihuahua, La Paz, Mazatlan */
124
125 {"America/Managua", "Central America"}, /* S (GMT-06:00) Central America */
126 {"America/Regina", "Canada Central"}, /* S (GMT-06:00) Saskatchewan */
127 {"America/Mexico_City", "Mexico"}, /* D (GMT-06:00) Guadalajara, Mexico City, Monterrey */
128 {"America/Chicago", "Central"}, /* D (GMT-06:00) Central Time (US & Canada) */
129
130 {"America/Indianapolis", "US Eastern"}, /* S (GMT-05:00) Indiana (East) */
131 {"America/Bogota", "SA Pacific"}, /* S (GMT-05:00) Bogota, Lima, Quito */
132 {"America/New_York", "Eastern"}, /* D (GMT-05:00) Eastern Time (US & Canada) */
133
134 {"America/Caracas", "SA Western"}, /* S (GMT-04:00) Caracas, La Paz */
135 {"America/Santiago", "Pacific SA"}, /* D (GMT-04:00) Santiago */
136 {"America/Halifax", "Atlantic"}, /* D (GMT-04:00) Atlantic Time (Canada) */
137
138 {"America/St_Johns", "Newfoundland"}, /* D (GMT-03:30) Newfoundland */
139
140 {"America/Buenos_Aires", "SA Eastern"}, /* S (GMT-03:00) Buenos Aires, Georgetown */
141 {"America/Godthab", "Greenland"}, /* D (GMT-03:00) Greenland */
142 {"America/Sao_Paulo", "E. South America"}, /* D (GMT-03:00) Brasilia */
143
144 {"America/Noronha", "Mid-Atlantic"}, /* D (GMT-02:00) Mid-Atlantic */
145
146 {"Atlantic/Cape_Verde", "Cape Verde"}, /* S (GMT-01:00) Cape Verde Is. */
147 {"Atlantic/Azores", "Azores"}, /* D (GMT-01:00) Azores */
148
149 {"Africa/Casablanca", "Greenwich"}, /* S (GMT) Casablanca, Monrovia */
150 {"Europe/London", "GMT"}, /* D (GMT) Greenwich Mean Time : Dublin, Edinburgh, Lisbon, London */
151
152 {"Africa/Lagos", "W. Central Africa"}, /* S (GMT+01:00) West Central Africa */
153 {"Europe/Berlin", "W. Europe"}, /* D (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna */
154 {"Europe/Paris", "Romance"}, /* D (GMT+01:00) Brussels, Copenhagen, Madrid, Paris */
155 {"Europe/Sarajevo", "Central European"}, /* D (GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb */
156 {"Europe/Belgrade", "Central Europe"}, /* D (GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague */
157
158 {"Africa/Johannesburg", "South Africa"}, /* S (GMT+02:00) Harare, Pretoria */
159 {"Asia/Jerusalem", "Israel"}, /* S (GMT+02:00) Jerusalem */
160 {"Europe/Istanbul", "GTB"}, /* D (GMT+02:00) Athens, Istanbul, Minsk */
161 {"Europe/Helsinki", "FLE"}, /* D (GMT+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius */
162 {"Africa/Cairo", "Egypt"}, /* D (GMT+02:00) Cairo */
163 {"Europe/Bucharest", "E. Europe"}, /* D (GMT+02:00) Bucharest */
164
165 {"Africa/Nairobi", "E. Africa"}, /* S (GMT+03:00) Nairobi */
166 {"Asia/Riyadh", "Arab"}, /* S (GMT+03:00) Kuwait, Riyadh */
167 {"Europe/Moscow", "Russian"}, /* D (GMT+03:00) Moscow, St. Petersburg, Volgograd */
168 {"Asia/Baghdad", "Arabic"}, /* D (GMT+03:00) Baghdad */
169
170 {"Asia/Tehran", "Iran"}, /* D (GMT+03:30) Tehran */
171
172 {"Asia/Muscat", "Arabian"}, /* S (GMT+04:00) Abu Dhabi, Muscat */
173 {"Asia/Tbilisi", "Caucasus"}, /* D (GMT+04:00) Baku, Tbilisi, Yerevan */
174
175 {"Asia/Kabul", "Afghanistan"}, /* S (GMT+04:30) Kabul */
176
177 {"Asia/Karachi", "West Asia"}, /* S (GMT+05:00) Islamabad, Karachi, Tashkent */
178 {"Asia/Yekaterinburg", "Ekaterinburg"}, /* D (GMT+05:00) Ekaterinburg */
179
180 {"Asia/Calcutta", "India"}, /* S (GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi */
181
182 {"Asia/Katmandu", "Nepal"}, /* S (GMT+05:45) Kathmandu */
183
184 {"Asia/Colombo", "Sri Lanka"}, /* S (GMT+06:00) Sri Jayawardenepura */
185 {"Asia/Dhaka", "Central Asia"}, /* S (GMT+06:00) Astana, Dhaka */
186 {"Asia/Novosibirsk", "N. Central Asia"}, /* D (GMT+06:00) Almaty, Novosibirsk */
187
188 {"Asia/Rangoon", "Myanmar"}, /* S (GMT+06:30) Rangoon */
189
190 {"Asia/Bangkok", "SE Asia"}, /* S (GMT+07:00) Bangkok, Hanoi, Jakarta */
191 {"Asia/Krasnoyarsk", "North Asia"}, /* D (GMT+07:00) Krasnoyarsk */
192
193 {"Australia/Perth", "W. Australia"}, /* S (GMT+08:00) Perth */
194 {"Asia/Taipei", "Taipei"}, /* S (GMT+08:00) Taipei */
195 {"Asia/Singapore", "Singapore"}, /* S (GMT+08:00) Kuala Lumpur, Singapore */
196 {"Asia/Hong_Kong", "China"}, /* S (GMT+08:00) Beijing, Chongqing, Hong Kong, Urumqi */
197 {"Asia/Irkutsk", "North Asia East"}, /* D (GMT+08:00) Irkutsk, Ulaan Bataar */
198
199 {"Asia/Tokyo", "Tokyo"}, /* S (GMT+09:00) Osaka, Sapporo, Tokyo */
200 {"Asia/Seoul", "Korea"}, /* S (GMT+09:00) Seoul */
201 {"Asia/Yakutsk", "Yakutsk"}, /* D (GMT+09:00) Yakutsk */
202
203 {"Australia/Darwin", "AUS Central"}, /* S (GMT+09:30) Darwin */
204 {"Australia/Adelaide", "Cen. Australia"}, /* D (GMT+09:30) Adelaide */
205
206 {"Pacific/Guam", "West Pacific"}, /* S (GMT+10:00) Guam, Port Moresby */
207 {"Australia/Brisbane", "E. Australia"}, /* S (GMT+10:00) Brisbane */
208 {"Asia/Vladivostok", "Vladivostok"}, /* D (GMT+10:00) Vladivostok */
209 {"Australia/Hobart", "Tasmania"}, /* D (GMT+10:00) Hobart */
210 {"Australia/Sydney", "AUS Eastern"}, /* D (GMT+10:00) Canberra, Melbourne, Sydney */
211
212 {"Asia/Magadan", "Central Pacific"}, /* S (GMT+11:00) Magadan, Solomon Is., New Caledonia */
213
214 {"Pacific/Fiji", "Fiji"}, /* S (GMT+12:00) Fiji, Kamchatka, Marshall Is. */
215 {"Pacific/Auckland", "New Zealand"}, /* D (GMT+12:00) Auckland, Wellington */
216
217 {"Pacific/Tongatapu", "Tonga"}, /* S (GMT+13:00) Nuku'alofa */
218 NULL, NULL
219 };
220
221 /**
222 * If a lookup fails, we attempt to remap certain Windows ids to
223 * alternate Windows ids. If the alternate listed here begins with
224 * '-', we use it as is (without the '-'). If it begins with '+', we
225 * append a " Standard Time" if appropriate.
226 */
227 static const WindowsZoneRemap ZONE_REMAP[] = {
228 "Central European", "-Warsaw",
229 "Central Europe", "-Prague Bratislava",
230 "China", "-Beijing",
231
232 "Greenwich", "+GMT",
233 "GTB", "+GFT",
234 "Arab", "+Saudi Arabia",
235 "SE Asia", "+Bangkok",
236 "AUS Eastern", "+Sydney",
237 NULL, NULL,
238 };
239
240 static int32_t fWinType = -1;
241
242 static int32_t detectWindowsType()
243 {
244 int32_t winType;
245 LONG result;
246 HKEY hkey;
247
248 /* Detect the version of windows by trying to open a sequence of
249 probe keys. We don't use the OS version API because what we
250 really want to know is how the registry is laid out.
251 Specifically, is it 9x/Me or not, and is it "GMT" or "GMT
252 Standard Time". */
253 for (winType = 0; winType < 2; winType += 1) {
254 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
255 WIN_TYPE_PROBE_REGKEY[winType],
256 0,
257 KEY_QUERY_VALUE,
258 &hkey);
259 RegCloseKey(hkey);
260
261 if (result == ERROR_SUCCESS) {
262 break;
263 }
264 }
265
266 return winType;
267 }
268
269 /*
270 * TODO: Binary search sorted ZONE_MAP...
271 * (u_detectWindowsTimeZone() needs them sorted by offset...)
272 */
273 static const char *findWindowsZoneID(const UChar *icuid, int32_t length)
274 {
275 char stackBuffer[ICUID_STACK_BUFFER_SIZE];
276 char *buffer = stackBuffer;
277 const char *result = NULL;
278 int i;
279
280 /*
281 * NOTE: >= because length doesn't include
282 * trailing null.
283 */
284 if (length >= ICUID_STACK_BUFFER_SIZE) {
285 buffer = NEW_ARRAY(char, length + 1);
286 }
287
288 u_UCharsToChars(icuid, buffer, length);
289 buffer[length] = '\0';
290
291 for (i = 0; ZONE_MAP[i].icuid != NULL; i += 1) {
292 if (uprv_strcmp(buffer, ZONE_MAP[i].icuid) == 0) {
293 result = ZONE_MAP[i].winid;
294 break;
295 }
296 }
297
298 if (buffer != stackBuffer) {
299 DELETE_ARRAY(buffer);
300 }
301
302 return result;
303 }
304
305 static LONG openTZRegKey(HKEY *hkey, const char *winid)
306 {
307 char subKeyName[96]; /* TODO: why 96?? */
308 char *name;
309 LONG result;
310
311 /* TODO: This isn't thread safe, but it's probably good enough. */
312 if (fWinType < 0) {
313 fWinType = detectWindowsType();
314 }
315
316 uprv_strcpy(subKeyName, TZ_REGKEY[(fWinType == WIN_9X_ME_TYPE) ? 0 : 1]);
317 name = &subKeyName[strlen(subKeyName)];
318 uprv_strcat(subKeyName, winid);
319
320 if (fWinType != WIN_9X_ME_TYPE &&
321 (winid[strlen(winid) - 1] != '2') &&
322 !(fWinType == WIN_NT_TYPE && strcmp(winid, "GMT") == 0)) {
323 uprv_strcat(subKeyName, STANDARD_TIME_REGKEY);
324 }
325
326 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
327 subKeyName,
328 0,
329 KEY_QUERY_VALUE,
330 hkey);
331
332 if (result != ERROR_SUCCESS) {
333 int i;
334
335 /* If the primary lookup fails, try to remap the Windows zone
336 ID, according to the remapping table. */
337 for (i=0; ZONE_REMAP[i].winid; i++) {
338 if (uprv_strcmp(winid, ZONE_REMAP[i].winid) == 0) {
339 uprv_strcpy(name, ZONE_REMAP[i].altwinid + 1);
340 if (*(ZONE_REMAP[i].altwinid) == '+' && fWinType != WIN_9X_ME_TYPE) {
341 uprv_strcat(subKeyName, STANDARD_TIME_REGKEY);
342 }
343 return RegOpenKeyEx(HKEY_LOCAL_MACHINE,
344 subKeyName,
345 0,
346 KEY_QUERY_VALUE,
347 hkey);
348 }
349 }
350 }
351
352 return result;
353 }
354
355 static LONG getTZI(const char *winid, TZI *tzi)
356 {
357 DWORD cbData = sizeof(TZI);
358 LONG result;
359 HKEY hkey;
360
361 result = openTZRegKey(&hkey, winid);
362
363 if (result == ERROR_SUCCESS) {
364 result = RegQueryValueEx(hkey,
365 TZI_REGKEY,
366 NULL,
367 NULL,
368 (LPBYTE)tzi,
369 &cbData);
370
371 }
372
373 RegCloseKey(hkey);
374
375 return result;
376 }
377
378 U_CAPI UBool U_EXPORT2
379 uprv_getWindowsTimeZoneInfo(TIME_ZONE_INFORMATION *zoneInfo, const UChar *icuid, int32_t length)
380 {
381 const char *winid;
382 TZI tzi;
383 LONG result;
384
385 winid = findWindowsZoneID(icuid, length);
386
387 if (winid != NULL) {
388 result = getTZI(winid, &tzi);
389
390 if (result == ERROR_SUCCESS) {
391 zoneInfo->Bias = tzi.bias;
392 zoneInfo->DaylightBias = tzi.daylightBias;
393 zoneInfo->StandardBias = tzi.standardBias;
394 zoneInfo->DaylightDate = tzi.daylightDate;
395 zoneInfo->StandardDate = tzi.standardDate;
396
397 return TRUE;
398 }
399 }
400
401 return FALSE;
402 }
403
404 /*
405 This code attempts to detect the Windows time zone, as set in the
406 Windows Date and Time control panel. It attempts to work on
407 multiple flavors of Windows (9x, Me, NT, 2000, XP) and on localized
408 installs. It works by directly interrogating the registry and
409 comparing the data there with the data returned by the
410 GetTimeZoneInformation API, along with some other strategies. The
411 registry contains time zone data under one of two keys (depending on
412 the flavor of Windows):
413
414 HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones\
415 HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\
416
417 Under this key are several subkeys, one for each time zone. These
418 subkeys are named "Pacific" on Win9x/Me and "Pacific Standard Time"
419 on WinNT/2k/XP. There are some other wrinkles; see the code for
420 details. The subkey name is NOT LOCALIZED, allowing us to support
421 localized installs.
422
423 Under the subkey are data values. We care about:
424
425 Std Standard time display name, localized
426 TZI Binary block of data
427
428 The TZI data is of particular interest. It contains the offset, two
429 more offsets for standard and daylight time, and the start and end
430 rules. This is the same data returned by the GetTimeZoneInformation
431 API. The API may modify the data on the way out, so we have to be
432 careful, but essentially we do a binary comparison against the TZI
433 blocks of various registry keys. When we find a match, we know what
434 time zone Windows is set to. Since the registry key is not
435 localized, we can then translate the key through a simple table
436 lookup into the corresponding ICU time zone.
437
438 This strategy doesn't always work because there are zones which
439 share an offset and rules, so more than one TZI block will match.
440 For example, both Tokyo and Seoul are at GMT+9 with no DST rules;
441 their TZI blocks are identical. For these cases, we fall back to a
442 name lookup. We attempt to match the display name as stored in the
443 registry for the current zone to the display name stored in the
444 registry for various Windows zones. By comparing the registry data
445 directly we avoid conversion complications.
446
447 Author: Alan Liu
448 Since: ICU 2.6
449 Based on original code by Carl Brown <cbrown@xnetinc.com>
450 */
451
452 /**
453 * Main Windows time zone detection function. Returns the Windows
454 * time zone, translated to an ICU time zone, or NULL upon failure.
455 */
456 U_CAPI const char* U_EXPORT2
457 uprv_detectWindowsTimeZone() {
458 LONG result;
459 HKEY hkey;
460 TZI tziKey;
461 TZI tziReg;
462 TIME_ZONE_INFORMATION apiTZI;
463 int firstMatch, lastMatch;
464 int j;
465
466 /* Obtain TIME_ZONE_INFORMATION from the API, and then convert it
467 to TZI. We could also interrogate the registry directly; we do
468 this below if needed. */
469 uprv_memset(&apiTZI, 0, sizeof(apiTZI));
470 uprv_memset(&tziKey, 0, sizeof(tziKey));
471 uprv_memset(&tziReg, 0, sizeof(tziReg));
472 GetTimeZoneInformation(&apiTZI);
473 tziKey.bias = apiTZI.Bias;
474 uprv_memcpy((char *)&tziKey.standardDate, (char*)&apiTZI.StandardDate,
475 sizeof(apiTZI.StandardDate));
476 uprv_memcpy((char *)&tziKey.daylightDate, (char*)&apiTZI.DaylightDate,
477 sizeof(apiTZI.DaylightDate));
478
479 /* For each zone that can be identified by Offset+Rules, see if we
480 have a match. Continue scanning after finding a match,
481 recording the index of the first and the last match. We have
482 to do this because some zones are not unique under
483 Offset+Rules. */
484 firstMatch = -1;
485 lastMatch = -1;
486 for (j=0; ZONE_MAP[j].icuid; j++) {
487 result = getTZI(ZONE_MAP[j].winid, &tziReg);
488
489 if (result == ERROR_SUCCESS) {
490 /* Assume that offsets are grouped together, and bail out
491 when we've scanned everything with a matching
492 offset. */
493 if (firstMatch >= 0 && tziKey.bias != tziReg.bias) {
494 break;
495 }
496
497 /* Windows alters the DaylightBias in some situations.
498 Using the bias and the rules suffices, so overwrite
499 these unreliable fields. */
500 tziKey.standardBias = tziReg.standardBias;
501 tziKey.daylightBias = tziReg.daylightBias;
502
503 if (uprv_memcmp((char *)&tziKey, (char*)&tziReg, sizeof(tziKey)) == 0) {
504 if (firstMatch < 0) {
505 firstMatch = j;
506 }
507
508 lastMatch = j;
509 }
510 }
511 }
512
513 /* This should never happen; if it does it means our table doesn't
514 match Windows AT ALL, perhaps because this is post-XP? */
515 if (firstMatch < 0) {
516 return NULL;
517 }
518
519 if (firstMatch != lastMatch) {
520 char stdName[32];
521 DWORD stdNameSize;
522 char stdRegName[64];
523 DWORD stdRegNameSize;
524
525 /* Offset+Rules lookup yielded >= 2 matches. Try to match the
526 localized display name. Get the name from the registry
527 (not the API). This avoids conversion issues. Use the
528 standard name, since Windows modifies the daylight name to
529 match the standard name if there is no DST. */
530 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
531 CURRENT_ZONE_REGKEY,
532 0,
533 KEY_QUERY_VALUE,
534 &hkey) == ERROR_SUCCESS)
535 {
536 stdNameSize = sizeof(stdName);
537 result = RegQueryValueEx(hkey,
538 (LPTSTR)STANDARD_NAME_REGKEY,
539 NULL,
540 NULL,
541 (LPBYTE)stdName,
542 &stdNameSize);
543 RegCloseKey(hkey);
544
545 /*
546 * Scan through the Windows time zone data in the registry
547 * again (just the range of zones with matching TZIs) and
548 * look for a standard display name match.
549 */
550 for (j = firstMatch; j <= lastMatch; j += 1) {
551 stdRegNameSize = sizeof(stdRegName);
552 result = openTZRegKey(&hkey, ZONE_MAP[j].winid);
553
554 if (result == ERROR_SUCCESS) {
555 result = RegQueryValueEx(hkey,
556 (LPTSTR)STD_REGKEY,
557 NULL,
558 NULL,
559 (LPBYTE)stdRegName,
560 &stdRegNameSize);
561 }
562
563 RegCloseKey(hkey);
564
565 if (result == ERROR_SUCCESS &&
566 stdRegNameSize == stdNameSize &&
567 uprv_memcmp(stdName, stdRegName, stdNameSize) == 0)
568 {
569 firstMatch = j; /* record the match */
570 break;
571 }
572 }
573 } else {
574 RegCloseKey(hkey); /* should never get here */
575 }
576 }
577
578 return ZONE_MAP[firstMatch].icuid;
579 }
580
581 #endif /* #ifdef U_WINDOWS */