Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1302 lines
44 KiB

/******************************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 <setupbat.h> // 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);
}