1/* 2 * Copyright (c) 1998, 2016, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26#include <windows.h> 27#include <stdio.h> 28 29#include <jni.h> 30#include <jni_util.h> 31#include <sun_awt_Win32FontManager.h> 32 33#define BSIZE (max(512, MAX_PATH+1)) 34 35/* Typically all local references held by a JNI function are automatically 36 * released by JVM when the function returns. However, there is a limit to the 37 * number of local references that can remain active. If the local references 38 * continue to grow, it could result in out of memory error. Henceforth, we 39 * invoke DeleteLocalRef on objects that are no longer needed for execution in 40 * the JNI function. 41 */ 42#define DeleteLocalReference(env, jniRef) \ 43 do { \ 44 if (jniRef != NULL) { \ 45 (*env)->DeleteLocalRef(env, jniRef); \ 46 jniRef = NULL; \ 47 } \ 48 } while (0) 49 50JNIEXPORT jstring JNICALL Java_sun_awt_Win32FontManager_getFontPath(JNIEnv *env, jobject thiz, jboolean noType1) 51{ 52 char windir[BSIZE]; 53 char sysdir[BSIZE]; 54 char fontpath[BSIZE*2]; 55 char *end; 56 57 /* Locate fonts directories relative to the Windows System directory. 58 * If Windows System location is different than the user's window 59 * directory location, as in a shared Windows installation, 60 * return both locations as potential font directories 61 */ 62 GetSystemDirectory(sysdir, BSIZE); 63 end = strrchr(sysdir,'\\'); 64 if (end && (stricmp(end,"\\System") || stricmp(end,"\\System32"))) { 65 *end = 0; 66 strcat(sysdir, "\\Fonts"); 67 } 68 69 GetWindowsDirectory(windir, BSIZE); 70 if (strlen(windir) > BSIZE-7) { 71 *windir = 0; 72 } else { 73 strcat(windir, "\\Fonts"); 74 } 75 76 strcpy(fontpath,sysdir); 77 if (stricmp(sysdir,windir)) { 78 strcat(fontpath,";"); 79 strcat(fontpath,windir); 80 } 81 82 return JNU_NewStringPlatform(env, fontpath); 83} 84 85/* The code below is used to obtain information from the windows font APIS 86 * and registry on which fonts are available and what font files hold those 87 * fonts. The results are used to speed font lookup. 88 */ 89 90typedef struct GdiFontMapInfo { 91 JNIEnv *env; 92 jstring family; 93 jobject fontToFamilyMap; 94 jobject familyToFontListMap; 95 jobject list; 96 jmethodID putMID; 97 jmethodID containsKeyMID; 98 jclass arrayListClass; 99 jmethodID arrayListCtr; 100 jmethodID addMID; 101 jmethodID toLowerCaseMID; 102 jobject locale; 103} GdiFontMapInfo; 104 105/* Registry entry for fonts */ 106static const char FONTKEY_NT[] = 107 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"; 108 109typedef struct CheckFamilyInfo { 110 wchar_t *family; 111 wchar_t* fullName; 112 int isDifferent; 113} CheckFamilyInfo; 114 115static int CALLBACK CheckFontFamilyProcW( 116 ENUMLOGFONTEXW *lpelfe, 117 NEWTEXTMETRICEX *lpntme, 118 int FontType, 119 LPARAM lParam) 120{ 121 CheckFamilyInfo *info = (CheckFamilyInfo*)lParam; 122 info->isDifferent = wcscmp(lpelfe->elfLogFont.lfFaceName, info->family); 123 124/* if (!info->isDifferent) { */ 125/* wprintf(LFor font %s expected family=%s instead got %s\n", */ 126/* lpelfe->elfFullName, */ 127/* info->family, */ 128/* lpelfe->elfLogFont.lfFaceName); */ 129/* fflush(stdout); */ 130/* } */ 131 return 0; 132} 133 134/* This HDC is initialised and released in the populate family map 135 * JNI entry point, and used within the call which would otherwise 136 * create many DCs. 137 */ 138static HDC screenDC = NULL; 139 140static int DifferentFamily(wchar_t *family, wchar_t* fullName) { 141 LOGFONTW lfw; 142 CheckFamilyInfo info; 143 144 /* If fullName can't be stored in the struct, assume correct family */ 145 if (wcslen((LPWSTR)fullName) >= LF_FACESIZE) { 146 return 0; 147 } 148 149 memset(&info, 0, sizeof(CheckFamilyInfo)); 150 info.family = family; 151 info.fullName = fullName; 152 info.isDifferent = 0; 153 154 memset(&lfw, 0, sizeof(lfw)); 155 wcscpy(lfw.lfFaceName, fullName); 156 lfw.lfCharSet = DEFAULT_CHARSET; 157 EnumFontFamiliesExW(screenDC, &lfw, 158 (FONTENUMPROCW)CheckFontFamilyProcW, 159 (LPARAM)(&info), 0L); 160 161 return info.isDifferent; 162} 163 164/* Callback for call to EnumFontFamiliesEx in the EnumFamilyNames function. 165 * Expects to be called once for each face name in the family specified 166 * in the call. We extract the full name for the font which is expected 167 * to be in the "system encoding" and create canonical and lower case 168 * Java strings for the name which are added to the maps. The lower case 169 * name is used as key to the family name value in the font to family map, 170 * the canonical name is one of the"list" of members of the family. 171 */ 172static int CALLBACK EnumFontFacesInFamilyProcW( 173 ENUMLOGFONTEXW *lpelfe, 174 NEWTEXTMETRICEX *lpntme, 175 int FontType, 176 LPARAM lParam) 177{ 178 GdiFontMapInfo *fmi = (GdiFontMapInfo*)lParam; 179 JNIEnv *env = fmi->env; 180 jstring fullname, fullnameLC; 181 182 /* Exceptions indicate critical errors such that program cannot continue 183 * with further execution. Henceforth, the function returns immediately 184 * on pending exceptions. In these situations, the function also returns 185 * 0 indicating windows API to stop further enumeration and callbacks. 186 * 187 * The JNI functions do not clear the pending exceptions. This allows the 188 * caller (Java code) to check and handle exceptions in the best possible 189 * way. 190 */ 191 if ((*env)->ExceptionCheck(env)) { 192 return 0; 193 } 194 195 /* Both Vista and XP return DEVICE_FONTTYPE for OTF fonts */ 196 if (FontType != TRUETYPE_FONTTYPE && FontType != DEVICE_FONTTYPE) { 197 return 1; 198 } 199 200 /* Windows has font aliases and so may enumerate fonts from 201 * the aliased family if any actual font of that family is installed. 202 * To protect against it ignore fonts which aren't enumerated under 203 * their true family. 204 */ 205 if (DifferentFamily(lpelfe->elfLogFont.lfFaceName, 206 lpelfe->elfFullName)) { 207 return 1; 208 } 209 210 fullname = (*env)->NewString(env, lpelfe->elfFullName, 211 (jsize)wcslen((LPWSTR)lpelfe->elfFullName)); 212 if (fullname == NULL) { 213 (*env)->ExceptionClear(env); 214 return 1; 215 } 216 217 (*env)->CallBooleanMethod(env, fmi->list, fmi->addMID, fullname); 218 if ((*env)->ExceptionCheck(env)) { 219 /* Delete the created reference before return */ 220 DeleteLocalReference(env, fullname); 221 return 0; 222 } 223 224 fullnameLC = (*env)->CallObjectMethod(env, fullname, 225 fmi->toLowerCaseMID, fmi->locale); 226 /* Delete the created reference after its usage */ 227 DeleteLocalReference(env, fullname); 228 if ((*env)->ExceptionCheck(env)) { 229 return 0; 230 } 231 232 (*env)->CallObjectMethod(env, fmi->fontToFamilyMap, 233 fmi->putMID, fullnameLC, fmi->family); 234 /* Delete the created reference after its usage */ 235 DeleteLocalReference(env, fullnameLC); 236 if ((*env)->ExceptionCheck(env)) { 237 return 0; 238 } 239 240 return 1; 241} 242 243/* Callback for EnumFontFamiliesEx in populateFontFileNameMap. 244 * Expects to be called for every charset of every font family. 245 * If this is the first time we have been called for this family, 246 * add a new mapping to the familyToFontListMap from this family to a 247 * list of its members. To populate that list, further enumerate all faces 248 * in this family for the matched charset. This assumes that all fonts 249 * in a family support the same charset, which is a fairly safe assumption 250 * and saves time as the call we make here to EnumFontFamiliesEx will 251 * enumerate the members of this family just once each. 252 * Because we set fmi->list to be the newly created list the call back 253 * can safely add to that list without a search. 254 */ 255static int CALLBACK EnumFamilyNamesW( 256 ENUMLOGFONTEXW *lpelfe, /* pointer to logical-font data */ 257 NEWTEXTMETRICEX *lpntme, /* pointer to physical-font data */ 258 int FontType, /* type of font */ 259 LPARAM lParam ) /* application-defined data */ 260{ 261 GdiFontMapInfo *fmi = (GdiFontMapInfo*)lParam; 262 JNIEnv *env = fmi->env; 263 jstring familyLC; 264 size_t slen; 265 LOGFONTW lfw; 266 jboolean mapHasKey; 267 268 /* Exceptions indicate critical errors such that program cannot continue 269 * with further execution. Henceforth, the function returns immediately 270 * on pending exceptions. In these situations, the function also returns 271 * 0 indicating windows API to stop further enumeration and callbacks. 272 * 273 * The JNI functions do not clear the pending exceptions. This allows the 274 * caller (Java code) to check and handle exceptions in the best possible 275 * way. 276 */ 277 if ((*env)->ExceptionCheck(env)) { 278 return 0; 279 } 280 281 /* Both Vista and XP return DEVICE_FONTTYPE for OTF fonts */ 282 if (FontType != TRUETYPE_FONTTYPE && FontType != DEVICE_FONTTYPE) { 283 return 1; 284 } 285/* wprintf(L"FAMILY=%s charset=%d FULL=%s\n", */ 286/* lpelfe->elfLogFont.lfFaceName, */ 287/* lpelfe->elfLogFont.lfCharSet, */ 288/* lpelfe->elfFullName); */ 289/* fflush(stdout); */ 290 291 /* Windows lists fonts which have a vmtx (vertical metrics) table twice. 292 * Once using their normal name, and again preceded by '@'. These appear 293 * in font lists in some windows apps, such as wordpad. We don't want 294 * these so we skip any font where the first character is '@' 295 */ 296 if (lpelfe->elfLogFont.lfFaceName[0] == L'@') { 297 return 1; 298 } 299 slen = wcslen(lpelfe->elfLogFont.lfFaceName); 300 fmi->family = (*env)->NewString(env,lpelfe->elfLogFont.lfFaceName, (jsize)slen); 301 if (fmi->family == NULL) { 302 (*env)->ExceptionClear(env); 303 return 1; 304 } 305 306 familyLC = (*env)->CallObjectMethod(env, fmi->family, 307 fmi->toLowerCaseMID, fmi->locale); 308 /* Delete the created reference after its usage */ 309 if ((*env)->ExceptionCheck(env)) { 310 DeleteLocalReference(env, fmi->family); 311 return 0; 312 } 313 314 /* check if already seen this family with a different charset */ 315 mapHasKey = (*env)->CallBooleanMethod(env, 316 fmi->familyToFontListMap, 317 fmi->containsKeyMID, 318 familyLC); 319 if ((*env)->ExceptionCheck(env)) { 320 /* Delete the created references before return */ 321 DeleteLocalReference(env, fmi->family); 322 DeleteLocalReference(env, familyLC); 323 return 0; 324 } else if (mapHasKey) { 325 /* Delete the created references before return */ 326 DeleteLocalReference(env, fmi->family); 327 DeleteLocalReference(env, familyLC); 328 return 1; 329 } 330 331 fmi->list = (*env)->NewObject(env, 332 fmi->arrayListClass, fmi->arrayListCtr, 4); 333 if (fmi->list == NULL) { 334 /* Delete the created references before return */ 335 DeleteLocalReference(env, fmi->family); 336 DeleteLocalReference(env, familyLC); 337 return 0; 338 } 339 340 (*env)->CallObjectMethod(env, fmi->familyToFontListMap, 341 fmi->putMID, familyLC, fmi->list); 342 /* Delete the created reference after its usage */ 343 DeleteLocalReference(env, familyLC); 344 if ((*env)->ExceptionCheck(env)) { 345 /* Delete the created reference before return */ 346 DeleteLocalReference(env, fmi->family); 347 DeleteLocalReference(env, fmi->list); 348 return 0; 349 } 350 351 memset(&lfw, 0, sizeof(lfw)); 352 wcscpy(lfw.lfFaceName, lpelfe->elfLogFont.lfFaceName); 353 lfw.lfCharSet = lpelfe->elfLogFont.lfCharSet; 354 EnumFontFamiliesExW(screenDC, &lfw, 355 (FONTENUMPROCW)EnumFontFacesInFamilyProcW, 356 lParam, 0L); 357 358 /* Delete the created reference after its usage in the enum function */ 359 DeleteLocalReference(env, fmi->family); 360 DeleteLocalReference(env, fmi->list); 361 return 1; 362} 363 364/* It looks like TrueType fonts have " (TrueType)" tacked on the end of their 365 * name, so we can try to use that to distinguish TT from other fonts. 366 * However if a program "installed" a font in the registry the key may 367 * not include that. We could also try to "pass" fonts which have no "(..)" 368 * at the end. But that turns out to pass a few .FON files that MS supply. 369 * If there's no parenthesized type string, we could next try to infer 370 * the file type from the file name extension. Since the MS entries that 371 * have no type string are very few, and have odd names like "MS-DOS CP 437" 372 * and would never return a Java Font anyway its currently OK to put these 373 * in the font map, although clearly the returned names must never percolate 374 * up into a list of available fonts returned to the application. 375 * Additionally for TTC font files the key looks like 376 * Font 1 & Font 2 (TrueType) 377 * or sometimes even : 378 * Font 1 & Font 2 & Font 3 (TrueType) 379 * Also if a Font has a name for this locale that name also 380 * exists in the registry using the appropriate platform encoding. 381 * What do we do then? 382 * 383 * Note: OpenType fonts seems to have " (TrueType)" suffix on Vista 384 * but " (OpenType)" on XP. 385 */ 386static BOOL RegistryToBaseTTNameW(LPWSTR name) { 387 static const wchar_t TTSUFFIX[] = L" (TrueType)"; 388 static const wchar_t OTSUFFIX[] = L" (OpenType)"; 389 size_t TTSLEN = wcslen(TTSUFFIX); 390 wchar_t *suffix; 391 392 size_t len = wcslen(name); 393 if (len == 0) { 394 return FALSE; 395 } 396 if (name[len-1] != L')') { 397 return FALSE; 398 } 399 if (len <= TTSLEN) { 400 return FALSE; 401 } 402 /* suffix length is the same for truetype and opentype fonts */ 403 suffix = name + (len - TTSLEN); 404 if (wcscmp(suffix, TTSUFFIX) == 0 || wcscmp(suffix, OTSUFFIX) == 0) { 405 suffix[0] = L'\0'; /* truncate name */ 406 return TRUE; 407 } 408 return FALSE; 409} 410 411static void registerFontW(GdiFontMapInfo *fmi, jobject fontToFileMap, 412 LPWSTR name, LPWSTR data) { 413 414 wchar_t *ptr1, *ptr2; 415 jstring fontStr; 416 jstring fontStrLC; 417 JNIEnv *env = fmi->env; 418 size_t dslen = wcslen(data); 419 jstring fileStr = (*env)->NewString(env, data, (jsize)dslen); 420 if (fileStr == NULL) { 421 (*env)->ExceptionClear(env); 422 return; 423 } 424 425 /* TTC or ttc means it may be a collection. Need to parse out 426 * multiple font face names separated by " & " 427 * By only doing this for fonts which look like collections based on 428 * file name we are adhering to MS recommendations for font file names 429 * so it seems that we can be sure that this identifies precisely 430 * the MS-supplied truetype collections. 431 * This avoids any potential issues if a TTF file happens to have 432 * a & in the font name (I can't find anything which prohibits this) 433 * and also means we only parse the key in cases we know to be 434 * worthwhile. 435 */ 436 437 if ((data[dslen-1] == L'C' || data[dslen-1] == L'c') && 438 (ptr1 = wcsstr(name, L" & ")) != NULL) { 439 ptr1+=3; 440 while (ptr1 >= name) { /* marginally safer than while (true) */ 441 while ((ptr2 = wcsstr(ptr1, L" & ")) != NULL) { 442 ptr1 = ptr2+3; 443 } 444 fontStr = (*env)->NewString(env, ptr1, (jsize)wcslen(ptr1)); 445 if (fontStr == NULL) { 446 (*env)->ExceptionClear(env); 447 /* Delete the created reference before return */ 448 DeleteLocalReference(env, fileStr); 449 return; 450 } 451 452 fontStrLC = (*env)->CallObjectMethod(env, fontStr, 453 fmi->toLowerCaseMID, 454 fmi->locale); 455 /* Delete the created reference after its usage */ 456 DeleteLocalReference(env, fontStr); 457 if ((*env)->ExceptionCheck(env)) { 458 /* Delete the created reference before return */ 459 DeleteLocalReference(env, fileStr); 460 return; 461 } 462 463 (*env)->CallObjectMethod(env, fontToFileMap, fmi->putMID, 464 fontStrLC, fileStr); 465 /* Delete the reference after its usage */ 466 DeleteLocalReference(env, fontStrLC); 467 if ((*env)->ExceptionCheck(env)) { 468 /* Delete the created reference before return */ 469 DeleteLocalReference(env, fileStr); 470 return; 471 } 472 473 if (ptr1 == name) { 474 break; 475 } else { 476 *(ptr1-3) = L'\0'; 477 ptr1 = name; 478 } 479 } 480 } else { 481 fontStr = (*env)->NewString(env, name, (jsize)wcslen(name)); 482 if (fontStr == NULL) { 483 (*env)->ExceptionClear(env); 484 /* Delete the created reference before return */ 485 DeleteLocalReference(env, fileStr); 486 return; 487 } 488 489 fontStrLC = (*env)->CallObjectMethod(env, fontStr, 490 fmi->toLowerCaseMID, fmi->locale); 491 /* Delete the created reference after its usage */ 492 DeleteLocalReference(env, fontStr); 493 if ((*env)->ExceptionCheck(env)) { 494 /* Delete the created reference before return */ 495 DeleteLocalReference(env, fileStr); 496 return; 497 } 498 499 (*env)->CallObjectMethod(env, fontToFileMap, fmi->putMID, 500 fontStrLC, fileStr); 501 /* Delete the created reference after its usage */ 502 DeleteLocalReference(env, fontStrLC); 503 if ((*env)->ExceptionCheck(env)) { 504 /* Delete the created reference before return */ 505 DeleteLocalReference(env, fileStr); 506 return; 507 } 508 } 509 510 /* Delete the created reference after its usage */ 511 DeleteLocalReference(env, fileStr); 512} 513 514/* Obtain all the fontname -> filename mappings. 515 * This is called once and the results returned to Java code which can 516 * use it for lookups to reduce or avoid the need to search font files. 517 */ 518JNIEXPORT void JNICALL 519Java_sun_awt_Win32FontManager_populateFontFileNameMap0 520(JNIEnv *env, jclass obj, jobject fontToFileMap, 521 jobject fontToFamilyMap, jobject familyToFontListMap, jobject locale) 522{ 523#define MAX_BUFFER (FILENAME_MAX+1) 524 const wchar_t wname[MAX_BUFFER]; 525 const char data[MAX_BUFFER]; 526 527 DWORD type; 528 LONG ret; 529 HKEY hkeyFonts; 530 DWORD dwNameSize; 531 DWORD dwDataValueSize; 532 DWORD nval; 533 DWORD dwNumValues, dwMaxValueNameLen, dwMaxValueDataLen; 534 DWORD numValues = 0; 535 jclass classIDHashMap; 536 jclass classIDString; 537 jmethodID putMID; 538 GdiFontMapInfo fmi; 539 LOGFONTW lfw; 540 541 /* Check we were passed all the maps we need, and do lookup of 542 * methods for JNI up-calls 543 */ 544 if (fontToFileMap == NULL || 545 fontToFamilyMap == NULL || 546 familyToFontListMap == NULL) { 547 return; 548 } 549 classIDHashMap = (*env)->FindClass(env, "java/util/HashMap"); 550 if (classIDHashMap == NULL) { 551 return; 552 } 553 putMID = (*env)->GetMethodID(env, classIDHashMap, "put", 554 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); 555 if (putMID == NULL) { 556 return; 557 } 558 559 fmi.env = env; 560 fmi.fontToFamilyMap = fontToFamilyMap; 561 fmi.familyToFontListMap = familyToFontListMap; 562 fmi.putMID = putMID; 563 fmi.locale = locale; 564 fmi.containsKeyMID = (*env)->GetMethodID(env, classIDHashMap, 565 "containsKey", 566 "(Ljava/lang/Object;)Z"); 567 if (fmi.containsKeyMID == NULL) { 568 return; 569 } 570 571 fmi.arrayListClass = (*env)->FindClass(env, "java/util/ArrayList"); 572 if (fmi.arrayListClass == NULL) { 573 return; 574 } 575 fmi.arrayListCtr = (*env)->GetMethodID(env, fmi.arrayListClass, 576 "<init>", "(I)V"); 577 if (fmi.arrayListCtr == NULL) { 578 return; 579 } 580 fmi.addMID = (*env)->GetMethodID(env, fmi.arrayListClass, 581 "add", "(Ljava/lang/Object;)Z"); 582 if (fmi.addMID == NULL) { 583 return; 584 } 585 586 classIDString = (*env)->FindClass(env, "java/lang/String"); 587 if (classIDString == NULL) { 588 return; 589 } 590 fmi.toLowerCaseMID = 591 (*env)->GetMethodID(env, classIDString, "toLowerCase", 592 "(Ljava/util/Locale;)Ljava/lang/String;"); 593 if (fmi.toLowerCaseMID == NULL) { 594 return; 595 } 596 597 screenDC = GetDC(NULL); 598 if (screenDC == NULL) { 599 return; 600 } 601 602 /* Enumerate fonts via GDI to build maps of fonts and families */ 603 memset(&lfw, 0, sizeof(lfw)); 604 lfw.lfCharSet = DEFAULT_CHARSET; /* all charsets */ 605 wcscpy(lfw.lfFaceName, L""); /* one face per family (CHECK) */ 606 EnumFontFamiliesExW(screenDC, &lfw, 607 (FONTENUMPROCW)EnumFamilyNamesW, 608 (LPARAM)(&fmi), 0L); 609 610 /* Use the windows registry to map font names to files */ 611 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, 612 FONTKEY_NT, 0L, KEY_READ, &hkeyFonts); 613 if (ret != ERROR_SUCCESS) { 614 ReleaseDC(NULL, screenDC); 615 screenDC = NULL; 616 return; 617 } 618 619 ret = RegQueryInfoKeyW(hkeyFonts, NULL, NULL, NULL, NULL, NULL, NULL, 620 &dwNumValues, &dwMaxValueNameLen, 621 &dwMaxValueDataLen, NULL, NULL); 622 623 if (ret != ERROR_SUCCESS || 624 dwMaxValueNameLen >= MAX_BUFFER || 625 dwMaxValueDataLen >= MAX_BUFFER) { 626 RegCloseKey(hkeyFonts); 627 ReleaseDC(NULL, screenDC); 628 screenDC = NULL; 629 return; 630 } 631 for (nval = 0; nval < dwNumValues; nval++ ) { 632 dwNameSize = MAX_BUFFER; 633 dwDataValueSize = MAX_BUFFER; 634 ret = RegEnumValueW(hkeyFonts, nval, (LPWSTR)wname, &dwNameSize, 635 NULL, &type, (LPBYTE)data, &dwDataValueSize); 636 637 if (ret != ERROR_SUCCESS) { 638 break; 639 } 640 if (type != REG_SZ) { /* REG_SZ means a null-terminated string */ 641 continue; 642 } 643 644 if (!RegistryToBaseTTNameW((LPWSTR)wname) ) { 645 /* If the filename ends with ".ttf" or ".otf" also accept it. 646 * Not expecting to need to do this for .ttc files. 647 * Also note this code is not mirrored in the "A" (win9x) path. 648 */ 649 LPWSTR dot = wcsrchr((LPWSTR)data, L'.'); 650 if (dot == NULL || ((wcsicmp(dot, L".ttf") != 0) 651 && (wcsicmp(dot, L".otf") != 0))) { 652 continue; /* not a TT font... */ 653 } 654 } 655 registerFontW(&fmi, fontToFileMap, (LPWSTR)wname, (LPWSTR)data); 656 } 657 658 RegCloseKey(hkeyFonts); 659 ReleaseDC(NULL, screenDC); 660 screenDC = NULL; 661} 662