Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

fntsweep.c

Go to the documentation of this file.
00001 /******************************Module*Header*******************************\ 00002 * Module Name: fntsweep.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * Author: Bodin Dresevic [BodinD] 00006 * 00007 * Copyright (c) 1990 Microsoft Corporation 00008 * 00009 * This file contains font sweeper related stuff. 00010 * On the boot of ths system, i.e. initialization of userk, the 00011 * [Fonts] section of win.ini is checked to 00012 * find out if any new fonts have been added by any font installers. 00013 * If third party installers have installed fonts in the system directory 00014 * those are copied to fonts directory. Any fot entries are replaced 00015 * by appropriate *.ttf entries, any fot files are deleted if they were 00016 * ever installed. 00017 * 00018 \**************************************************************************/ 00019 00020 00021 #include "precomp.h" 00022 #pragma hdrstop 00023 #include <setupbat.h> // in sdkinc 00024 00025 CONST WCHAR pwszType1Key[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Type 1 Installer\\Type 1 Fonts"; 00026 CONST WCHAR pwszSweepType1Key[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Type 1 Installer\\LastType1Sweep"; 00027 CONST WCHAR pwszUpdType1Key[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Type 1 Installer\\Upgraded Type1"; 00028 00029 CONST WCHAR pwszFontsKey[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"; 00030 CONST WCHAR pwszSweepKey[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\LastFontSweep"; 00031 CONST WCHAR pwszFontDrivers[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Font Drivers"; 00032 00033 #define LAST_SWEEP_TIME L"LastSweepTime" 00034 #define UPGRADED_TYPE1 L"UpgradedType1" 00035 00036 #define DWORDALIGN(X) (((X) + 3) & ~3) 00037 00038 WCHAR *gpwcSystemDir; 00039 WCHAR *gpwcFontsDir; 00040 BOOL gbWin31Upgrade; 00041 00042 00043 BOOL bCheckIfDualBootingWithWin31() 00044 { 00045 WCHAR Buffer[32]; 00046 WCHAR awcWindowsDir[MAX_PATH]; 00047 DWORD dwRet; 00048 UINT cwchWinPath = GetSystemWindowsDirectoryW(awcWindowsDir, MAX_PATH); 00049 00050 // the cwchWinPath value does not include the terminating zero 00051 00052 if (awcWindowsDir[cwchWinPath - 1] == L'\\') 00053 { 00054 cwchWinPath -= 1; 00055 } 00056 awcWindowsDir[cwchWinPath] = L'\0'; // make sure to zero terminated 00057 00058 lstrcatW(awcWindowsDir, L"\\system32\\"); 00059 lstrcatW(awcWindowsDir, WINNT_GUI_FILE_W); 00060 00061 dwRet = GetPrivateProfileStringW( 00062 WINNT_DATA_W, 00063 WINNT_D_WIN31UPGRADE_W, 00064 WINNT_A_NO_W, 00065 Buffer, 00066 sizeof(Buffer)/sizeof(WCHAR), 00067 awcWindowsDir 00068 ); 00069 00070 #if DBGSWEEP 00071 DbgPrint("\n dwRet = %ld, win31upgrade = %ws\n\n", dwRet, Buffer); 00072 #endif 00073 00074 return (BOOL)(dwRet ? (!lstrcmpiW(Buffer,WINNT_A_YES)) : 0); 00075 } 00076 00077 00078 /******************************Public*Routine******************************\ 00079 * 00080 * VOID vNullTermWideString (WCHAR *pwcDest, WCHAR *pwcSrc, ULONG ulLength) 00081 * 00082 * Given pwcSrc, which is not necessarily null-terminated, copy ulLength characters 00083 * the into pwcDest and place a null character after it. 00084 * 00085 * History: 00086 * 03-Feb-99 -by- Donald Chinn [dchinn] 00087 * Wrote it. 00088 \**************************************************************************/ 00089 VOID vNullTermWideString (WCHAR *pwcDest, WCHAR *pwcSrc, ULONG ulLength) 00090 { 00091 ULONG index; 00092 00093 for (index = 0; index < ulLength; index++) { 00094 *pwcDest++ = *pwcSrc++; 00095 } 00096 *pwcDest = '\0'; 00097 } 00098 00099 00100 /******************************Public*Routine******************************\ 00101 * 00102 * BOOL bCheckFontEntry(WCHAR *pwcName, WCHAR *pwcExtension) 00103 * 00104 * This function assumes that both pwcName and pwcExtension are null-terminated. 00105 * 00106 * History: 00107 * 25-Oct-1995 -by- Bodin Dresevic [BodinD] 00108 * Wrote it. 00109 \**************************************************************************/ 00110 00111 00112 BOOL bCheckFontEntry(WCHAR *pwcName, WCHAR *pwcExtension) 00113 { 00114 BOOL bRet = FALSE; 00115 LONG cwc = (LONG)wcslen(pwcName) - (LONG)wcslen(pwcExtension); 00116 if (cwc > 0) 00117 { 00118 bRet = !_wcsicmp(&pwcName[cwc], pwcExtension); 00119 } 00120 return bRet; 00121 00122 } 00123 00124 00125 00126 /******************************Public*Routine******************************\ 00127 * Process win.ini line 00128 * 00129 * History: 00130 * 24-Oct-1995 -by- Bodin Dresevic [BodinD] 00131 * Wrote it. 00132 \**************************************************************************/ 00133 00134 #define EXT_TRUETYPE L"(TrueType)" 00135 #define EXT_FOT L".FOT" 00136 00137 00138 VOID vProcessFontEntry( 00139 HKEY hkey, 00140 WCHAR *pwcValueName, 00141 ULONG ulValueNameLength, 00142 WCHAR *pwcFileName, 00143 ULONG ulFileNameLength 00144 ) 00145 { 00146 NTSTATUS Status; 00147 UNICODE_STRING UnicodeString; 00148 BOOL bFot = FALSE; 00149 WCHAR awcTTF[MAX_PATH]; 00150 WCHAR awcTmpBuf[MAX_PATH]; 00151 WCHAR *pwcTTF; 00152 FLONG fl, fl2; 00153 FLONG flEmbed; 00154 DWORD dwPidTid; 00155 WCHAR awcValueName[MAX_PATH]; // null-terminated pwcValueName 00156 WCHAR awcFileName[MAX_PATH]; // null-terminated pwcFileName 00157 00158 00159 // Make sure the ValueName is null-terminated 00160 ulValueNameLength = min(MAX_PATH - 1, ulValueNameLength); 00161 vNullTermWideString (awcValueName, pwcValueName, ulValueNameLength); 00162 00163 // Make sure the FileName is null-terminated 00164 ulFileNameLength = min(MAX_PATH - 1, ulFileNameLength); 00165 vNullTermWideString (awcFileName, pwcFileName, ulFileNameLength); 00166 00167 if (bCheckFontEntry(awcValueName, EXT_TRUETYPE)) 00168 { 00169 // This is a tt entry, either .fot or .ttf 00170 00171 if (bFot = bCheckFontEntry(awcFileName, EXT_FOT)) 00172 { 00173 // this is an .fot entry, must find ttf pointed to by .fot, 00174 // but first must get the full path to the .fot file 00175 // for cGetTTFFromFOT routine expects it. We will also need 00176 // the full path to the .fot file so that we can delete it 00177 // eventually. 00178 00179 if (bMakePathNameW(awcTmpBuf, awcFileName, NULL, &fl2)) 00180 { 00181 if (cGetTTFFromFOT(awcTmpBuf, MAX_PATH, awcTTF, &fl, &flEmbed, &dwPidTid, TRUE) && 00182 !(fl & FONT_ISNOT_FOT)) 00183 { 00184 // fix the entry to point to .ttf file. At this point 00185 // awcTTF points to the FULL path to the .ttf file. 00186 // However, we will only need a relative path to the 00187 // .ttf file, when the .ttf file is in the %windir%\system 00188 // or %windir%\fonts directories. In case the file is in the 00189 // %windir%\system directory we shall copy it to %windir%\fonts 00190 // directory and write the relative path to the registry. 00191 // In case it is in the %windir%\fonts directory we do not 00192 // touch the file and also just write the relative path to the 00193 // registry. In any other case we just write the full .ttf 00194 // path to the registry. 00195 00196 // first delete the .fot file, it is no longer needed 00197 00198 if (bFot && !gbWin31Upgrade) 00199 { 00200 UserVerify(DeleteFileW(awcTmpBuf)); 00201 } 00202 00203 if ((fl & (FONT_IN_FONTS_DIR | FONT_IN_SYSTEM_DIR)) == 0) 00204 { 00205 // if ttf file is not in either the system or the fonts 00206 // directories, just write the full path to the registry 00207 00208 pwcTTF = awcTTF; 00209 } 00210 else 00211 { 00212 // find the bare file part, this is what will be written 00213 // in the registry 00214 00215 pwcTTF = &awcTTF[wcslen(awcTTF) - 1]; 00216 while ((pwcTTF >= awcTTF) && (*pwcTTF != L'\\') && (*pwcTTF != L':')) 00217 pwcTTF--; 00218 pwcTTF++; 00219 00220 if (fl & FONT_IN_SYSTEM_DIR) 00221 { 00222 // need to move the ttf to fonts dir, can reuse the 00223 // buffer on the stack: 00224 00225 wcscpy(awcTmpBuf, gpwcFontsDir); 00226 lstrcatW(awcTmpBuf, L"\\"); 00227 lstrcatW(awcTmpBuf, pwcTTF); 00228 00229 // note that MoveFile should succeed, for if there was 00230 // a ttf file of the same file name in %windir%\fonts dir 00231 // we would not have been in this code path. 00232 00233 RIPMSG2(RIP_VERBOSE, "Moving %ws to %ws", awcTTF, awcTmpBuf); 00234 if (!gbWin31Upgrade) 00235 { 00236 UserVerify(MoveFileW(awcTTF, awcTmpBuf)); 00237 } 00238 else 00239 { 00240 // Boolean value TRUE means "do not copy if target exists" 00241 00242 UserVerify(CopyFileW(awcTTF, awcTmpBuf, TRUE)); 00243 } 00244 } 00245 } 00246 00247 RIPMSG2(RIP_VERBOSE, "writing to the registry:\n %ws=%ws", pwcValueName, pwcTTF); 00248 RtlInitUnicodeString(&UnicodeString, awcValueName); 00249 Status = NtSetValueKey(hkey, 00250 &UnicodeString, 00251 0, 00252 REG_SZ, 00253 pwcTTF, 00254 (wcslen(pwcTTF)+1) * sizeof(WCHAR)); 00255 UserAssert(NT_SUCCESS(Status)); 00256 } 00257 #if DBG 00258 else 00259 { 00260 RIPMSG1(RIP_WARNING, "Could not locate ttf pointed to by %ws", awcTmpBuf); 00261 } 00262 #endif 00263 } 00264 #if DBG 00265 else 00266 { 00267 RIPMSG1(RIP_WARNING, "Could not locate .fot: %ws", awcFileName); 00268 } 00269 #endif 00270 } 00271 } 00272 else 00273 { 00274 // not a true type case. little bit simpler, 00275 // we will use awcTTF buffer for the full path name, and pwcTTF 00276 // as local variable even though these TTF names are misnomer 00277 // for these are not tt fonts 00278 00279 if (bMakePathNameW(awcTTF, awcFileName,NULL, &fl)) 00280 { 00281 // At this point 00282 // awcTTF points to the FULL path to the font file. 00283 00284 // If the font is in the system subdirectory we will just move it 00285 // to the fonts subdirectory. If the path in the registry is relative 00286 // we will leave it alone. If it is an absolute path, we shall 00287 // fix the registry entry to only contain relative path, the 00288 // absolute path is redundant. 00289 00290 if (fl & (FONT_IN_SYSTEM_DIR | FONT_IN_FONTS_DIR)) 00291 { 00292 // find the bare file part, this is what will be written 00293 // in the registry 00294 00295 pwcTTF = &awcTTF[wcslen(awcTTF) - 1]; 00296 while ((pwcTTF >= awcTTF) && (*pwcTTF != L'\\') && (*pwcTTF != L':')) 00297 pwcTTF--; 00298 pwcTTF++; 00299 00300 if (fl & FONT_IN_SYSTEM_DIR) 00301 { 00302 // need to move the font to fonts dir, can reuse the 00303 // buffer on the stack to build the full destination path 00304 00305 wcscpy(awcTmpBuf, gpwcFontsDir); 00306 lstrcatW(awcTmpBuf, L"\\"); 00307 lstrcatW(awcTmpBuf, pwcTTF); 00308 00309 // note that MoveFile should succeed, for if there was 00310 // a font file of the same file name in %windir%\fonts dir 00311 // we would not have been in this code path. The only time 00312 // it could fail if the path in the registry is absolute. 00313 00314 RIPMSG2(RIP_VERBOSE, "Moving %ws to %ws", awcTTF, awcTmpBuf); 00315 if (!gbWin31Upgrade) 00316 { 00317 UserVerify(MoveFileW(awcTTF, awcTmpBuf)); 00318 } 00319 else 00320 { 00321 // Boolean value TRUE means "do not copy if target exists" 00322 00323 UserVerify(CopyFileW(awcTTF, awcTmpBuf, TRUE)); 00324 } 00325 } 00326 00327 // check if the file path in the registry is absolute, 00328 // if so make it relative: 00329 00330 if (!(fl & FONT_RELATIVE_PATH)) 00331 { 00332 RIPMSG2(RIP_VERBOSE, "writing to the registry:\n %ws=%ws", pwcValueName, pwcTTF); 00333 RtlInitUnicodeString(&UnicodeString, awcValueName); 00334 Status = NtSetValueKey(hkey, 00335 &UnicodeString, 00336 0, 00337 REG_SZ, 00338 pwcTTF, 00339 (wcslen(pwcTTF)+1) * sizeof(WCHAR)); 00340 UserAssert(NT_SUCCESS(Status)); 00341 } 00342 } 00343 } 00344 } 00345 } 00346 00347 00348 /******************************Public*Routine******************************\ 00349 * 00350 * VOID vMoveFileFromSystemToFontsDir(WCHAR *pwcFile) 00351 * 00352 * History: 00353 * 24-Apr-1996 -by- Bodin Dresevic [BodinD] 00354 * Wrote it. 00355 \**************************************************************************/ 00356 00357 00358 00359 00360 VOID vMoveFileFromSystemToFontsDir(WCHAR *pwcFile) 00361 { 00362 WCHAR awcTmpBuf[MAX_PATH]; 00363 WCHAR awcTmp[MAX_PATH]; 00364 FLONG fl; 00365 WCHAR *pwcTmp; 00366 00367 #if DBG 00368 BOOL bOk; 00369 #endif 00370 00371 if (bMakePathNameW(awcTmp, pwcFile,NULL, &fl)) 00372 { 00373 // If the font is in the system subdirectory we will just move it 00374 // to the fonts subdirectory. The path in the registry is relative 00375 // and we will leave it alone. 00376 00377 if 00378 ( 00379 (fl & (FONT_IN_SYSTEM_DIR | FONT_RELATIVE_PATH)) == 00380 (FONT_IN_SYSTEM_DIR | FONT_RELATIVE_PATH) 00381 ) 00382 { 00383 // find the bare file part, this is what will be written 00384 // in the registry 00385 00386 pwcTmp = &awcTmp[wcslen(awcTmp) - 1]; 00387 while ((pwcTmp >= awcTmp) && (*pwcTmp != L'\\') && (*pwcTmp != L':')) 00388 pwcTmp--; 00389 00390 if (pwcTmp > awcTmp) 00391 pwcTmp++; 00392 00393 // need to move the font to fonts dir, can reuse the 00394 // buffer on the stack to build the full destination path 00395 00396 wcscpy(awcTmpBuf, gpwcFontsDir); 00397 lstrcatW(awcTmpBuf, L"\\"); 00398 lstrcatW(awcTmpBuf, pwcTmp); 00399 00400 // note that MoveFile should succeed, for if there was 00401 // a font file of the same file name in %windir%\fonts dir 00402 // we would not have been in this code path. 00403 00404 #if DBG 00405 bOk = 00406 #endif 00407 MoveFileW(awcTmp, awcTmpBuf); 00408 00409 RIPMSG3(RIP_VERBOSE, 00410 "move %ws to %ws %s", 00411 awcTmp, 00412 awcTmpBuf, 00413 (bOk) ? "succeeded" : "failed"); 00414 } 00415 #if DBG 00416 else 00417 { 00418 RIPMSG2(RIP_WARNING, 00419 "File %ws not in system directory, fl = 0x%lx\n", 00420 awcTmp, fl); 00421 } 00422 #endif 00423 00424 } 00425 #if DBG 00426 else 00427 { 00428 RIPMSG1(RIP_WARNING, "Could not locate %ws", pwcFile); 00429 } 00430 #endif 00431 } 00432 00433 00434 00435 /******************************Public*Routine******************************\ 00436 * 00437 * VOID vProcessType1FontEntry 00438 * 00439 * 00440 * Effects: All this routine does is to check if pwcPFM and pwcPFB pointed to 00441 * by pwcValueData point to files in the %windir%system directory 00442 * and if so copies these type 1 files to %windir%\fonts directory 00443 * 00444 * History: 00445 * 20-Nov-1995 -by- Bodin Dresevic [BodinD] 00446 * Wrote it. 00447 \**************************************************************************/ 00448 00449 00450 VOID vProcessType1FontEntry( 00451 HKEY hkey, 00452 WCHAR *pwcValueName, 00453 ULONG ulValueNameLength, 00454 WCHAR *pwcValueData, 00455 ULONG ulValueDataLength 00456 ) 00457 { 00458 WCHAR *pwcPFM, *pwcPFB; 00459 00460 UNREFERENCED_PARAMETER(hkey); 00461 UNREFERENCED_PARAMETER(pwcValueName); 00462 UNREFERENCED_PARAMETER(ulValueNameLength); 00463 UNREFERENCED_PARAMETER(ulValueDataLength); 00464 00465 // skip unused boolean value in this multi reg_sz string: 00466 00467 if ((pwcValueData[0] != L'\0') && (pwcValueData[1] == L'\0')) 00468 { 00469 pwcPFM = &pwcValueData[2]; 00470 pwcPFB = pwcPFM + wcslen(pwcPFM) + 1; // add 1 for zero separator 00471 00472 vMoveFileFromSystemToFontsDir(pwcPFM); 00473 vMoveFileFromSystemToFontsDir(pwcPFB); 00474 } 00475 } 00476 00477 00478 /******************************Public*Routine******************************\ 00479 * 00480 * VOID vAddRemote/LocalType1Font 00481 * 00482 * History: 00483 * 25-Apr-1996 -by- Bodin Dresevic [BodinD] 00484 * Wrote it. 00485 \**************************************************************************/ 00486 00487 00488 00489 VOID vAddType1Font( 00490 WCHAR *pwcValueData, 00491 DWORD dwFlags 00492 ) 00493 { 00494 WCHAR *pwcPFM, *pwcPFB, *pwcMMM; 00495 00496 #if DBG 00497 int iRet; 00498 #endif 00499 00500 // skip unused boolean value in this multi reg_sz string: 00501 00502 if ((pwcValueData[0] != L'\0') && (pwcValueData[1] == L'\0')) 00503 { 00504 pwcPFM = &pwcValueData[2]; 00505 pwcPFB = pwcPFM + wcslen(pwcPFM) + 1; // add 1 for zero separator 00506 pwcMMM = pwcPFB + wcslen(pwcPFB) + 1; // may of may not be there. 00507 00508 // replace space by separator and call addfontresourcew 00509 00510 pwcPFB[-1] = PATH_SEPARATOR; 00511 00512 // if this is a multiple master font, need one more separator: 00513 00514 if (pwcMMM[0] != L'\0') 00515 pwcMMM[-1] = PATH_SEPARATOR; 00516 00517 #if DBG 00518 iRet = 00519 #endif 00520 00521 GdiAddFontResourceW(pwcPFM, dwFlags, NULL); 00522 00523 #if DBGSWEEP 00524 DbgPrint("%ld = GdiAddFontResourceW(%ws, 0x%lx);\n", 00525 iRet, pwcPFM, dwFlags); 00526 #endif 00527 } 00528 } 00529 00530 00531 VOID vAddRemoteType1Font( 00532 HKEY hkey, 00533 WCHAR *pwcValueName, 00534 ULONG ulValueNameLength, 00535 WCHAR *pwcValueData, 00536 ULONG ulValueDataLength 00537 ) 00538 { 00539 UNREFERENCED_PARAMETER(hkey); 00540 UNREFERENCED_PARAMETER(pwcValueName); 00541 UNREFERENCED_PARAMETER(ulValueNameLength); 00542 UNREFERENCED_PARAMETER(ulValueDataLength); 00543 vAddType1Font(pwcValueData, AFRW_ADD_REMOTE_FONT); 00544 } 00545 00546 VOID vAddLocalType1Font( 00547 HKEY hkey, 00548 WCHAR *pwcValueName, 00549 ULONG ulValueNameLength, 00550 WCHAR *pwcValueData, 00551 ULONG ulValueDataLength 00552 ) 00553 { 00554 UNREFERENCED_PARAMETER(hkey); 00555 UNREFERENCED_PARAMETER(pwcValueName); 00556 UNREFERENCED_PARAMETER(ulValueNameLength); 00557 UNREFERENCED_PARAMETER(ulValueDataLength); 00558 vAddType1Font(pwcValueData, AFRW_ADD_LOCAL_FONT); 00559 } 00560 00561 00562 typedef VOID (*PFNENTRY)(HKEY hkey, WCHAR *, ULONG, WCHAR *, ULONG); 00563 00564 00565 /******************************Public*Routine******************************\ 00566 * 00567 * VOID vFontSweep() 00568 * 00569 * This is the main routine in this module. Checks if the fonts need to be 00570 * "sweeped" and does so if need be. 00571 * 00572 * History: 00573 * 27-Oct-1995 -by- Bodin Dresevic [BodinD] 00574 * Wrote it. 00575 \**************************************************************************/ 00576 00577 VOID vSweepFonts( 00578 PCWSTR pwszFontListKey, // font list key 00579 PCWSTR pwszFontSweepKey, // the corresponding sweep key 00580 PFNENTRY pfnProcessFontEntry, // function that processes individual entry 00581 BOOL bForceEnum // force enumeration 00582 ) 00583 { 00584 DWORD cjMaxValueName; 00585 DWORD iFont; 00586 NTSTATUS Status; 00587 UNICODE_STRING UnicodeString; 00588 OBJECT_ATTRIBUTES ObjA; 00589 KEY_FULL_INFORMATION KeyInfo; 00590 DWORD dwReturnLength; 00591 00592 PKEY_VALUE_FULL_INFORMATION KeyValueInfo; 00593 BYTE *pjValueData; 00594 00595 HKEY hkey = NULL; 00596 struct { 00597 KEY_VALUE_PARTIAL_INFORMATION; 00598 LARGE_INTEGER; 00599 } SweepValueInfo; 00600 LARGE_INTEGER LastSweepTime; 00601 BOOL bSweep = FALSE; 00602 00603 HKEY hkeyLastSweep; 00604 DWORD cjData; 00605 00606 if (!bForceEnum) 00607 { 00608 // first check if anything needs to be done, that is, if anybody 00609 // touched the [Fonts] section of the registry since the last time we sweeped it. 00610 // get the time of the last sweep of the fonts section of the registry: 00611 00612 RtlInitUnicodeString(&UnicodeString, pwszFontSweepKey); 00613 InitializeObjectAttributes(&ObjA, 00614 &UnicodeString, 00615 OBJ_CASE_INSENSITIVE, 00616 NULL, 00617 NULL); 00618 Status = NtOpenKey(&hkeyLastSweep, 00619 KEY_READ | KEY_WRITE, 00620 &ObjA); 00621 00622 if (!NT_SUCCESS(Status)) 00623 { 00624 DWORD dwDisposition; 00625 00626 // We are running for the first time, we need to create the key 00627 // for it does not exist as yet at this time 00628 00629 bSweep = TRUE; 00630 00631 // Create the key, open it for writing, since we will have to 00632 // store the time when the [Fonts] section of the registry was last swept 00633 00634 Status = NtCreateKey(&hkeyLastSweep, 00635 KEY_WRITE, 00636 &ObjA, 00637 0, 00638 NULL, 00639 REG_OPTION_NON_VOLATILE, 00640 &dwDisposition); 00641 00642 if (!NT_SUCCESS(Status)) 00643 return; 00644 } 00645 else 00646 { 00647 RtlInitUnicodeString(&UnicodeString, LAST_SWEEP_TIME); 00648 Status = NtQueryValueKey(hkeyLastSweep, 00649 &UnicodeString, 00650 KeyValuePartialInformation, 00651 &SweepValueInfo, 00652 sizeof(SweepValueInfo), 00653 &dwReturnLength); 00654 if (!NT_SUCCESS(Status)) 00655 { 00656 bSweep = TRUE; // force sweep, something is suspicious 00657 } 00658 else 00659 { 00660 UserAssert(SweepValueInfo.Type == REG_BINARY); 00661 UserAssert(SweepValueInfo.DataLength == sizeof(LastSweepTime)); 00662 RtlCopyMemory(&LastSweepTime, &SweepValueInfo.Data, sizeof(LastSweepTime)); 00663 } 00664 } 00665 } 00666 else 00667 { 00668 bSweep = TRUE; 00669 } 00670 00671 // now open the Fonts key and get the time the key last changed: 00672 // now get the time of the time of the last change is bigger than 00673 // the time of last sweep, must sweep again: 00674 00675 RtlInitUnicodeString(&UnicodeString, pwszFontListKey); 00676 InitializeObjectAttributes(&ObjA, 00677 &UnicodeString, 00678 OBJ_CASE_INSENSITIVE, 00679 NULL, 00680 NULL); 00681 Status = NtOpenKey(&hkey, 00682 KEY_READ | KEY_WRITE, 00683 &ObjA); 00684 00685 if (NT_SUCCESS(Status)) 00686 { 00687 // get the number of entries in the [Fonts] section 00688 00689 Status = NtQueryKey(hkey, 00690 KeyFullInformation, 00691 &KeyInfo, 00692 sizeof(KeyInfo), 00693 &dwReturnLength); 00694 00695 if (NT_SUCCESS(Status) && KeyInfo.Values) 00696 { 00697 UserAssert(!(KeyInfo.ClassLength | KeyInfo.SubKeys | KeyInfo.MaxNameLen | KeyInfo.MaxClassLen)); 00698 00699 // now let us check if the fonts need to be sweeped. This is the case 00700 // when the registry last write time is bigger than the last sweep time 00701 00702 if (!bSweep) 00703 { 00704 if (KeyInfo.LastWriteTime.QuadPart != LastSweepTime.QuadPart ) { 00705 bSweep = TRUE; 00706 } 00707 } 00708 00709 // init system dir, we will need it: 00710 00711 if (bSweep && 00712 bInitSystemAndFontsDirectoriesW(&gpwcSystemDir, &gpwcFontsDir)) 00713 { 00714 // alloc buffer big enough to hold the biggest ValueName and ValueData 00715 00716 cjMaxValueName = DWORDALIGN(KeyInfo.MaxValueNameLen + sizeof(WCHAR)); 00717 00718 // allocate temporary buffer into which we are going to suck the contents 00719 // of the registry 00720 00721 KeyInfo.MaxValueDataLen = DWORDALIGN(KeyInfo.MaxValueDataLen); 00722 cjData = cjMaxValueName + // space for the value name 00723 KeyInfo.MaxValueDataLen ; // space for the value data 00724 00725 if (KeyValueInfo = UserLocalAlloc(0, sizeof(*KeyValueInfo) + cjData)) 00726 { 00727 for (iFont = 0; iFont < KeyInfo.Values; iFont++) 00728 { 00729 Status = NtEnumerateValueKey( 00730 hkey, 00731 iFont, 00732 KeyValueFullInformation, 00733 KeyValueInfo, 00734 sizeof(*KeyValueInfo) + cjData, 00735 &dwReturnLength); 00736 00737 if (NT_SUCCESS(Status)) 00738 { 00739 UserAssert(KeyValueInfo->NameLength <= KeyInfo.MaxValueNameLen); 00740 UserAssert(KeyValueInfo->DataLength <= KeyInfo.MaxValueDataLen); 00741 UserAssert((KeyValueInfo->Type == REG_SZ) || (KeyValueInfo->Type == REG_MULTI_SZ)); 00742 00743 // data goes into the second half of the buffer 00744 00745 pjValueData = (BYTE *)KeyValueInfo + KeyValueInfo->DataOffset; 00746 00747 // see if the font files are where the registry claims they are. 00748 // It is unfortunate we have to do this because SearchPathW 00749 // is slow because it touches the disk. 00750 00751 (*pfnProcessFontEntry)(hkey, 00752 KeyValueInfo->Name, 00753 KeyValueInfo->NameLength / sizeof(WCHAR), 00754 (WCHAR *)pjValueData, 00755 KeyValueInfo->DataLength / sizeof(WCHAR)); 00756 } 00757 } 00758 00759 if (!bForceEnum) 00760 { 00761 // now that the sweep is completed, get the last write time 00762 // and store it as the LastSweepTime at the appropriate location 00763 00764 Status = NtQueryKey(hkey, 00765 KeyFullInformation, 00766 &KeyInfo, 00767 sizeof(KeyInfo), 00768 &dwReturnLength); 00769 UserAssert(NT_SUCCESS(Status)); 00770 00771 // now remember the result 00772 00773 RtlInitUnicodeString(&UnicodeString, LAST_SWEEP_TIME); 00774 Status = NtSetValueKey(hkeyLastSweep, 00775 &UnicodeString, 00776 0, 00777 REG_BINARY, 00778 &KeyInfo.LastWriteTime, 00779 sizeof(KeyInfo.LastWriteTime)); 00780 UserAssert(NT_SUCCESS(Status)); 00781 } 00782 00783 // free the memory that will be no longer needed 00784 00785 UserLocalFree(KeyValueInfo); 00786 } 00787 } 00788 } 00789 NtClose(hkey); 00790 } 00791 00792 if (!bForceEnum) 00793 { 00794 NtClose(hkeyLastSweep); 00795 } 00796 } 00797 00798 00799 /******************************Public*Routine******************************\ 00800 * 00801 * BOOL bLoadableFontDrivers() 00802 * 00803 * open the font drivers key and check if there are any entries, if so 00804 * return true. If that is the case we will call AddFontResourceW on 00805 * Type 1 fonts at boot time, right after user had logged on 00806 * PostScript printer drivers are not initialized at this time yet, 00807 * it is safe to do it at this time. 00808 * Effects: 00809 * 00810 * Warnings: 00811 * 00812 * History: 00813 * 24-Apr-1996 -by- Bodin Dresevic [BodinD] 00814 * Wrote it. 00815 \**************************************************************************/ 00816 00817 00818 BOOL bLoadableFontDrivers() 00819 { 00820 NTSTATUS Status; 00821 UNICODE_STRING UnicodeString; 00822 OBJECT_ATTRIBUTES ObjA; 00823 KEY_FULL_INFORMATION KeyInfo; 00824 DWORD dwReturnLength; 00825 HKEY hkey = NULL; 00826 BOOL bRet = FALSE; 00827 00828 // open the font drivers key and check if there are any entries, if so 00829 // return true. If that is the case we will call AddFontResourceW on 00830 // Type 1 fonts at boot time, right after user had logged on 00831 // PostScript printer drivers are not initialized at this time yet, 00832 // it is safe to do it at this time. 00833 00834 RtlInitUnicodeString(&UnicodeString, pwszFontDrivers); 00835 InitializeObjectAttributes(&ObjA, 00836 &UnicodeString, 00837 OBJ_CASE_INSENSITIVE, 00838 NULL, 00839 NULL); 00840 Status = NtOpenKey(&hkey, 00841 KEY_READ, 00842 &ObjA); 00843 00844 if (NT_SUCCESS(Status)) 00845 { 00846 // get the number of entries in the [Fonts] section 00847 00848 Status = NtQueryKey(hkey, 00849 KeyFullInformation, 00850 &KeyInfo, 00851 sizeof(KeyInfo), 00852 &dwReturnLength); 00853 00854 if (NT_SUCCESS(Status) && KeyInfo.Values) 00855 { 00856 UserAssert(!(KeyInfo.ClassLength | KeyInfo.SubKeys | KeyInfo.MaxNameLen | KeyInfo.MaxClassLen)); 00857 00858 // externally loadable drivers are present, force sweep 00859 00860 bRet = TRUE; 00861 } 00862 00863 NtClose(hkey); 00864 } 00865 return bRet; 00866 } 00867 00868 00869 00870 /***********************Public*Routine******************************\ 00871 * 00872 * BOOL bCheckAndDeleteTTF() 00873 * 00874 * Checks whether there is a converted TTF corresponding to 00875 * a Type1 font. Delete the TTF file and the reg entry if there is. 00876 * 00877 * History: 00878 * 29-Jan-1998 -by- Xudong Wu [TessieW] 00879 * Wrote it. 00880 \*******************************************************************/ 00881 BOOL bCheckAndDeleteTTF 00882 ( 00883 HKEY hkey, 00884 PKEY_FULL_INFORMATION pKeyInfo, 00885 PKEY_VALUE_FULL_INFORMATION KeyValueInfo, 00886 PKEY_VALUE_BASIC_INFORMATION KeyValueBasicInfo, 00887 DWORD cjData 00888 ) 00889 { 00890 NTSTATUS Status; 00891 UNICODE_STRING UnicodeString; 00892 DWORD dwReturnLength; 00893 ULONG iFont; 00894 WCHAR awcTmp[MAX_PATH], *pFontName, *pType1Name, *pwcFile; 00895 BOOL bDelTTFfile, bRet = TRUE; 00896 FLONG fl; 00897 WCHAR awcType1Name[MAX_PATH]; // null-terminated pType1Name 00898 WCHAR awcFontName[MAX_PATH]; // null-terminated pFontName 00899 WCHAR awcFile[MAX_PATH]; // null-terminated pwcFile 00900 00901 // pKeyInfo holds the full info on the key "Fonts" 00902 for (iFont = 0; iFont < pKeyInfo->Values; iFont++) 00903 { 00904 RtlZeroMemory(KeyValueInfo->Name, cjData); 00905 Status = NtEnumerateValueKey( 00906 hkey, 00907 iFont, 00908 KeyValueFullInformation, 00909 KeyValueInfo, 00910 sizeof(*KeyValueInfo) + cjData, 00911 &dwReturnLength); 00912 00913 if (NT_SUCCESS(Status)) 00914 { 00915 UserAssert(KeyValueInfo->NameLength <= pKeyInfo->MaxValueNameLen); 00916 UserAssert(KeyValueInfo->DataLength <= pKeyInfo->MaxValueDataLen); 00917 UserAssert(KeyValueInfo->Type == REG_SZ); 00918 00919 bDelTTFfile = FALSE; 00920 00921 // Make sure we use null-terminated strings 00922 vNullTermWideString (awcType1Name, 00923 KeyValueBasicInfo->Name, 00924 KeyValueBasicInfo->NameLength / sizeof(WCHAR)); 00925 vNullTermWideString (awcFontName, 00926 KeyValueInfo->Name, 00927 KeyValueInfo->NameLength / sizeof(WCHAR)); 00928 vNullTermWideString (awcFile, 00929 (WCHAR *) ((BYTE *)KeyValueInfo + KeyValueInfo->DataOffset), 00930 KeyValueInfo->DataLength / sizeof(WCHAR)); 00931 pType1Name = awcType1Name; 00932 pFontName = awcFontName; 00933 pwcFile = awcFile; 00934 00935 while((*pType1Name) && (*pType1Name++ == *pFontName++)) 00936 ; 00937 00938 // if the font name match the type1 name 00939 // check whether this is a ttf font 00940 if ((*pType1Name == 0) && (*pFontName++ == L' ')) 00941 { 00942 WCHAR *pTrueType = L"(TrueType)"; 00943 00944 while(*pTrueType && (*pTrueType++ == *pFontName++)) 00945 ; 00946 if (*pTrueType == 0) 00947 { 00948 bDelTTFfile = TRUE; 00949 } 00950 } 00951 00952 if (bDelTTFfile) 00953 { 00954 // delete the converted TTF file 00955 if (bRet = bMakePathNameW(awcTmp, pwcFile, NULL, &fl)) 00956 { 00957 UserVerify((bRet = DeleteFileW(awcTmp))); 00958 } 00959 00960 // remove the reg entry 00961 *pFontName = 0; 00962 RtlInitUnicodeString(&UnicodeString, awcFontName); 00963 Status = NtDeleteValueKey(hkey, (PUNICODE_STRING)&UnicodeString); 00964 00965 // decrement the number of values under [Fonts] 00966 if (NT_SUCCESS(Status)) 00967 pKeyInfo->Values--; 00968 else 00969 bRet = FALSE; 00970 00971 break; 00972 } 00973 } 00974 else 00975 { 00976 bRet = FALSE; 00977 break; 00978 } 00979 } 00980 00981 return bRet; 00982 } 00983 00984 00985 /***********************Public*Routine**************************\ 00986 * 00987 * BOOL bCleanConvertedTTFs() 00988 * 00989 * Enumerate each entry under "Upgrade Type1" key, call 00990 * bCheckAndDeleteTTF() to remove the coverted TTFs. 00991 * 00992 * History: 00993 * 29-Jan-1998 -by- Xudong Wu [TessieW] 00994 * Wrote it. 00995 \***************************************************************/ 00996 BOOL bCleanConvertedTTFs() 00997 { 00998 UNICODE_STRING UnicodeString; 00999 OBJECT_ATTRIBUTES ObjA; 01000 NTSTATUS Status; 01001 HKEY hkeyFonts = NULL, hkeyType1 = NULL; 01002 DWORD dwReturnLength; 01003 DWORD iFontT1, cjData; 01004 DWORD cjMaxValueNameT1, cjMaxValueNameFonts; 01005 BOOL bRet = FALSE, bError = FALSE; 01006 01007 KEY_FULL_INFORMATION KeyInfoType1, KeyInfoFonts; 01008 PKEY_VALUE_BASIC_INFORMATION KeyValueBasicInfo; 01009 PKEY_VALUE_FULL_INFORMATION KeyValueInfo; 01010 01011 // Open and query the value from the "Type1 Fonts" key 01012 // No need to continue if not succeed or no Type1 font listed 01013 RtlInitUnicodeString(&UnicodeString, pwszType1Key); 01014 InitializeObjectAttributes(&ObjA, 01015 &UnicodeString, 01016 OBJ_CASE_INSENSITIVE, 01017 NULL, 01018 NULL); 01019 01020 Status = NtOpenKey(&hkeyType1, 01021 KEY_READ | KEY_WRITE, 01022 &ObjA); 01023 01024 if (NT_SUCCESS(Status)) 01025 { 01026 Status = NtQueryKey(hkeyType1, 01027 KeyFullInformation, 01028 &KeyInfoType1, 01029 sizeof(KeyInfoType1), 01030 &dwReturnLength); 01031 01032 if (NT_SUCCESS(Status) && KeyInfoType1.Values) 01033 { 01034 UserAssert(!(KeyInfoType1.ClassLength | KeyInfoType1.SubKeys | 01035 KeyInfoType1.MaxNameLen | KeyInfoType1.MaxClassLen)); 01036 01037 cjMaxValueNameT1 = DWORDALIGN(KeyInfoType1.MaxValueNameLen + sizeof(WCHAR)); 01038 01039 // Alloc buffer big enough to hold the longest Name 01040 if (KeyValueBasicInfo = UserLocalAlloc(0, sizeof(*KeyValueBasicInfo) + cjMaxValueNameT1)) 01041 { 01042 RtlInitUnicodeString(&UnicodeString, pwszFontsKey); 01043 InitializeObjectAttributes(&ObjA, 01044 &UnicodeString, 01045 OBJ_CASE_INSENSITIVE, 01046 NULL, 01047 NULL); 01048 Status = NtOpenKey(&hkeyFonts, 01049 KEY_READ | KEY_WRITE, 01050 &ObjA); 01051 01052 if (NT_SUCCESS(Status)) 01053 { 01054 Status = NtQueryKey(hkeyFonts, 01055 KeyFullInformation, 01056 &KeyInfoFonts, 01057 sizeof(KeyInfoFonts), 01058 &dwReturnLength); 01059 01060 if (NT_SUCCESS(Status) && KeyInfoFonts.Values) 01061 { 01062 UserAssert(!(KeyInfoFonts.ClassLength | KeyInfoFonts.SubKeys | 01063 KeyInfoFonts.MaxNameLen | KeyInfoFonts.MaxClassLen)); 01064 01065 cjMaxValueNameFonts = DWORDALIGN(KeyInfoFonts.MaxValueNameLen + sizeof(WCHAR)); 01066 KeyInfoFonts.MaxValueDataLen = DWORDALIGN(KeyInfoFonts.MaxValueDataLen); 01067 cjData = cjMaxValueNameFonts + KeyInfoFonts.MaxValueDataLen; 01068 01069 // Alloc buffer big enough to hold the longest Name and Value 01070 if (KeyValueInfo = UserLocalAlloc(0, sizeof(*KeyValueInfo) + cjData)) 01071 { 01072 // Enum the "Type1 Fonts" key 01073 for (iFontT1 = 0; iFontT1 < KeyInfoType1.Values; iFontT1++) 01074 { 01075 RtlZeroMemory(KeyValueBasicInfo->Name, cjMaxValueNameT1); 01076 Status = NtEnumerateValueKey( 01077 hkeyType1, 01078 iFontT1, 01079 KeyValueBasicInformation, 01080 KeyValueBasicInfo, 01081 sizeof(*KeyValueBasicInfo) + cjMaxValueNameT1, 01082 &dwReturnLength); 01083 01084 if (NT_SUCCESS(Status)) 01085 { 01086 UserAssert(KeyValueBasicInfo->NameLength <= KeyInfoType1.MaxValueNameLen); 01087 UserAssert(KeyValueBasicInfo->Type == REG_MULTI_SZ); 01088 01089 // For each Type1 font, check to see whether 01090 // there is corresponding converted TTF 01091 // Delete the TTF file and reg entry if any 01092 01093 bRet = bCheckAndDeleteTTF(hkeyFonts, &KeyInfoFonts, KeyValueInfo, 01094 KeyValueBasicInfo, cjData); 01095 if (!bRet) 01096 { 01097 bError = TRUE; 01098 } 01099 } 01100 } 01101 UserLocalFree(KeyValueInfo); 01102 // no type1 fonts installed 01103 if (KeyInfoType1.Values == 0) 01104 { 01105 bRet = TRUE; 01106 } 01107 } 01108 } 01109 NtClose(hkeyFonts); 01110 } // NtOpenKey (hkeyFonts) 01111 UserLocalFree(KeyValueBasicInfo); 01112 } 01113 } // NtQueryKey (hkeyType1) 01114 NtClose(hkeyType1); 01115 } 01116 01117 return (bRet && !bError); 01118 } 01119 01120 01121 /***********************Public*Routine******************************\ 01122 * 01123 * VOID vCleanConvertedTTFs() 01124 * 01125 * Delete the converted TTFs and clean the registry if there is any 01126 * TTFs generated from Type1 fonts. 01127 * 01128 * History: 01129 * 29-Jan-1998 -by- Xudong Wu [TessieW] 01130 * Wrote it. 01131 \*******************************************************************/ 01132 VOID vCleanConvertedTTFs() 01133 { 01134 BOOL bNeedUpgrade = FALSE; 01135 UNICODE_STRING UnicodeString; 01136 OBJECT_ATTRIBUTES ObjA; 01137 DWORD dwReturnLength; 01138 NTSTATUS Status; 01139 HKEY hkeyUpgradeType1 = NULL; 01140 01141 struct { 01142 KEY_VALUE_PARTIAL_INFORMATION; 01143 LARGE_INTEGER; 01144 } UpgradeValueInfo; 01145 DWORD UpgradeValue = 0; 01146 01147 RtlInitUnicodeString(&UnicodeString, pwszUpdType1Key); 01148 InitializeObjectAttributes(&ObjA, 01149 &UnicodeString, 01150 OBJ_CASE_INSENSITIVE, 01151 NULL, 01152 NULL); 01153 01154 Status = NtOpenKey(&hkeyUpgradeType1, 01155 KEY_READ | KEY_WRITE, 01156 &ObjA); 01157 01158 if (!NT_SUCCESS(Status)) 01159 { 01160 // Key doesn't exist, run for the first time 01161 // Create the key, open it for writing 01162 01163 DWORD dwDisposition; 01164 01165 Status = NtCreateKey(&hkeyUpgradeType1, 01166 KEY_WRITE, 01167 &ObjA, 01168 0, 01169 NULL, 01170 REG_OPTION_NON_VOLATILE, 01171 &dwDisposition); 01172 if (NT_SUCCESS(Status)) 01173 { 01174 bNeedUpgrade = TRUE; 01175 } 01176 } 01177 else 01178 { 01179 RtlInitUnicodeString(&UnicodeString, UPGRADED_TYPE1); 01180 Status = NtQueryValueKey(hkeyUpgradeType1, 01181 &UnicodeString, 01182 KeyValuePartialInformation, 01183 &UpgradeValueInfo, 01184 sizeof(UpgradeValueInfo), 01185 &dwReturnLength); 01186 01187 if (NT_SUCCESS(Status)) 01188 { 01189 UserAssert(UpgradeValueInfo.Type == REG_DWORD); 01190 UserAssert(UpgradeValueInfo.DataLength == sizeof(UpgradeValue)); 01191 RtlCopyMemory(&UpgradeValue, &UpgradeValueInfo.Data, sizeof(UpgradeValue)); 01192 01193 // Done if the value is non-zero. 01194 if (UpgradeValue == 0) 01195 { 01196 bNeedUpgrade = TRUE; 01197 } 01198 } 01199 } 01200 01201 if (bNeedUpgrade) 01202 { 01203 if (bCleanConvertedTTFs()) 01204 { 01205 UpgradeValue = 1; 01206 } 01207 01208 RtlInitUnicodeString(&UnicodeString, UPGRADED_TYPE1); 01209 Status = NtSetValueKey(hkeyUpgradeType1, 01210 &UnicodeString, 01211 0, 01212 REG_DWORD, 01213 &UpgradeValue, 01214 sizeof(UpgradeValue)); 01215 UserAssert(NT_SUCCESS(Status)); 01216 } 01217 01218 if (hkeyUpgradeType1) 01219 { 01220 NtClose(hkeyUpgradeType1); 01221 } 01222 } 01223 01224 01225 /******************************Public*Routine******************************\ 01226 * 01227 * VOID vFontSweep() 01228 * 01229 * Effects: The main routine, calls vSweepFonts to sweep "regular" fonts 01230 * and then to sweep type 1 fonts 01231 * 01232 * History: 01233 * 20-Nov-1995 -by- Bodin Dresevic [BodinD] 01234 * Wrote it. 01235 \**************************************************************************/ 01236 01237 VOID vFontSweep() 01238 { 01239 // check if shared windows directory installation: 01240 01241 gbWin31Upgrade = bCheckIfDualBootingWithWin31(); 01242 01243 // before we sweep the files to the Fonts directory, 01244 // check whether the 'converted' ttf's have been rmoved 01245 01246 vCleanConvertedTTFs(); 01247 01248 // sweep fonts in the [Fonts] key 01249 01250 vSweepFonts(pwszFontsKey, pwszSweepKey, vProcessFontEntry, FALSE); 01251 01252 // now sweep type 1 fonts, if any 01253 01254 vSweepFonts(pwszType1Key, pwszSweepType1Key, vProcessType1FontEntry, FALSE); 01255 01256 // one of the two routines above may have initialized %windir%\system 01257 // and %windir%\fonts directories. Free the memory associated with this 01258 01259 if (gpwcSystemDir) 01260 { 01261 LocalFree(gpwcSystemDir); 01262 gpwcSystemDir = NULL; 01263 } 01264 01265 } 01266 01267 01268 /******************************Public*Routine******************************\ 01269 * 01270 * VOID vLoadLocal/RemoteT1Fonts() 01271 * 01272 * History: 01273 * 30-Apr-1996 -by- Bodin Dresevic [BodinD] 01274 * Wrote it. 01275 \**************************************************************************/ 01276 01277 VOID vLoadT1Fonts(PFNENTRY pfnProcessFontEntry) 01278 { 01279 01280 if (bLoadableFontDrivers()) 01281 { 01282 #if DBGSWEEP 01283 DbgPrint("vLoadT1Fonts(0x%lx) was called\n", pfnProcessFontEntry); 01284 #endif 01285 // now enum and add remote type1 fonts if any 01286 01287 vSweepFonts(pwszType1Key, pwszSweepType1Key, pfnProcessFontEntry, TRUE); 01288 01289 // if the routines above initialized %windir%\system 01290 // and %windir%\fonts directories. Free the memory associated with this 01291 01292 if (gpwcSystemDir) 01293 { 01294 LocalFree(gpwcSystemDir); 01295 gpwcSystemDir = NULL; 01296 } 01297 } 01298 } 01299 01300 VOID vLoadLocalT1Fonts() 01301 { 01302 vLoadT1Fonts(vAddLocalType1Font); 01303 } 01304 01305 VOID vLoadRemoteT1Fonts() 01306 { 01307 vLoadT1Fonts(vAddRemoteType1Font); 01308 }

Generated on Sat May 15 19:40:03 2004 for test by doxygen 1.3.7