1 /* 2 * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Sun designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Sun in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 * CA 95054 USA or visit www.sun.com if you need additional information or 23 * have any questions. 24 */ 25 26 #include <windows.h> 27 #include <shlobj.h> 28 #include <objidl.h> 29 #include <locale.h> 30 #include <sys/types.h> 31 #include <sys/timeb.h> 32 #include <tchar.h> 33 34 #include "locale_str.h" 35 #include "java_props.h" 36 37 #ifndef VER_PLATFORM_WIN32_WINDOWS 38 #define VER_PLATFORM_WIN32_WINDOWS 1 39 #endif 40 41 #ifndef PROCESSOR_ARCHITECTURE_AMD64 42 #define PROCESSOR_ARCHITECTURE_AMD64 9 43 #endif 44 45 typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); 46 47 #define SHELL_KEY "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders" 48 49 /* Encodings for Windows language groups. According to 50 www.microsoft.com/globaldev/faqs/locales.asp, 51 some locales do not have codepages, and are 52 supported in Windows 2000/XP solely through Unicode. 53 In this case, we use utf-8 encoding */ 54 55 static char *encoding_names[] = { 56 "Cp1250", /* 0:Latin 2 */ 57 "Cp1251", /* 1:Cyrillic */ 58 "Cp1252", /* 2:Latin 1 */ 59 "Cp1253", /* 3:Greek */ 60 "Cp1254", /* 4:Latin 5 */ 61 "Cp1255", /* 5:Hebrew */ 62 "Cp1256", /* 6:Arabic */ 63 "Cp1257", /* 7:Baltic */ 64 "Cp1258", /* 8:Viet Nam */ 65 "MS874", /* 9:Thai */ 66 "MS932", /* 10:Japanese */ 67 "GBK", /* 11:PRC GBK */ 68 "MS949", /* 12:Korean Extended Wansung */ 69 "MS950", /* 13:Chinese (Taiwan, Hongkong, Macau) */ 70 "utf-8", /* 14:Unicode */ 71 "MS1361", /* 15:Korean Johab */ 72 }; 73 74 /* 75 * List mapping from LanguageID to Java locale IDs. 76 * The entries in this list should not be construed to suggest we actually have 77 * full locale-data and other support for all of these locales; these are 78 * merely all of the Windows locales for which we could construct an accurate 79 * locale ID. The data is based on the web page "Windows XP/Server 2003 - 80 * List of Locale IDs, Input Locale, and Language Collection" 81 * (http://www.microsoft.com/globaldev/reference/winxp/xp-lcid.mspx) 82 * 83 * Some of the language IDs below are not yet used by Windows, but were 84 * defined by Microsoft for other products, such as Office XP. They may 85 * become Windows language IDs in the future. 86 * 87 */ 88 typedef struct LANGIDtoLocale { 89 WORD langID; 90 WORD encoding; 91 char* javaID; 92 } LANGIDtoLocale; 93 94 static LANGIDtoLocale langIDMap[] = { 95 /* fallback locales to use when the country code doesn't match anything we have */ 96 0x01, 6, "ar", 97 0x02, 1, "bg", 98 0x03, 2, "ca", 99 0x04, 11, "zh", 100 0x05, 0, "cs", 101 0x06, 2, "da", 102 0x07, 2, "de", 103 0x08, 3, "el", 104 0x09, 2, "en", 105 0x0a, 2, "es", 106 0x0b, 2, "fi", 107 0x0c, 2, "fr", 108 0x0d, 5, "iw", 109 0x0e, 0, "hu", 110 0x0f, 2, "is", 111 0x10, 2, "it", 112 0x11, 10, "ja", 113 0x12, 12, "ko", 114 0x13, 2, "nl", 115 0x14, 2, "no", 116 0x15, 0, "pl", 117 0x16, 2, "pt", 118 0x17, 2, "rm", 119 0x18, 0, "ro", 120 0x19, 1, "ru", 121 0x1a, 0, "sr", 122 0x1b, 0, "sk", 123 0x1c, 0, "sq", 124 0x1d, 2, "sv", 125 0x1e, 9, "th", 126 0x1f, 4, "tr", 127 0x20, 2, "ur", 128 0x21, 2, "in", 129 0x22, 1, "uk", 130 0x23, 1, "be", 131 0x24, 0, "sl", 132 0x25, 7, "et", 133 0x26, 7, "lv", 134 0x27, 7, "lt", 135 0x28, 1, "tg", 136 0x29, 6, "fa", 137 0x2a, 8, "vi", 138 0x2b, 14, "hy", 139 0x2c, 4, "az", 140 0x2d, 2, "eu", 141 /* 0x2e, 2, "??", no ISO-639 abbreviation for Sorbian */ 142 0x2f, 1, "mk", 143 0x31, 2, "ts", 144 0x32, 2, "tn", 145 0x34, 2, "xh", 146 0x35, 2, "zu", 147 0x36, 2, "af", 148 0x37, 14, "ka", 149 0x38, 2, "fo", 150 0x39, 14, "hi", 151 0x3a, 14, "mt", 152 0x3b, 2, "se", 153 0x3c, 2, "gd", 154 0x3d, 2, "yi", 155 0x3e, 2, "ms", 156 0x3f, 1, "kk", 157 0x40, 1, "ky", 158 0x41, 2, "sw", 159 0x42, 0, "tk", 160 0x43, 1, "uz", 161 0x44, 1, "tt", 162 0x45, 14, "bn", 163 0x46, 14, "pa", 164 0x47, 14, "gu", 165 0x48, 14, "or", 166 0x49, 14, "ta", 167 0x4a, 14, "te", 168 0x4b, 14, "kn", 169 0x4c, 14, "ml", 170 0x4d, 14, "as", 171 0x4e, 14, "mr", 172 0x4f, 14, "sa", 173 0x50, 1, "mn", 174 0x51, 14, "bo", 175 0x52, 1, "cy", 176 0x53, 14, "km", 177 0x54, 14, "lo", 178 0x56, 2, "gl", 179 0x5b, 14, "si", 180 0x5d, 14, "iu", 181 0x5e, 14, "am", 182 /* 0x5f, 2, "??", no ISO-639 abbreviation for Tamazight */ 183 0x68, 2, "ha", 184 0x6a, 2, "yo", 185 0x6b, 2, "qu", 186 0x6d, 1, "ba", 187 0x6f, 2, "kl", 188 0x70, 2, "ig", 189 /* 0x78, 14, "??", no ISO-639 abbreviation for Yi */ 190 0x7e, 2, "br", 191 0x80, 6, "ug", 192 0x81, 14, "mi", 193 0x82, 2, "oc", 194 0x83, 2, "co", 195 /* 0x84, 2, "??", no ISO-639 abbreviation for Alsatian */ 196 /* 0x85, 1, "??", no ISO-639 abbreviation for Yakut */ 197 /* 0x86, 2, "??", no ISO-639 abbreviation for K'iche */ 198 0x87, 2, "rw", 199 0x88, 2, "wo", 200 /* 0x8c, 6, "??", no ISO-639 abbreviation for Dari */ 201 /* mappings for real Windows LCID values */ 202 0x0401, 6, "ar_SA", 203 0x0402, 1, "bg_BG", 204 0x0403, 2, "ca_ES", 205 0x0404, 13, "zh_TW", 206 0x0405, 0, "cs_CZ", 207 0x0406, 2, "da_DK", 208 0x0407, 2, "de_DE", 209 0x0408, 3, "el_GR", 210 0x0409, 2, "en_US", 211 0x040a, 2, "es_ES", /* (traditional sort) */ 212 0x040b, 2, "fi_FI", 213 0x040c, 2, "fr_FR", 214 0x040d, 5, "iw_IL", 215 0x040e, 0, "hu_HU", 216 0x040f, 2, "is_IS", 217 0x0410, 2, "it_IT", 218 0x0411, 10, "ja_JP", 219 0x0412, 12, "ko_KR", 220 0x0413, 2, "nl_NL", 221 0x0414, 2, "no_NO", 222 0x0415, 0, "pl_PL", 223 0x0416, 2, "pt_BR", 224 0x0417, 2, "rm_CH", 225 0x0418, 0, "ro_RO", 226 0x0419, 1, "ru_RU", 227 0x041a, 0, "hr_HR", 228 0x041b, 0, "sk_SK", 229 0x041c, 0, "sq_AL", 230 0x041d, 2, "sv_SE", 231 0x041e, 9, "th_TH", 232 0x041f, 4, "tr_TR", 233 0x0420, 6, "ur_PK", 234 0x0421, 2, "in_ID", 235 0x0422, 1, "uk_UA", 236 0x0423, 1, "be_BY", 237 0x0424, 0, "sl_SI", 238 0x0425, 7, "et_EE", 239 0x0426, 7, "lv_LV", 240 0x0427, 7, "lt_LT", 241 0x0428, 1, "tg_TJ", 242 0x0429, 6, "fa_IR", 243 0x042a, 8, "vi_VN", 244 0x042b, 14, "hy_AM", /* Armenian */ 245 0x042c, 4, "az_AZ", /* Azeri_Latin */ 246 0x042d, 2, "eu_ES", 247 /* 0x042e, 2, "??", no ISO-639 abbreviation for Upper Sorbian */ 248 0x042f, 1, "mk_MK", 249 /* 0x0430, 2, "??", no ISO-639 abbreviation for Sutu */ 250 0x0431, 2, "ts", /* (country?) */ 251 0x0432, 2, "tn_ZA", 252 /* 0x0433, 2, "??", no ISO-639 abbreviation for Venda */ 253 0x0434, 2, "xh_ZA", 254 0x0435, 2, "zu_ZA", 255 0x0436, 2, "af_ZA", 256 0x0437, 14, "ka_GE", /* Georgian */ 257 0x0438, 2, "fo_FO", 258 0x0439, 14, "hi_IN", 259 0x043a, 14, "mt_MT", 260 0x043b, 2, "se_NO", /* Sami, Northern - Norway */ 261 0x043c, 2, "gd_GB", 262 0x043d, 2, "yi", /* (country?) */ 263 0x043e, 2, "ms_MY", 264 0x043f, 1, "kk_KZ", /* Kazakh */ 265 0x0440, 1, "ky_KG", /* Kyrgyz */ 266 0x0441, 2, "sw_KE", 267 0x0442, 0, "tk_TM", 268 0x0443, 4, "uz_UZ", /* Uzbek_Latin */ 269 0x0444, 1, "tt_RU", /* Tatar */ 270 0x0445, 14, "bn_IN", /* Bengali */ 271 0x0446, 14, "pa_IN", /* Punjabi */ 272 0x0447, 14, "gu_IN", /* Gujarati */ 273 0x0448, 14, "or_IN", /* Oriya */ 274 0x0449, 14, "ta_IN", /* Tamil */ 275 0x044a, 14, "te_IN", /* Telugu */ 276 0x044b, 14, "kn_IN", /* Kannada */ 277 0x044c, 14, "ml_IN", /* Malayalam */ 278 0x044d, 14, "as_IN", /* Assamese */ 279 0x044e, 14, "mr_IN", /* Marathi */ 280 0x044f, 14, "sa_IN", /* Sanskrit */ 281 0x0450, 1, "mn_MN", /* Mongolian */ 282 0x0451, 14, "bo_CN", /* Tibetan */ 283 0x0452, 2, "cy_GB", /* Welsh */ 284 0x0453, 14, "km_KH", /* Khmer */ 285 0x0454, 14, "lo_LA", /* Lao */ 286 0x0456, 2, "gl_ES", /* Galician */ 287 /* 0x0457, 14, "??_IN", /* Konkani, no ISO-639 abbreviation*/ 288 /* 0x045a, 14, "??_SY", /* Syriac, no ISO-639 abbreviation*/ 289 0x045b, 14, "si_LK", /* Sinhala */ 290 0x045d, 14, "iu_CA", /* Inuktitut */ 291 0x045e, 14, "am_ET", /* Amharic */ 292 0x0461, 14, "ne_NP", /* Nepali */ 293 0x0462, 2, "fy_NL", /* Frisian */ 294 0x0463, 6, "ps_AF", /* Pushto */ 295 /* 0x0464, 2, "??_PH", /* Filipino, no ISO-639 abbreviation*/ 296 0x0465, 14, "dv_MV", /* Divehi */ 297 0x0468, 2, "ha_NG", /* Hausa */ 298 0x046a, 2, "yo_NG", /* Yoruba */ 299 0x046b, 2, "qu_BO", /* Quechua - Bolivia */ 300 /* 0x046c, 2, "??_ZA", /* Northern Sotho, no ISO-639 abbreviation */ 301 0x046d, 1, "ba_RU", /* Bashkir */ 302 0x046e, 2, "lb_LU", /* Luxembourgish */ 303 0x046f, 2, "kl_GL", /* Greenlandic */ 304 0x0470, 2, "ig_NG", /* Igbo */ 305 /* 0x0478, 14, "??_CN", /* Yi (PRC), no ISO-639 abbreviation */ 306 /* 0x047a, 2, "??_CL", /* Mapudungun (Araucanian), no ISO-639 abbreviation */ 307 /* 0x047c, 2, "??_CA", /* Mohawk, no ISO-639 abbreviation */ 308 0x047e, 2, "br_FR", /* Breton */ 309 0x0480, 6, "ug_CN", /* Uighur */ 310 0x0481, 14, "mi_NZ", /* Maori - New Zealand */ 311 0x0482, 2, "oc_FR", /* Occitan */ 312 0x0483, 2, "co_FR", /* Corsican */ 313 /* 0x0484, 2, "??_FR", /* Alsatian, no ISO-639 abbreviation */ 314 /* 0x0485, 1, "??_RU", /* Yakut, no ISO-639 abbreviation */ 315 /* 0x0486, 2, "??_GT", /* K'iche, no ISO-639 abbreviation */ 316 0x0487, 2, "rw_RW", /* Kinyarwanda */ 317 0x0488, 2, "wo_SN", /* Wolof */ 318 /* 0x048c, 6, "??_AF", /* Dari, no ISO-639 abbreviation */ 319 0x0801, 6, "ar_IQ", 320 0x0804, 11, "zh_CN", 321 0x0807, 2, "de_CH", 322 0x0809, 2, "en_GB", 323 0x080a, 2, "es_MX", 324 0x080c, 2, "fr_BE", 325 0x0810, 2, "it_CH", 326 0x0812, 15, "ko_KR", /* Korean(Johab)*/ 327 0x0813, 2, "nl_BE", 328 0x0814, 2, "no_NO_NY", 329 0x0816, 2, "pt_PT", 330 0x0818, 0, "ro_MD", 331 0x0819, 1, "ru_MD", 332 0x081a, 0, "sr_CS", 333 0x081d, 2, "sv_FI", 334 0x082c, 1, "az_AZ", /* Azeri_Cyrillic */ 335 /* 0x082e, 2, "??", no ISO-639 abbreviation for Lower Sorbian */ 336 0x083b, 2, "se_SE", /* Sami, Northern - Sweden */ 337 0x083c, 2, "ga_IE", 338 0x083e, 2, "ms_BN", 339 0x0843, 1, "uz_UZ", /* Uzbek_Cyrillic */ 340 0x0845, 14, "bn_BD", /* Bengali */ 341 0x0850, 14, "mn_CN", /* Traditional Mongolian */ 342 0x085d, 2, "iu_CA", /* Inuktitut */ 343 /* 0x085f, 2, "??_DZ", no ISO-639 abbreviation for Tamazight */ 344 0x086b, 2, "qu_EC", /* Quechua - Ecuador */ 345 0x0c01, 6, "ar_EG", 346 0x0c04, 13, "zh_HK", 347 0x0c07, 2, "de_AT", 348 0x0c09, 2, "en_AU", 349 0x0c0a, 2, "es_ES", /* (modern sort) */ 350 0x0c0c, 2, "fr_CA", 351 0x0c1a, 1, "sr_CS", 352 0x0c3b, 2, "se_FI", /* Sami, Northern - Finland */ 353 0x0c6b, 2, "qu_PE", /* Quechua - Peru */ 354 0x1001, 6, "ar_LY", 355 0x1004, 11, "zh_SG", 356 0x1007, 2, "de_LU", 357 0x1009, 2, "en_CA", 358 0x100a, 2, "es_GT", 359 0x100c, 2, "fr_CH", 360 0x101a, 0, "hr_BA", 361 /* 0x103b, 2, "??_NO", /* Sami, Lule - Norway */ 362 0x1401, 6, "ar_DZ", 363 0x1404, 13, "zh_MO", 364 0x1407, 2, "de_LI", 365 0x1409, 2, "en_NZ", 366 0x140a, 2, "es_CR", 367 0x140c, 2, "fr_LU", 368 0x141a, 0, "bs_BA", 369 /* 0x143b, 2, "??_SE", /* Sami, Lule - Sweden */ 370 0x1801, 6, "ar_MA", 371 0x1809, 2, "en_IE", 372 0x180a, 2, "es_PA", 373 0x180c, 2, "fr_MC", 374 0x181a, 0, "sr_BA", 375 /* 0x183b, 2, "??_NO", /* Sami, Southern - Norway */ 376 0x1c01, 6, "ar_TN", 377 0x1c09, 2, "en_ZA", 378 0x1c0a, 2, "es_DO", 379 0x1c1a, 1, "sr_BA", 380 /* 0x1c3b, 2, "??_SE", /* Sami, Southern - Sweden */ 381 0x2001, 6, "ar_OM", 382 0x2009, 2, "en_JM", 383 0x200a, 2, "es_VE", 384 0x201a, 0, "bs_BA", /* Bosnian (Cyrillic) */ 385 /* 0x203b, 2, "??_FI", /* Sami, Skolt - Finland */ 386 0x2401, 6, "ar_YE", 387 0x2409, 2, "en", /* ("Caribbean", which could be any of many countries) */ 388 0x240a, 2, "es_CO", 389 /* 0x243b, 2, "??_FI", /* Sami, Inari - Finland */ 390 0x2801, 6, "ar_SY", 391 0x2809, 2, "en_BZ", 392 0x280a, 2, "es_PE", 393 0x2c01, 6, "ar_JO", 394 0x2c09, 2, "en_TT", 395 0x2c0a, 2, "es_AR", 396 0x3001, 6, "ar_LB", 397 0x3009, 2, "en_ZW", 398 0x300a, 2, "es_EC", 399 0x3401, 6, "ar_KW", 400 0x3409, 2, "en_PH", 401 0x340a, 2, "es_CL", 402 0x3801, 6, "ar_AE", 403 0x380a, 2, "es_UY", 404 0x3c01, 6, "ar_BH", 405 0x3c0a, 2, "es_PY", 406 0x4001, 6, "ar_QA", 407 0x4009, 2, "en_IN", 408 0x400a, 2, "es_BO", 409 0x4409, 2, "en_MY", 410 0x440a, 2, "es_SV", 411 0x4809, 2, "en_SG", 412 0x480a, 2, "es_HN", 413 0x4c0a, 2, "es_NI", 414 0x500a, 2, "es_PR", 415 0x540a, 2, "es_US" 416 }; 417 418 /* 419 * binary-search our list of LANGID values. If we don't find the 420 * one we're looking for, mask out the country code and try again 421 * with just the primary language ID 422 */ 423 static int 424 getLocaleEntryIndex(LANGID langID) 425 { 426 int index = -1; 427 int tries = 0; 428 do { 429 int lo, hi, mid; 430 lo = 0; 431 hi = sizeof(langIDMap) / sizeof(LANGIDtoLocale); 432 while (index == -1 && lo < hi) { 433 mid = (lo + hi) / 2; 434 if (langIDMap[mid].langID == langID) { 435 index = mid; 436 } else if (langIDMap[mid].langID > langID) { 437 hi = mid; 438 } else { 439 lo = mid + 1; 440 } 441 } 442 langID = PRIMARYLANGID(langID); 443 ++tries; 444 } while (index == -1 && tries < 2); 445 446 return index; 447 } 448 449 static char * 450 getEncodingInternal(int index) 451 { 452 char * ret = encoding_names[langIDMap[index].encoding]; 453 454 //Traditional Chinese Windows should use MS950_HKSCS as the 455 //default encoding, if HKSCS patch has been installed. 456 // "old" MS950 0xfa41 -> u+e001 457 // "new" MS950 0xfa41 -> u+92db 458 if (strcmp(ret, "MS950") == 0) { 459 TCHAR mbChar[2] = {(char)0xfa, (char)0x41}; 460 WCHAR unicodeChar; 461 MultiByteToWideChar(CP_ACP, 0, mbChar, 2, &unicodeChar, 1); 462 if (unicodeChar == 0x92db) { 463 ret = "MS950_HKSCS"; 464 } 465 } else { 466 //SimpChinese Windows should use GB18030 as the default 467 //encoding, if gb18030 patch has been installed (on windows 468 //2000/XP, (1)Codepage 54936 will be available 469 //(2)simsun18030.ttc will exist under system fonts dir ) 470 if (strcmp(ret, "GBK") == 0 && IsValidCodePage(54936)) { 471 char systemPath[MAX_PATH + 1]; 472 char* gb18030Font = "\\FONTS\\SimSun18030.ttc"; 473 FILE *f = NULL; 474 if (GetWindowsDirectory(systemPath, MAX_PATH + 1) != 0 && 475 strlen(systemPath) + strlen(gb18030Font) < MAX_PATH + 1) { 476 strcat(systemPath, "\\FONTS\\SimSun18030.ttc"); 477 if ((f = fopen(systemPath, "r")) != NULL) { 478 fclose(f); 479 ret = "GB18030"; 480 } 481 } 482 } 483 } 484 485 return ret; 486 } 487 488 // Exported entries for AWT 489 DllExport const char * 490 getEncodingFromLangID(LANGID langID) 491 { 492 int index = getLocaleEntryIndex(langID); 493 494 if (index != (-1)) { 495 return getEncodingInternal(index); 496 } else { 497 return "Cp1252"; 498 } 499 } 500 501 DllExport const char * 502 getJavaIDFromLangID(LANGID langID) 503 { 504 int index = getLocaleEntryIndex(langID); 505 506 if (index != (-1)) { 507 return langIDMap[index].javaID; 508 } else { 509 return NULL; 510 } 511 } 512 513 /* 514 * Code to figure out the user's home directory using the registry 515 */ 516 static char * 517 getHomeFromRegistry() 518 { 519 HKEY key; 520 int rc; 521 DWORD type; 522 char *p; 523 char path[MAX_PATH+1]; 524 int size = MAX_PATH+1; 525 526 rc = RegOpenKeyEx(HKEY_CURRENT_USER, SHELL_KEY, 0, KEY_READ, &key); 527 if (rc != ERROR_SUCCESS) { 528 // Shell folder doesn't exist??!! 529 return NULL; 530 } 531 532 path[0] = 0; 533 rc = RegQueryValueEx(key, "Desktop", 0, &type, path, &size); 534 if (rc != ERROR_SUCCESS || type != REG_SZ) { 535 return NULL; 536 } 537 RegCloseKey(key); 538 /* Get the parent of Desktop directory */ 539 p = strrchr(path, '\\'); 540 if (p == NULL) { 541 return NULL; 542 } 543 *p = '\0'; 544 return strdup(path); 545 } 546 547 /* 548 * Code to figure out the user's home directory using shell32.dll 549 */ 550 typedef HRESULT (WINAPI *GetSpecialFolderType)(HWND, int, LPITEMIDLIST *); 551 typedef BOOL (WINAPI *GetPathFromIDListType)(LPCITEMIDLIST, LPSTR); 552 553 char * 554 getHomeFromShell32() 555 { 556 HMODULE lib = LoadLibrary("SHELL32.DLL"); 557 GetSpecialFolderType do_get_folder; 558 GetPathFromIDListType do_get_path; 559 HRESULT rc; 560 LPITEMIDLIST item_list = 0; 561 char *p; 562 char path[MAX_PATH+1]; 563 int size = MAX_PATH+1; 564 565 if (lib == 0) { 566 // We can't load the library !!?? 567 return NULL; 568 } 569 570 do_get_folder = (GetSpecialFolderType)GetProcAddress(lib, "SHGetSpecialFolderLocation"); 571 do_get_path = (GetPathFromIDListType)GetProcAddress(lib, "SHGetPathFromIDListA"); 572 573 if (do_get_folder == 0 || do_get_path == 0) { 574 // the library doesn't hold the right functions !!?? 575 return NULL; 576 } 577 578 rc = (*do_get_folder)(NULL, CSIDL_DESKTOPDIRECTORY, &item_list); 579 if (!SUCCEEDED(rc)) { 580 // we can't find the shell folder. 581 return NULL; 582 } 583 584 path[0] = 0; 585 (*do_get_path)(item_list, path); 586 587 /* Get the parent of Desktop directory */ 588 p = strrchr(path, '\\'); 589 if (p) { 590 *p = 0; 591 } 592 593 /* 594 * We've been successful. Note that we don't free the memory allocated 595 * by ShGetSpecialFolderLocation. We only ever come through here once, 596 * and only if the registry lookup failed, so it's just not worth it. 597 * 598 * We also don't unload the SHELL32 DLL. We've paid the hit for loading 599 * it and we may need it again later. 600 */ 601 602 return strdup(path); 603 } 604 605 static boolean 606 haveMMX(void) 607 { 608 boolean mmx = 0; 609 HMODULE lib = LoadLibrary("KERNEL32"); 610 if (lib != NULL) { 611 BOOL (WINAPI *isProcessorFeaturePresent)(DWORD) = 612 (BOOL (WINAPI *)(DWORD)) 613 GetProcAddress(lib, "IsProcessorFeaturePresent"); 614 if (isProcessorFeaturePresent != NULL) 615 mmx = isProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE); 616 FreeLibrary(lib); 617 } 618 return mmx; 619 } 620 621 static const char * 622 cpu_isalist(void) 623 { 624 SYSTEM_INFO info; 625 GetSystemInfo(&info); 626 switch (info.wProcessorArchitecture) { 627 #ifdef PROCESSOR_ARCHITECTURE_IA64 628 case PROCESSOR_ARCHITECTURE_IA64: return "ia64"; 629 #endif 630 #ifdef PROCESSOR_ARCHITECTURE_AMD64 631 case PROCESSOR_ARCHITECTURE_AMD64: return "amd64"; 632 #endif 633 case PROCESSOR_ARCHITECTURE_INTEL: 634 switch (info.wProcessorLevel) { 635 case 6: return haveMMX() 636 ? "pentium_pro+mmx pentium_pro pentium+mmx pentium i486 i386 i86" 637 : "pentium_pro pentium i486 i386 i86"; 638 case 5: return haveMMX() 639 ? "pentium+mmx pentium i486 i386 i86" 640 : "pentium i486 i386 i86"; 641 case 4: return "i486 i386 i86"; 642 case 3: return "i386 i86"; 643 } 644 } 645 return NULL; 646 } 647 648 java_props_t * 649 GetJavaProperties(JNIEnv* env) 650 { 651 static java_props_t sprops = {0}; 652 653 if (sprops.user_dir) { 654 return &sprops; 655 } 656 657 /* AWT properties */ 658 sprops.awt_toolkit = "sun.awt.windows.WToolkit"; 659 660 /* tmp dir */ 661 { 662 char tmpdir[MAX_PATH + 1]; 663 /* we might want to check that this succeed */ 664 GetTempPath(MAX_PATH + 1, tmpdir); 665 sprops.tmp_dir = strdup(tmpdir); 666 } 667 668 /* Printing properties */ 669 sprops.printerJob = "sun.awt.windows.WPrinterJob"; 670 671 /* Java2D properties */ 672 sprops.graphics_env = "sun.awt.Win32GraphicsEnvironment"; 673 674 { /* This is used only for debugging of font problems. */ 675 char *path = getenv("JAVA2D_FONTPATH"); 676 sprops.font_dir = (path != 0) ? strdup(path) : NULL; 677 } 678 679 /* OS properties */ 680 { 681 char buf[100]; 682 OSVERSIONINFOEX ver; 683 SYSTEM_INFO si; 684 PGNSI pGNSI; 685 686 ver.dwOSVersionInfoSize = sizeof(ver); 687 GetVersionEx((OSVERSIONINFO *) &ver); 688 689 ZeroMemory(&si, sizeof(SYSTEM_INFO)); 690 // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise. 691 pGNSI = (PGNSI) GetProcAddress( 692 GetModuleHandle(TEXT("kernel32.dll")), 693 "GetNativeSystemInfo"); 694 if(NULL != pGNSI) 695 pGNSI(&si); 696 else 697 GetSystemInfo(&si); 698 699 /* 700 * From msdn page on OSVERSIONINFOEX, current as of this 701 * writing, decoding of dwMajorVersion and dwMinorVersion. 702 * 703 * Operating system dwMajorVersion dwMinorVersion 704 * ================== ============== ============== 705 * 706 * Windows 95 4 0 707 * Windows 98 4 10 708 * Windows ME 4 90 709 * Windows 3.51 3 51 710 * Windows NT 4.0 4 0 711 * Windows 2000 5 0 712 * Windows XP 32 bit 5 1 713 * Windows Server 2003 family 5 2 714 * Windows XP 64 bit 5 2 715 * where ((&ver.wServicePackMinor) + 2) = 1 716 * and si.wProcessorArchitecture = 9 717 * Windows Vista family 6 0 718 * Windows 2008 6 0 719 * where ((&ver.wServicePackMinor) + 2) = 1 720 * Windows 7 6 1 721 * 722 * This mapping will presumably be augmented as new Windows 723 * versions are released. 724 */ 725 switch (ver.dwPlatformId) { 726 case VER_PLATFORM_WIN32s: 727 sprops.os_name = "Windows 3.1"; 728 break; 729 case VER_PLATFORM_WIN32_WINDOWS: 730 if (ver.dwMajorVersion == 4) { 731 switch (ver.dwMinorVersion) { 732 case 0: sprops.os_name = "Windows 95"; break; 733 case 10: sprops.os_name = "Windows 98"; break; 734 case 90: sprops.os_name = "Windows Me"; break; 735 default: sprops.os_name = "Windows 9X (unknown)"; break; 736 } 737 } else { 738 sprops.os_name = "Windows 9X (unknown)"; 739 } 740 break; 741 case VER_PLATFORM_WIN32_NT: 742 if (ver.dwMajorVersion <= 4) { 743 sprops.os_name = "Windows NT"; 744 } else if (ver.dwMajorVersion == 5) { 745 switch (ver.dwMinorVersion) { 746 case 0: sprops.os_name = "Windows 2000"; break; 747 case 1: sprops.os_name = "Windows XP"; break; 748 case 2: 749 /* 750 * From MSDN OSVERSIONINFOEX and SYSTEM_INFO documentation: 751 * 752 * "Because the version numbers for Windows Server 2003 753 * and Windows XP 6u4 bit are identical, you must also test 754 * whether the wProductType member is VER_NT_WORKSTATION. 755 * and si.wProcessorArchitecture is 756 * PROCESSOR_ARCHITECTURE_AMD64 (which is 9) 757 * If it is, the operating system is Windows XP 64 bit; 758 * otherwise, it is Windows Server 2003." 759 */ 760 if(ver.wProductType == VER_NT_WORKSTATION && 761 si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { 762 sprops.os_name = "Windows XP"; /* 64 bit */ 763 } else { 764 sprops.os_name = "Windows 2003"; 765 } 766 break; 767 default: sprops.os_name = "Windows NT (unknown)"; break; 768 } 769 } else if (ver.dwMajorVersion == 6) { 770 /* 771 * From MSDN OSVERSIONINFOEX documentation: 772 * 773 * "Because the version numbers for Windows Server 2008 774 * and Windows Vista are identical, you must also test 775 * whether the wProductType member is VER_NT_WORKSTATION. 776 * If wProductType is VER_NT_WORKSTATION, the operating 777 * system is Windows Vista or 7; otherwise, it is Windows 778 * Server 2008." 779 */ 780 if (ver.wProductType == VER_NT_WORKSTATION) { 781 switch (ver.dwMinorVersion) { 782 case 0: sprops.os_name = "Windows Vista"; break; 783 case 1: sprops.os_name = "Windows 7"; break; 784 default: sprops.os_name = "Windows NT (unknown)"; 785 } 786 } else { 787 sprops.os_name = "Windows Server 2008"; 788 } 789 } else { 790 sprops.os_name = "Windows NT (unknown)"; 791 } 792 break; 793 default: 794 sprops.os_name = "Windows (unknown)"; 795 break; 796 } 797 sprintf(buf, "%d.%d", ver.dwMajorVersion, ver.dwMinorVersion); 798 sprops.os_version = strdup(buf); 799 #if _M_IA64 800 sprops.os_arch = "ia64"; 801 #elif _M_AMD64 802 sprops.os_arch = "amd64"; 803 #elif _X86_ 804 sprops.os_arch = "x86"; 805 #else 806 sprops.os_arch = "unknown"; 807 #endif 808 809 sprops.patch_level = strdup(ver.szCSDVersion); 810 811 sprops.desktop = "windows"; 812 } 813 814 /* Endianness of platform */ 815 { 816 unsigned int endianTest = 0xff000000; 817 if (((char*)(&endianTest))[0] != 0) { 818 sprops.cpu_endian = "big"; 819 } else { 820 sprops.cpu_endian = "little"; 821 } 822 } 823 824 /* CPU ISA list */ 825 sprops.cpu_isalist = cpu_isalist(); 826 827 /* 828 * User name 829 * We try to avoid calling GetUserName as it turns out to 830 * be surprisingly expensive on NT. It pulls in an extra 831 * 100 K of footprint. 832 */ 833 { 834 char *uname = getenv("USERNAME"); 835 if (uname != NULL && strlen(uname) > 0) { 836 sprops.user_name = strdup(uname); 837 } else { 838 char buf[100]; 839 int buflen = sizeof(buf); 840 sprops.user_name = 841 GetUserName(buf, &buflen) ? strdup(buf) : "unknown"; 842 } 843 } 844 845 /* 846 * Home directory/ 847 * 848 * We first look under a standard registry key. If that fails we 849 * fall back on using a SHELL32.DLL API. If that fails we use a 850 * default value. 851 * 852 * Note: To save space we want to avoid loading SHELL32.DLL 853 * unless really necessary. However if we do load it, we leave it 854 * in memory, as it may be needed again later. 855 * 856 * The normal result is that for a given user name XXX: 857 * On multi-user NT, user.home gets set to c:\winnt\profiles\XXX. 858 * On multi-user Win95, user.home gets set to c:\windows\profiles\XXX. 859 * On single-user Win95, user.home gets set to c:\windows. 860 */ 861 { 862 char *homep = getHomeFromRegistry(); 863 if (homep == NULL) { 864 homep = getHomeFromShell32(); 865 if (homep == NULL) { 866 homep = "C:\\"; 867 } 868 } 869 sprops.user_home = homep; 870 } 871 872 /* 873 * user.language 874 * user.country, user.variant (if user's environment specifies them) 875 * file.encoding 876 * file.encoding.pkg 877 */ 878 { 879 /* 880 * query the system for the current system default locale 881 * (which is a Windows LCID value), 882 */ 883 LANGID langID = LANGIDFROMLCID(GetUserDefaultLCID()); 884 LANGID sysLangID = LANGIDFROMLCID(GetSystemDefaultLCID()); 885 886 { 887 int index = getLocaleEntryIndex(langID); 888 889 /* 890 * if we didn't find the LCID that the system returned to us, 891 * we don't have a Java locale ID that corresponds to it. 892 * Fall back on en_US. 893 */ 894 if (index == -1) { 895 sprops.language = "en"; 896 sprops.country = "US"; 897 sprops.encoding = "Cp1252"; 898 } else { 899 900 /* otherwise, look up the corresponding Java locale ID from 901 * the list of Java locale IDs and set up the system properties 902 * accordingly. 903 */ 904 905 char* lang; 906 char* ctry; 907 char* variant; 908 909 lang = strdup(langIDMap[index].javaID); 910 ctry = lang; 911 912 while (*ctry != '_' && *ctry != 0) 913 ++ctry; 914 915 if (*ctry == '_') { 916 *ctry++ = 0; 917 } 918 919 variant = ctry; 920 while (*variant != '_' && *variant != 0) 921 ++variant; 922 923 if (*variant == '_') { 924 *variant++ = 0; 925 } 926 927 sprops.language = lang; 928 sprops.country = ctry; 929 sprops.variant = variant; 930 sprops.encoding = getEncodingInternal(index); 931 } 932 index = getLocaleEntryIndex(sysLangID); 933 if (index == -1) { 934 sprops.sun_jnu_encoding = "Cp1252"; 935 } else { 936 sprops.sun_jnu_encoding = getEncodingInternal(index); 937 } 938 } 939 } 940 941 sprops.unicode_encoding = "UnicodeLittle"; 942 /* User TIMEZONE */ 943 { 944 /* 945 * We defer setting up timezone until it's actually necessary. 946 * Refer to TimeZone.getDefault(). However, the system 947 * property is necessary to be able to be set by the command 948 * line interface -D. Here temporarily set a null string to 949 * timezone. 950 */ 951 sprops.timezone = ""; 952 } 953 954 /* Current directory */ 955 { 956 char buf[MAX_PATH]; 957 GetCurrentDirectory(sizeof(buf), buf); 958 sprops.user_dir = strdup(buf); 959 } 960 961 sprops.file_separator = "\\"; 962 sprops.path_separator = ";"; 963 sprops.line_separator = "\r\n"; 964 965 return &sprops; 966 }