/******************************Module*Header*******************************\ * Module Name: fntsweep.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * Author: Bodin Dresevic [BodinD] * * Copyright (c) 1990 Microsoft Corporation * * This file contains font sweeper related stuff. * On the boot of ths system, i.e. initialization of userk, the * [Fonts] section of win.ini is checked to * find out if any new fonts have been added by any font installers. * If third party installers have installed fonts in the system directory * those are copied to fonts directory. Any fot entries are replaced * by appropriate *.ttf entries, any fot files are deleted if they were * ever installed. * \**************************************************************************/ #include "precomp.h" #pragma hdrstop #include // in sdkinc CONST WCHAR pwszType1Key[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Type 1 Installer\\Type 1 Fonts"; CONST WCHAR pwszSweepType1Key[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Type 1 Installer\\LastType1Sweep"; CONST WCHAR pwszUpdType1Key[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Type 1 Installer\\Upgraded Type1"; CONST WCHAR pwszFontsKey[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"; CONST WCHAR pwszSweepKey[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\LastFontSweep"; CONST WCHAR pwszFontDrivers[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Font Drivers"; #define LAST_SWEEP_TIME L"LastSweepTime" #define UPGRADED_TYPE1 L"UpgradedType1" #define DWORDALIGN(X) (((X) + 3) & ~3) WCHAR *gpwcSystemDir; WCHAR *gpwcFontsDir; BOOL gbWin31Upgrade; BOOL bCheckIfDualBootingWithWin31() { WCHAR Buffer[32]; WCHAR awcWindowsDir[MAX_PATH]; DWORD dwRet; UINT cwchWinPath; awcWindowsDir[0] = L'\0'; // prefix:make sure to zero terminated cwchWinPath = GetSystemWindowsDirectoryW(awcWindowsDir, MAX_PATH); if ((cwchWinPath == 0) || (cwchWinPath > MAX_PATH)) return FALSE; // the cwchWinPath value does not include the terminating zero if (awcWindowsDir[cwchWinPath - 1] == L'\\') { cwchWinPath -= 1; } awcWindowsDir[cwchWinPath] = L'\0'; // make sure to zero terminated lstrcatW(awcWindowsDir, L"\\system32\\"); lstrcatW(awcWindowsDir, WINNT_GUI_FILE_W); dwRet = GetPrivateProfileStringW( WINNT_DATA_W, WINNT_D_WIN31UPGRADE_W, WINNT_A_NO_W, Buffer, sizeof(Buffer)/sizeof(WCHAR), awcWindowsDir ); #if DBGSWEEP DbgPrint("\n dwRet = %ld, win31upgrade = %ws\n\n", dwRet, Buffer); #endif return (BOOL)(dwRet ? (!lstrcmpiW(Buffer,WINNT_A_YES)) : 0); } /******************************Public*Routine******************************\ * * VOID vNullTermWideString (WCHAR *pwcDest, WCHAR *pwcSrc, ULONG ulLength) * * Given pwcSrc, which is not necessarily null-terminated, copy ulLength characters * the into pwcDest and place a null character after it. * * History: * 03-Feb-99 -by- Donald Chinn [dchinn] * Wrote it. \**************************************************************************/ VOID vNullTermWideString (WCHAR *pwcDest, WCHAR *pwcSrc, ULONG ulLength) { ULONG index; for (index = 0; index < ulLength; index++) { *pwcDest++ = *pwcSrc++; } *pwcDest = '\0'; } /******************************Public*Routine******************************\ * * BOOL bCheckFontEntry(WCHAR *pwcName, WCHAR *pwcExtension) * * This function assumes that both pwcName and pwcExtension are null-terminated. * * History: * 25-Oct-1995 -by- Bodin Dresevic [BodinD] * Wrote it. \**************************************************************************/ BOOL bCheckFontEntry(WCHAR *pwcName, WCHAR *pwcExtension) { BOOL bRet = FALSE; LONG cwc = (LONG)wcslen(pwcName) - (LONG)wcslen(pwcExtension); if (cwc > 0) { bRet = !_wcsicmp(&pwcName[cwc], pwcExtension); } return bRet; } /******************************Public*Routine******************************\ * Process win.ini line * * History: * 24-Oct-1995 -by- Bodin Dresevic [BodinD] * Wrote it. \**************************************************************************/ #define EXT_TRUETYPE L"(TrueType)" #define EXT_FOT L".FOT" VOID vProcessFontEntry( HKEY hkey, WCHAR *pwcValueName, ULONG ulValueNameLength, WCHAR *pwcFileName, ULONG ulFileNameLength ) { NTSTATUS Status; UNICODE_STRING UnicodeString; BOOL bFot = FALSE; WCHAR awcTTF[MAX_PATH]; WCHAR awcTmpBuf[MAX_PATH]; WCHAR *pwcTTF; FLONG fl, fl2; FLONG flEmbed; DWORD dwPidTid; WCHAR awcValueName[MAX_PATH]; // null-terminated pwcValueName WCHAR awcFileName[MAX_PATH]; // null-terminated pwcFileName // Make sure the ValueName is null-terminated ulValueNameLength = min(MAX_PATH - 1, ulValueNameLength); vNullTermWideString (awcValueName, pwcValueName, ulValueNameLength); // Make sure the FileName is null-terminated ulFileNameLength = min(MAX_PATH - 1, ulFileNameLength); vNullTermWideString (awcFileName, pwcFileName, ulFileNameLength); if (bCheckFontEntry(awcValueName, EXT_TRUETYPE)) { // This is a tt entry, either .fot or .ttf if (bFot = bCheckFontEntry(awcFileName, EXT_FOT)) { // this is an .fot entry, must find ttf pointed to by .fot, // but first must get the full path to the .fot file // for cGetTTFFromFOT routine expects it. We will also need // the full path to the .fot file so that we can delete it // eventually. if (bMakePathNameW(awcTmpBuf, awcFileName, NULL, &fl2)) { if (cGetTTFFromFOT(awcTmpBuf, MAX_PATH, awcTTF, &fl, &flEmbed, &dwPidTid, TRUE) && !(fl & FONT_ISNOT_FOT)) { // fix the entry to point to .ttf file. At this point // awcTTF points to the FULL path to the .ttf file. // However, we will only need a relative path to the // .ttf file, when the .ttf file is in the %windir%\system // or %windir%\fonts directories. In case the file is in the // %windir%\system directory we shall copy it to %windir%\fonts // directory and write the relative path to the registry. // In case it is in the %windir%\fonts directory we do not // touch the file and also just write the relative path to the // registry. In any other case we just write the full .ttf // path to the registry. // first delete the .fot file, it is no longer needed if (bFot && !gbWin31Upgrade) { UserVerify(DeleteFileW(awcTmpBuf)); } if ((fl & (FONT_IN_FONTS_DIR | FONT_IN_SYSTEM_DIR)) == 0) { // if ttf file is not in either the system or the fonts // directories, just write the full path to the registry pwcTTF = awcTTF; } else { // find the bare file part, this is what will be written // in the registry pwcTTF = &awcTTF[wcslen(awcTTF) - 1]; while ((pwcTTF >= awcTTF) && (*pwcTTF != L'\\') && (*pwcTTF != L':')) pwcTTF--; pwcTTF++; if (fl & FONT_IN_SYSTEM_DIR) { // need to move the ttf to fonts dir, can reuse the // buffer on the stack: wcscpy(awcTmpBuf, gpwcFontsDir); lstrcatW(awcTmpBuf, L"\\"); lstrcatW(awcTmpBuf, pwcTTF); // note that MoveFile should succeed, for if there was // a ttf file of the same file name in %windir%\fonts dir // we would not have been in this code path. RIPMSG2(RIP_VERBOSE, "Moving %ws to %ws", awcTTF, awcTmpBuf); if (!gbWin31Upgrade) { UserVerify(MoveFileW(awcTTF, awcTmpBuf)); } else { // Boolean value TRUE means "do not copy if target exists" UserVerify(CopyFileW(awcTTF, awcTmpBuf, TRUE)); } } } RIPMSG2(RIP_VERBOSE, "writing to the registry:\n %ws=%ws", pwcValueName, pwcTTF); RtlInitUnicodeString(&UnicodeString, awcValueName); Status = NtSetValueKey(hkey, &UnicodeString, 0, REG_SZ, pwcTTF, (wcslen(pwcTTF)+1) * sizeof(WCHAR)); UserAssert(NT_SUCCESS(Status)); } #if DBG else { RIPMSG1(RIP_WARNING, "Could not locate ttf pointed to by %ws", awcTmpBuf); } #endif } #if DBG else { RIPMSG1(RIP_WARNING, "Could not locate .fot: %ws", awcFileName); } #endif } } else { // not a true type case. little bit simpler, // we will use awcTTF buffer for the full path name, and pwcTTF // as local variable even though these TTF names are misnomer // for these are not tt fonts if (bMakePathNameW(awcTTF, awcFileName,NULL, &fl)) { // At this point // awcTTF points to the FULL path to the font file. // If the font is in the system subdirectory we will just move it // to the fonts subdirectory. If the path in the registry is relative // we will leave it alone. If it is an absolute path, we shall // fix the registry entry to only contain relative path, the // absolute path is redundant. if (fl & (FONT_IN_SYSTEM_DIR | FONT_IN_FONTS_DIR)) { // find the bare file part, this is what will be written // in the registry pwcTTF = &awcTTF[wcslen(awcTTF) - 1]; while ((pwcTTF >= awcTTF) && (*pwcTTF != L'\\') && (*pwcTTF != L':')) pwcTTF--; pwcTTF++; if (fl & FONT_IN_SYSTEM_DIR) { // need to move the font to fonts dir, can reuse the // buffer on the stack to build the full destination path wcscpy(awcTmpBuf, gpwcFontsDir); lstrcatW(awcTmpBuf, L"\\"); lstrcatW(awcTmpBuf, pwcTTF); // note that MoveFile should succeed, for if there was // a font file of the same file name in %windir%\fonts dir // we would not have been in this code path. The only time // it could fail if the path in the registry is absolute. RIPMSG2(RIP_VERBOSE, "Moving %ws to %ws", awcTTF, awcTmpBuf); if (!gbWin31Upgrade) { UserVerify(MoveFileW(awcTTF, awcTmpBuf)); } else { // Boolean value TRUE means "do not copy if target exists" UserVerify(CopyFileW(awcTTF, awcTmpBuf, TRUE)); } } // check if the file path in the registry is absolute, // if so make it relative: if (!(fl & FONT_RELATIVE_PATH)) { RIPMSG2(RIP_VERBOSE, "writing to the registry:\n %ws=%ws", pwcValueName, pwcTTF); RtlInitUnicodeString(&UnicodeString, awcValueName); Status = NtSetValueKey(hkey, &UnicodeString, 0, REG_SZ, pwcTTF, (wcslen(pwcTTF)+1) * sizeof(WCHAR)); UserAssert(NT_SUCCESS(Status)); } } } } } /******************************Public*Routine******************************\ * * VOID vMoveFileFromSystemToFontsDir(WCHAR *pwcFile) * * History: * 24-Apr-1996 -by- Bodin Dresevic [BodinD] * Wrote it. \**************************************************************************/ VOID vMoveFileFromSystemToFontsDir(WCHAR *pwcFile) { WCHAR awcTmpBuf[MAX_PATH]; WCHAR awcTmp[MAX_PATH]; FLONG fl; WCHAR *pwcTmp; #if DBG BOOL bOk; #endif if (bMakePathNameW(awcTmp, pwcFile,NULL, &fl)) { // If the font is in the system subdirectory we will just move it // to the fonts subdirectory. The path in the registry is relative // and we will leave it alone. if ( (fl & (FONT_IN_SYSTEM_DIR | FONT_RELATIVE_PATH)) == (FONT_IN_SYSTEM_DIR | FONT_RELATIVE_PATH) ) { // find the bare file part, this is what will be written // in the registry pwcTmp = &awcTmp[wcslen(awcTmp) - 1]; while ((pwcTmp >= awcTmp) && (*pwcTmp != L'\\') && (*pwcTmp != L':')) pwcTmp--; if (pwcTmp > awcTmp) pwcTmp++; // need to move the font to fonts dir, can reuse the // buffer on the stack to build the full destination path wcscpy(awcTmpBuf, gpwcFontsDir); lstrcatW(awcTmpBuf, L"\\"); lstrcatW(awcTmpBuf, pwcTmp); // note that MoveFile should succeed, for if there was // a font file of the same file name in %windir%\fonts dir // we would not have been in this code path. #if DBG bOk = #endif MoveFileW(awcTmp, awcTmpBuf); RIPMSG3(RIP_VERBOSE, "move %ws to %ws %s", awcTmp, awcTmpBuf, (bOk) ? "succeeded" : "failed"); } #if DBG else { RIPMSG2(RIP_WARNING, "File %ws not in system directory, fl = 0x%lx\n", awcTmp, fl); } #endif } #if DBG else { RIPMSG1(RIP_WARNING, "Could not locate %ws", pwcFile); } #endif } /******************************Public*Routine******************************\ * * VOID vProcessType1FontEntry * * * Effects: All this routine does is to check if pwcPFM and pwcPFB pointed to * by pwcValueData point to files in the %windir%system directory * and if so copies these type 1 files to %windir%\fonts directory * * History: * 20-Nov-1995 -by- Bodin Dresevic [BodinD] * Wrote it. \**************************************************************************/ VOID vProcessType1FontEntry( HKEY hkey, WCHAR *pwcValueName, ULONG ulValueNameLength, WCHAR *pwcValueData, ULONG ulValueDataLength ) { WCHAR *pwcPFM, *pwcPFB; UNREFERENCED_PARAMETER(hkey); UNREFERENCED_PARAMETER(pwcValueName); UNREFERENCED_PARAMETER(ulValueNameLength); UNREFERENCED_PARAMETER(ulValueDataLength); // skip unused boolean value in this multi reg_sz string: if ((pwcValueData[0] != L'\0') && (pwcValueData[1] == L'\0')) { pwcPFM = &pwcValueData[2]; pwcPFB = pwcPFM + wcslen(pwcPFM) + 1; // add 1 for zero separator vMoveFileFromSystemToFontsDir(pwcPFM); vMoveFileFromSystemToFontsDir(pwcPFB); } } /******************************Public*Routine******************************\ * * VOID vAddRemote/LocalType1Font * * History: * 25-Apr-1996 -by- Bodin Dresevic [BodinD] * Wrote it. \**************************************************************************/ VOID vAddType1Font( WCHAR *pwcValueData, DWORD dwFlags ) { WCHAR *pwcPFM, *pwcPFB, *pwcMMM; #if DBG int iRet; #endif // skip unused boolean value in this multi reg_sz string: if ((pwcValueData[0] != L'\0') && (pwcValueData[1] == L'\0')) { pwcPFM = &pwcValueData[2]; pwcPFB = pwcPFM + wcslen(pwcPFM) + 1; // add 1 for zero separator pwcMMM = pwcPFB + wcslen(pwcPFB) + 1; // may of may not be there. // replace space by separator and call addfontresourcew pwcPFB[-1] = PATH_SEPARATOR; // if this is a multiple master font, need one more separator: if (pwcMMM[0] != L'\0') pwcMMM[-1] = PATH_SEPARATOR; #if DBG iRet = #endif GdiAddFontResourceW(pwcPFM, dwFlags, NULL); #if DBGSWEEP DbgPrint("%ld = GdiAddFontResourceW(%ws, 0x%lx);\n", iRet, pwcPFM, dwFlags); #endif } } VOID vAddRemoteType1Font( HKEY hkey, WCHAR *pwcValueName, ULONG ulValueNameLength, WCHAR *pwcValueData, ULONG ulValueDataLength ) { UNREFERENCED_PARAMETER(hkey); UNREFERENCED_PARAMETER(pwcValueName); UNREFERENCED_PARAMETER(ulValueNameLength); UNREFERENCED_PARAMETER(ulValueDataLength); vAddType1Font(pwcValueData, AFRW_ADD_REMOTE_FONT); } VOID vAddLocalType1Font( HKEY hkey, WCHAR *pwcValueName, ULONG ulValueNameLength, WCHAR *pwcValueData, ULONG ulValueDataLength ) { UNREFERENCED_PARAMETER(hkey); UNREFERENCED_PARAMETER(pwcValueName); UNREFERENCED_PARAMETER(ulValueNameLength); UNREFERENCED_PARAMETER(ulValueDataLength); vAddType1Font(pwcValueData, AFRW_ADD_LOCAL_FONT); } typedef VOID (*PFNENTRY)(HKEY hkey, WCHAR *, ULONG, WCHAR *, ULONG); /******************************Public*Routine******************************\ * * VOID vFontSweep() * * This is the main routine in this module. Checks if the fonts need to be * "sweeped" and does so if need be. * * History: * 27-Oct-1995 -by- Bodin Dresevic [BodinD] * Wrote it. \**************************************************************************/ VOID vSweepFonts( PCWSTR pwszFontListKey, // font list key PCWSTR pwszFontSweepKey, // the corresponding sweep key PFNENTRY pfnProcessFontEntry, // function that processes individual entry BOOL bForceEnum // force enumeration ) { DWORD cjMaxValueName; DWORD iFont; NTSTATUS Status; UNICODE_STRING UnicodeString; OBJECT_ATTRIBUTES ObjA; KEY_FULL_INFORMATION KeyInfo; DWORD dwReturnLength; PKEY_VALUE_FULL_INFORMATION KeyValueInfo; BYTE *pjValueData; HKEY hkey = NULL; struct { KEY_VALUE_PARTIAL_INFORMATION; LARGE_INTEGER; } SweepValueInfo; LARGE_INTEGER LastSweepTime; BOOL bSweep = FALSE; HKEY hkeyLastSweep; DWORD cjData; if (!bForceEnum) { // first check if anything needs to be done, that is, if anybody // touched the [Fonts] section of the registry since the last time we sweeped it. // get the time of the last sweep of the fonts section of the registry: RtlInitUnicodeString(&UnicodeString, pwszFontSweepKey); InitializeObjectAttributes(&ObjA, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenKey(&hkeyLastSweep, KEY_READ | KEY_WRITE, &ObjA); if (!NT_SUCCESS(Status)) { DWORD dwDisposition; // We are running for the first time, we need to create the key // for it does not exist as yet at this time bSweep = TRUE; // Create the key, open it for writing, since we will have to // store the time when the [Fonts] section of the registry was last swept Status = NtCreateKey(&hkeyLastSweep, KEY_WRITE, &ObjA, 0, NULL, REG_OPTION_NON_VOLATILE, &dwDisposition); if (!NT_SUCCESS(Status)) return; } else { RtlInitUnicodeString(&UnicodeString, LAST_SWEEP_TIME); Status = NtQueryValueKey(hkeyLastSweep, &UnicodeString, KeyValuePartialInformation, &SweepValueInfo, sizeof(SweepValueInfo), &dwReturnLength); if (!NT_SUCCESS(Status)) { bSweep = TRUE; // force sweep, something is suspicious } else { UserAssert(SweepValueInfo.Type == REG_BINARY); UserAssert(SweepValueInfo.DataLength == sizeof(LastSweepTime)); RtlCopyMemory(&LastSweepTime, &SweepValueInfo.Data, sizeof(LastSweepTime)); } } } else { bSweep = TRUE; } // now open the Fonts key and get the time the key last changed: // now get the time of the time of the last change is bigger than // the time of last sweep, must sweep again: RtlInitUnicodeString(&UnicodeString, pwszFontListKey); InitializeObjectAttributes(&ObjA, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenKey(&hkey, KEY_READ | KEY_WRITE, &ObjA); if (NT_SUCCESS(Status)) { // get the number of entries in the [Fonts] section Status = NtQueryKey(hkey, KeyFullInformation, &KeyInfo, sizeof(KeyInfo), &dwReturnLength); if (NT_SUCCESS(Status) && KeyInfo.Values) { UserAssert(!(KeyInfo.ClassLength | KeyInfo.SubKeys | KeyInfo.MaxNameLen | KeyInfo.MaxClassLen)); // now let us check if the fonts need to be sweeped. This is the case // when the registry last write time is bigger than the last sweep time if (!bSweep) { if (KeyInfo.LastWriteTime.QuadPart != LastSweepTime.QuadPart ) { bSweep = TRUE; } } // init system dir, we will need it: if (bSweep && bInitSystemAndFontsDirectoriesW(&gpwcSystemDir, &gpwcFontsDir)) { // alloc buffer big enough to hold the biggest ValueName and ValueData cjMaxValueName = DWORDALIGN(KeyInfo.MaxValueNameLen + sizeof(WCHAR)); // allocate temporary buffer into which we are going to pull the contents // of the registry KeyInfo.MaxValueDataLen = DWORDALIGN(KeyInfo.MaxValueDataLen); cjData = cjMaxValueName + // space for the value name KeyInfo.MaxValueDataLen ; // space for the value data if (KeyValueInfo = UserLocalAlloc(0, sizeof(*KeyValueInfo) + cjData)) { for (iFont = 0; iFont < KeyInfo.Values; iFont++) { Status = NtEnumerateValueKey( hkey, iFont, KeyValueFullInformation, KeyValueInfo, sizeof(*KeyValueInfo) + cjData, &dwReturnLength); if (NT_SUCCESS(Status)) { UserAssert(KeyValueInfo->NameLength <= KeyInfo.MaxValueNameLen); UserAssert(KeyValueInfo->DataLength <= KeyInfo.MaxValueDataLen); UserAssert((KeyValueInfo->Type == REG_SZ) || (KeyValueInfo->Type == REG_MULTI_SZ)); // data goes into the second half of the buffer pjValueData = (BYTE *)KeyValueInfo + KeyValueInfo->DataOffset; // see if the font files are where the registry claims they are. // It is unfortunate we have to do this because SearchPathW // is slow because it touches the disk. (*pfnProcessFontEntry)(hkey, KeyValueInfo->Name, KeyValueInfo->NameLength / sizeof(WCHAR), (WCHAR *)pjValueData, KeyValueInfo->DataLength / sizeof(WCHAR)); } } if (!bForceEnum) { // now that the sweep is completed, get the last write time // and store it as the LastSweepTime at the appropriate location Status = NtQueryKey(hkey, KeyFullInformation, &KeyInfo, sizeof(KeyInfo), &dwReturnLength); UserAssert(NT_SUCCESS(Status)); // now remember the result RtlInitUnicodeString(&UnicodeString, LAST_SWEEP_TIME); Status = NtSetValueKey(hkeyLastSweep, &UnicodeString, 0, REG_BINARY, &KeyInfo.LastWriteTime, sizeof(KeyInfo.LastWriteTime)); UserAssert(NT_SUCCESS(Status)); } // free the memory that will be no longer needed UserLocalFree(KeyValueInfo); } } } NtClose(hkey); } if (!bForceEnum) { NtClose(hkeyLastSweep); } } /******************************Public*Routine******************************\ * * BOOL bLoadableFontDrivers() * * open the font drivers key and check if there are any entries, if so * return true. If that is the case we will call AddFontResourceW on * Type 1 fonts at boot time, right after user had logged on * PostScript printer drivers are not initialized at this time yet, * it is safe to do it at this time. * Effects: * * Warnings: * * History: * 24-Apr-1996 -by- Bodin Dresevic [BodinD] * Wrote it. \**************************************************************************/ BOOL bLoadableFontDrivers() { NTSTATUS Status; UNICODE_STRING UnicodeString; OBJECT_ATTRIBUTES ObjA; KEY_FULL_INFORMATION KeyInfo; DWORD dwReturnLength; HKEY hkey = NULL; BOOL bRet = FALSE; // open the font drivers key and check if there are any entries, if so // return true. If that is the case we will call AddFontResourceW on // Type 1 fonts at boot time, right after user had logged on // PostScript printer drivers are not initialized at this time yet, // it is safe to do it at this time. RtlInitUnicodeString(&UnicodeString, pwszFontDrivers); InitializeObjectAttributes(&ObjA, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenKey(&hkey, KEY_READ, &ObjA); if (NT_SUCCESS(Status)) { // get the number of entries in the [Fonts] section Status = NtQueryKey(hkey, KeyFullInformation, &KeyInfo, sizeof(KeyInfo), &dwReturnLength); if (NT_SUCCESS(Status) && KeyInfo.Values) { UserAssert(!(KeyInfo.ClassLength | KeyInfo.SubKeys | KeyInfo.MaxNameLen | KeyInfo.MaxClassLen)); // externally loadable drivers are present, force sweep bRet = TRUE; } NtClose(hkey); } return bRet; } /***********************Public*Routine******************************\ * * BOOL bCheckAndDeleteTTF() * * Checks whether there is a converted TTF corresponding to * a Type1 font. Delete the TTF file and the reg entry if there is. * * History: * 29-Jan-1998 -by- Xudong Wu [TessieW] * Wrote it. \*******************************************************************/ BOOL bCheckAndDeleteTTF ( HKEY hkey, PKEY_FULL_INFORMATION pKeyInfo, PKEY_VALUE_FULL_INFORMATION KeyValueInfo, PKEY_VALUE_BASIC_INFORMATION KeyValueBasicInfo, DWORD cjData ) { NTSTATUS Status; UNICODE_STRING UnicodeString; DWORD dwReturnLength; ULONG iFont; WCHAR awcTmp[MAX_PATH], *pFontName, *pType1Name, *pwcFile; BOOL bDelTTFfile, bRet = TRUE; FLONG fl; WCHAR awcType1Name[MAX_PATH]; // null-terminated pType1Name WCHAR awcFontName[MAX_PATH]; // null-terminated pFontName WCHAR awcFile[MAX_PATH]; // null-terminated pwcFile // pKeyInfo holds the full info on the key "Fonts" for (iFont = 0; iFont < pKeyInfo->Values; iFont++) { RtlZeroMemory(KeyValueInfo->Name, cjData); Status = NtEnumerateValueKey( hkey, iFont, KeyValueFullInformation, KeyValueInfo, sizeof(*KeyValueInfo) + cjData, &dwReturnLength); if (NT_SUCCESS(Status)) { UserAssert(KeyValueInfo->NameLength <= pKeyInfo->MaxValueNameLen); UserAssert(KeyValueInfo->DataLength <= pKeyInfo->MaxValueDataLen); UserAssert(KeyValueInfo->Type == REG_SZ); bDelTTFfile = FALSE; // Make sure we use null-terminated strings vNullTermWideString (awcType1Name, KeyValueBasicInfo->Name, KeyValueBasicInfo->NameLength / sizeof(WCHAR)); vNullTermWideString (awcFontName, KeyValueInfo->Name, KeyValueInfo->NameLength / sizeof(WCHAR)); vNullTermWideString (awcFile, (WCHAR *) ((BYTE *)KeyValueInfo + KeyValueInfo->DataOffset), KeyValueInfo->DataLength / sizeof(WCHAR)); pType1Name = awcType1Name; pFontName = awcFontName; pwcFile = awcFile; while((*pType1Name) && (*pType1Name++ == *pFontName++)) ; // if the font name match the type1 name // check whether this is a ttf font if ((*pType1Name == 0) && (*pFontName++ == L' ')) { WCHAR *pTrueType = L"(TrueType)"; while(*pTrueType && (*pTrueType++ == *pFontName++)) ; if (*pTrueType == 0) { bDelTTFfile = TRUE; } } if (bDelTTFfile) { // delete the converted TTF file if (bRet = bMakePathNameW(awcTmp, pwcFile, NULL, &fl)) { UserVerify((bRet = DeleteFileW(awcTmp))); } // remove the reg entry *pFontName = 0; RtlInitUnicodeString(&UnicodeString, awcFontName); Status = NtDeleteValueKey(hkey, (PUNICODE_STRING)&UnicodeString); // decrement the number of values under [Fonts] if (NT_SUCCESS(Status)) pKeyInfo->Values--; else bRet = FALSE; break; } } else { bRet = FALSE; break; } } return bRet; } /***********************Public*Routine**************************\ * * BOOL bCleanConvertedTTFs() * * Enumerate each entry under "Upgrade Type1" key, call * bCheckAndDeleteTTF() to remove the coverted TTFs. * * History: * 29-Jan-1998 -by- Xudong Wu [TessieW] * Wrote it. \***************************************************************/ BOOL bCleanConvertedTTFs() { UNICODE_STRING UnicodeString; OBJECT_ATTRIBUTES ObjA; NTSTATUS Status; HKEY hkeyFonts = NULL, hkeyType1 = NULL; DWORD dwReturnLength; DWORD iFontT1, cjData; DWORD cjMaxValueNameT1, cjMaxValueNameFonts; BOOL bRet = FALSE, bError = FALSE; KEY_FULL_INFORMATION KeyInfoType1, KeyInfoFonts; PKEY_VALUE_BASIC_INFORMATION KeyValueBasicInfo; PKEY_VALUE_FULL_INFORMATION KeyValueInfo; // Open and query the value from the "Type1 Fonts" key // No need to continue if not succeed or no Type1 font listed RtlInitUnicodeString(&UnicodeString, pwszType1Key); InitializeObjectAttributes(&ObjA, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenKey(&hkeyType1, KEY_READ | KEY_WRITE, &ObjA); if (NT_SUCCESS(Status)) { Status = NtQueryKey(hkeyType1, KeyFullInformation, &KeyInfoType1, sizeof(KeyInfoType1), &dwReturnLength); if (NT_SUCCESS(Status) && KeyInfoType1.Values) { UserAssert(!(KeyInfoType1.ClassLength | KeyInfoType1.SubKeys | KeyInfoType1.MaxNameLen | KeyInfoType1.MaxClassLen)); cjMaxValueNameT1 = DWORDALIGN(KeyInfoType1.MaxValueNameLen + sizeof(WCHAR)); // Alloc buffer big enough to hold the longest Name if (KeyValueBasicInfo = UserLocalAlloc(0, sizeof(*KeyValueBasicInfo) + cjMaxValueNameT1)) { RtlInitUnicodeString(&UnicodeString, pwszFontsKey); InitializeObjectAttributes(&ObjA, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenKey(&hkeyFonts, KEY_READ | KEY_WRITE, &ObjA); if (NT_SUCCESS(Status)) { Status = NtQueryKey(hkeyFonts, KeyFullInformation, &KeyInfoFonts, sizeof(KeyInfoFonts), &dwReturnLength); if (NT_SUCCESS(Status) && KeyInfoFonts.Values) { UserAssert(!(KeyInfoFonts.ClassLength | KeyInfoFonts.SubKeys | KeyInfoFonts.MaxNameLen | KeyInfoFonts.MaxClassLen)); cjMaxValueNameFonts = DWORDALIGN(KeyInfoFonts.MaxValueNameLen + sizeof(WCHAR)); KeyInfoFonts.MaxValueDataLen = DWORDALIGN(KeyInfoFonts.MaxValueDataLen); cjData = cjMaxValueNameFonts + KeyInfoFonts.MaxValueDataLen; // Alloc buffer big enough to hold the longest Name and Value if (KeyValueInfo = UserLocalAlloc(0, sizeof(*KeyValueInfo) + cjData)) { // Enum the "Type1 Fonts" key for (iFontT1 = 0; iFontT1 < KeyInfoType1.Values; iFontT1++) { RtlZeroMemory(KeyValueBasicInfo->Name, cjMaxValueNameT1); Status = NtEnumerateValueKey( hkeyType1, iFontT1, KeyValueBasicInformation, KeyValueBasicInfo, sizeof(*KeyValueBasicInfo) + cjMaxValueNameT1, &dwReturnLength); if (NT_SUCCESS(Status)) { UserAssert(KeyValueBasicInfo->NameLength <= KeyInfoType1.MaxValueNameLen); UserAssert(KeyValueBasicInfo->Type == REG_MULTI_SZ); // For each Type1 font, check to see whether // there is corresponding converted TTF // Delete the TTF file and reg entry if any bRet = bCheckAndDeleteTTF(hkeyFonts, &KeyInfoFonts, KeyValueInfo, KeyValueBasicInfo, cjData); if (!bRet) { bError = TRUE; } } } UserLocalFree(KeyValueInfo); // no type1 fonts installed if (KeyInfoType1.Values == 0) { bRet = TRUE; } } } NtClose(hkeyFonts); } // NtOpenKey (hkeyFonts) UserLocalFree(KeyValueBasicInfo); } } // NtQueryKey (hkeyType1) NtClose(hkeyType1); } return (bRet && !bError); } /***********************Public*Routine******************************\ * * VOID vCleanConvertedTTFs() * * Delete the converted TTFs and clean the registry if there is any * TTFs generated from Type1 fonts. * * History: * 29-Jan-1998 -by- Xudong Wu [TessieW] * Wrote it. \*******************************************************************/ VOID vCleanConvertedTTFs() { BOOL bNeedUpgrade = FALSE; UNICODE_STRING UnicodeString; OBJECT_ATTRIBUTES ObjA; DWORD dwReturnLength; NTSTATUS Status; HKEY hkeyUpgradeType1 = NULL; struct { KEY_VALUE_PARTIAL_INFORMATION; LARGE_INTEGER; } UpgradeValueInfo; DWORD UpgradeValue = 0; RtlInitUnicodeString(&UnicodeString, pwszUpdType1Key); InitializeObjectAttributes(&ObjA, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenKey(&hkeyUpgradeType1, KEY_READ | KEY_WRITE, &ObjA); if (!NT_SUCCESS(Status)) { // Key doesn't exist, run for the first time // Create the key, open it for writing DWORD dwDisposition; Status = NtCreateKey(&hkeyUpgradeType1, KEY_WRITE, &ObjA, 0, NULL, REG_OPTION_NON_VOLATILE, &dwDisposition); if (NT_SUCCESS(Status)) { bNeedUpgrade = TRUE; } } else { RtlInitUnicodeString(&UnicodeString, UPGRADED_TYPE1); Status = NtQueryValueKey(hkeyUpgradeType1, &UnicodeString, KeyValuePartialInformation, &UpgradeValueInfo, sizeof(UpgradeValueInfo), &dwReturnLength); if (NT_SUCCESS(Status)) { UserAssert(UpgradeValueInfo.Type == REG_DWORD); UserAssert(UpgradeValueInfo.DataLength == sizeof(UpgradeValue)); RtlCopyMemory(&UpgradeValue, &UpgradeValueInfo.Data, sizeof(UpgradeValue)); // Done if the value is non-zero. if (UpgradeValue == 0) { bNeedUpgrade = TRUE; } } } if (bNeedUpgrade) { if (bCleanConvertedTTFs()) { UpgradeValue = 1; } RtlInitUnicodeString(&UnicodeString, UPGRADED_TYPE1); Status = NtSetValueKey(hkeyUpgradeType1, &UnicodeString, 0, REG_DWORD, &UpgradeValue, sizeof(UpgradeValue)); UserAssert(NT_SUCCESS(Status)); } if (hkeyUpgradeType1) { NtClose(hkeyUpgradeType1); } } /******************************Public*Routine******************************\ * * VOID vFontSweep() * * Effects: The main routine, calls vSweepFonts to sweep "regular" fonts * and then to sweep type 1 fonts * * History: * 20-Nov-1995 -by- Bodin Dresevic [BodinD] * Wrote it. \**************************************************************************/ VOID vFontSweep( VOID) { /* * Check if shared windows directory installation. */ gbWin31Upgrade = bCheckIfDualBootingWithWin31(); /* * Before we sweep the files to the Fonts directory, check whether the * 'converted' TTFs have been removed. */ vCleanConvertedTTFs(); /* * Sweep fonts in the [Fonts] key. */ vSweepFonts(pwszFontsKey, pwszSweepKey, vProcessFontEntry, FALSE); /* * Now sweep type 1 fonts, if any. */ vSweepFonts(pwszType1Key, pwszSweepType1Key, vProcessType1FontEntry, FALSE); if (gpwcSystemDir) { UserLocalFree(gpwcSystemDir); gpwcSystemDir = NULL; } } /******************************Public*Routine******************************\ * vLoadLT1Fonts * * History: * 30-Apr-1996 -by- Bodin Dresevic [BodinD] * Wrote it. \**************************************************************************/ VOID vLoadT1Fonts( PFNENTRY pfnProcessFontEntry) { if (bLoadableFontDrivers()) { /* * Now enum and add remote type1 fonts if any. */ vSweepFonts(pwszType1Key, pwszSweepType1Key, pfnProcessFontEntry, TRUE); if (gpwcSystemDir) { UserLocalFree(gpwcSystemDir); gpwcSystemDir = NULL; } } } VOID vLoadLocalT1Fonts( VOID) { vLoadT1Fonts(vAddLocalType1Font); } VOID vLoadRemoteT1Fonts( VOID) { vLoadT1Fonts(vAddRemoteType1Font); }