697 lines
17 KiB
C
697 lines
17 KiB
C
|
||
/*
|
||
|
||
Copyright (c) 1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
psqfont.c
|
||
|
||
Abstract:
|
||
|
||
This DLL is responsible for the FONTLIST management of the PSTODIB
|
||
component of MACPRINT. It will enumerate the fontsubtitution table
|
||
in the registry and build a composite font list that maps PostScript
|
||
font names to TrueType TTF files installed on the current system. This
|
||
list is built from scratch, by enumerating the postscript to true
|
||
type list and checking to see which fonts are actually installed in
|
||
the NT font list.
|
||
|
||
|
||
Author:
|
||
|
||
James Bratsanos <v-jimbr@microsoft.com or mcrafts!jamesb>
|
||
|
||
|
||
Revision History:
|
||
22 Nov 1992 Initial Version
|
||
14 Jun 1993 Took out code to put new font list into registry
|
||
|
||
Notes: Tab stop: 4
|
||
--*/
|
||
|
||
#include <windows.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include "psqfont.h"
|
||
#include "psqfontp.h"
|
||
#include "psqdefp.h"
|
||
|
||
|
||
//GLOBALS
|
||
HANDLE hInst; // Global handle to our instance
|
||
|
||
|
||
/* This entry point is called on DLL initialisation.
|
||
* We need to know the module handle so we can load resources.
|
||
*/
|
||
BOOL PsQDLLInit(
|
||
IN PVOID hmod,
|
||
IN DWORD Reason,
|
||
IN PCONTEXT pctx OPTIONAL)
|
||
{
|
||
DBG_UNREFERENCED_PARAMETER(pctx);
|
||
|
||
if (Reason == DLL_PROCESS_ATTACH)
|
||
{
|
||
hInst = hmod;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
|
||
LPTSTR LocPsAllocAndCopy( HANDLE hHeap, LPTSTR lptStr )
|
||
{
|
||
DWORD dwStrLen;
|
||
LPTSTR lptRet;
|
||
|
||
// Get some memory from our heap and the copy the string in
|
||
|
||
dwStrLen = lstrlen( lptStr );
|
||
lptRet = (LPTSTR) HeapAlloc( hHeap, 0, (dwStrLen + 1 ) * sizeof(TCHAR));
|
||
|
||
if (lptRet != NULL) {
|
||
|
||
// Copy it since the memory allocation succeded
|
||
lstrcpy( lptRet, lptStr);
|
||
}
|
||
|
||
return(lptRet);
|
||
}
|
||
|
||
|
||
|
||
|
||
PS_QFONT_ERROR LocPsMakeSubListEntry( PPS_FONT_QUERY pFontQuery,
|
||
LPWSTR lpUniNTFontData,
|
||
LPTSTR lpFaceName )
|
||
{
|
||
|
||
CHAR szFullPathToTT[MAX_PATH];
|
||
WCHAR uniSzFullPathToTT[MAX_PATH];
|
||
DWORD dwSizeOfFullPathToTT;
|
||
PPS_FONT_ENTRY pPsFontEntry;
|
||
PS_QFONT_ERROR pPsError=PS_QFONT_SUCCESS;
|
||
|
||
|
||
//
|
||
// Now that we have found a match we need to get the path to
|
||
// the TTF name. The entry we have most likely found is an FOT
|
||
// file which we need to pass to an INTERNAL function such that
|
||
// we may extract the full path to the TTF file name.
|
||
//
|
||
|
||
//
|
||
//***** NOTE **********************************************
|
||
//DJC NOTE: This is a call to an INTERNAL FUNCTION!!!!!!!
|
||
//***** NOTE **********************************************
|
||
//
|
||
|
||
extern GetFontResourceInfoW(LPWSTR,LPDWORD, LPVOID, DWORD);
|
||
|
||
//
|
||
// Set the initial size of the buffer
|
||
//
|
||
|
||
dwSizeOfFullPathToTT = sizeof( uniSzFullPathToTT);
|
||
|
||
if ( GetFontResourceInfoW(lpUniNTFontData,
|
||
&dwSizeOfFullPathToTT,
|
||
(LPVOID) uniSzFullPathToTT,
|
||
4L )) // 4 = GFRI_TTFILENAME out of wingdip.h
|
||
{
|
||
wcstombs( szFullPathToTT, uniSzFullPathToTT, sizeof(szFullPathToTT) );
|
||
|
||
//
|
||
// Okay were in good shape its a true type font...
|
||
// This worked meaning we have a real value so lets write it
|
||
// to the current list
|
||
//
|
||
|
||
if (pFontQuery->dwNumFonts < PSQFONT_MAX_FONTS) {
|
||
|
||
pPsFontEntry = &(pFontQuery->FontEntry[ pFontQuery->dwNumFonts ]);
|
||
|
||
pPsFontEntry->lpFontName = LocPsAllocAndCopy( pFontQuery->hHeap,
|
||
lpFaceName);
|
||
|
||
pPsFontEntry->dwFontNameLen = lstrlen(lpFaceName) * sizeof(TCHAR)
|
||
+ sizeof(TCHAR);
|
||
|
||
pPsFontEntry->lpFontFileName = LocPsAllocAndCopy( pFontQuery->hHeap,
|
||
szFullPathToTT);
|
||
|
||
pPsFontEntry->dwFontFileNameLen = lstrlen(szFullPathToTT) * sizeof(TCHAR)
|
||
+ sizeof(TCHAR);
|
||
|
||
pFontQuery->dwNumFonts++;
|
||
|
||
} else{
|
||
|
||
//
|
||
// Were out of space there are more fonts that match our criteria
|
||
// than we are able to report back. This is not a GREAT error message
|
||
// but adding a new one would be a change to a semi public header.
|
||
//
|
||
|
||
pPsError = PS_QFONT_ERROR_INDEX_OUT_OF_RANGE;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
return(pPsError);
|
||
}
|
||
|
||
PS_QFONT_ERROR LocPsAddToListIfNTfont( PPS_FONT_QUERY pFontQuery,
|
||
HKEY hNTFontlist,
|
||
DWORD dwNumNTfonts,
|
||
LPTSTR lpPsName,
|
||
LPTSTR lpTTData)
|
||
|
||
{
|
||
|
||
TCHAR sztNTFontData[MAX_PATH];
|
||
WCHAR uniSzNTFontData[MAX_PATH];
|
||
DWORD dwNTFontDataLen;
|
||
DWORD dwType;
|
||
BOOL bFound=FALSE;
|
||
|
||
|
||
|
||
|
||
// Now query the NT font to see if the font in question exists
|
||
dwNTFontDataLen = sizeof(sztNTFontData);
|
||
|
||
if ( RegQueryValueEx( hNTFontlist,
|
||
lpTTData,
|
||
NULL,
|
||
&dwType,
|
||
sztNTFontData,
|
||
&dwNTFontDataLen ) == ERROR_SUCCESS ) {
|
||
|
||
mbstowcs(uniSzNTFontData, sztNTFontData, sizeof(sztNTFontData));
|
||
|
||
return( LocPsMakeSubListEntry( pFontQuery, uniSzNTFontData, lpPsName ));
|
||
|
||
|
||
}
|
||
|
||
|
||
|
||
return( PS_QFONT_SUCCESS );
|
||
|
||
}
|
||
|
||
|
||
LONG LocPsWriteDefaultSubListToRegistry(void)
|
||
{
|
||
|
||
HKEY hSubstList;
|
||
DWORD dwStatus;
|
||
LPSTR lpStr;
|
||
|
||
HRSRC hrSubst;
|
||
HRSRC hrLoadSubst;
|
||
CHAR szPsName[PSQFONT_SCRATCH_SIZE];
|
||
CHAR szTTName[PSQFONT_SCRATCH_SIZE];
|
||
LPSTR lpDest;
|
||
int iState;
|
||
DWORD dwTotalLen;
|
||
LONG lRetVal=PS_QFONT_SUCCESS;
|
||
|
||
// Now lets recreate the new Key
|
||
RegCreateKeyEx(HKEY_LOCAL_MACHINE,
|
||
PSQFONT_SUBST_LIST,
|
||
0,
|
||
NULL,
|
||
REG_OPTION_NON_VOLATILE,
|
||
KEY_ALL_ACCESS | KEY_WRITE,
|
||
NULL,
|
||
&hSubstList,
|
||
&dwStatus );
|
||
|
||
|
||
|
||
hrSubst = FindResourceEx( hInst,
|
||
"RAWDATA",
|
||
MAKEINTRESOURCE(PSFONTSUB),
|
||
0);
|
||
if (hrSubst) {
|
||
|
||
// Get the size of the resource for future use
|
||
dwTotalLen = SizeofResource( hInst, hrSubst);
|
||
|
||
|
||
// We got it... so load it and lock it!!
|
||
hrLoadSubst = LoadResource( hInst, hrSubst);
|
||
|
||
|
||
lpStr = (LPSTR) LockResource( hrLoadSubst);
|
||
|
||
|
||
iState = PSP_DOING_PS_NAME;
|
||
lpDest = szPsName;
|
||
|
||
if (lpStr != (LPSTR) NULL) {
|
||
// enum through the list adding the keys....
|
||
while( dwTotalLen--) {
|
||
|
||
switch (iState) {
|
||
case PSP_DOING_PS_NAME:
|
||
if (*lpStr == '=') {
|
||
*lpDest = '\000';
|
||
iState = PSP_DOING_TT_NAME;
|
||
lpDest = szTTName;
|
||
|
||
}else{
|
||
*lpDest++ = *lpStr;
|
||
}
|
||
break;
|
||
case PSP_GETTING_EOL:
|
||
if (*lpStr == 0x0a) {
|
||
iState = PSP_DOING_PS_NAME;
|
||
|
||
lpDest = szPsName;
|
||
|
||
|
||
|
||
// Now write to the registry
|
||
RegSetValueEx( hSubstList,
|
||
szPsName,
|
||
0,
|
||
REG_SZ,
|
||
szTTName,
|
||
lstrlen(szTTName)+1);
|
||
|
||
|
||
|
||
|
||
|
||
}
|
||
break;
|
||
case PSP_DOING_TT_NAME:
|
||
|
||
if (*lpStr == ';') {
|
||
*lpDest = '\000';
|
||
iState = PSP_GETTING_EOL;
|
||
|
||
} else if (*lpStr == 0x0d) {
|
||
*lpDest = '\000';
|
||
iState = PSP_GETTING_EOL;
|
||
|
||
|
||
}else {
|
||
*lpDest++ = *lpStr;
|
||
}
|
||
|
||
break;
|
||
|
||
|
||
|
||
}
|
||
|
||
lpStr++;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
RegCloseKey(hSubstList);
|
||
|
||
|
||
return(lRetVal);
|
||
}
|
||
|
||
|
||
LONG LocPsGetOrCreateSubstList( PHKEY phKey )
|
||
{
|
||
LONG lRetVal;
|
||
BOOL bDone=FALSE;
|
||
|
||
lRetVal = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||
PSQFONT_SUBST_LIST,
|
||
0,
|
||
KEY_READ,
|
||
phKey );
|
||
|
||
|
||
if (lRetVal == ERROR_FILE_NOT_FOUND) {
|
||
|
||
// Since we did not find a font substitute list create a default one!
|
||
// in the registry
|
||
lRetVal = LocPsWriteDefaultSubListToRegistry();
|
||
|
||
|
||
|
||
lRetVal = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||
PSQFONT_SUBST_LIST,
|
||
0,
|
||
KEY_READ,
|
||
phKey );
|
||
|
||
}
|
||
return(lRetVal);
|
||
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// LocPsNormalizeFontName
|
||
//
|
||
// This function takes a font name as Stored in the registry and
|
||
// normalizes it by removing all spaces and stops processing when
|
||
// it hits a open paren
|
||
//
|
||
// Parameters:
|
||
// LPTSTR lptIN - The source string
|
||
// LPTSTR lptOUT - The destination string
|
||
//
|
||
// Returns:
|
||
//
|
||
// Nothing...
|
||
//
|
||
VOID LocPsNormalizeFontName(LPTSTR lptIN, LPTSTR lptOUT)
|
||
{
|
||
|
||
while(*lptIN != '\000' ) {
|
||
if (*lptIN == '(' ) {
|
||
break;
|
||
} else if ( *lptIN != ' ' ) {
|
||
*lptOUT++ = *lptIN;
|
||
}
|
||
lptIN++;
|
||
}
|
||
*lptOUT = '\000';
|
||
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
// verify the list is up to date
|
||
PS_QFONT_ERROR LocPsBuildCurrentFontList(PPS_FONT_QUERY pFontQuery )
|
||
{
|
||
HKEY hNtFontKey;
|
||
HKEY hSubstKey;
|
||
DWORD dwNumSubstFonts;
|
||
FILETIME ftSubstFontsTime;
|
||
TCHAR sztPsName[MAX_PATH];
|
||
TCHAR sztTTName[MAX_PATH];
|
||
DWORD dwPsNameSize;
|
||
DWORD dwTTNameSize;
|
||
DWORD dwType;
|
||
DWORD i;
|
||
DWORD dwNumNTFonts;
|
||
FILETIME ftNtFontTime;
|
||
BOOL bFoundCurrentFontList = FALSE;
|
||
|
||
|
||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||
PSQFONT_NT_FONT_LIST,
|
||
0,
|
||
KEY_READ,
|
||
&hNtFontKey ) != ERROR_SUCCESS ) {
|
||
|
||
return( PS_QFONT_ERROR_NO_NTFONT_REGISTRY_DATA );
|
||
|
||
}
|
||
|
||
LocPsQueryTimeAndValueCount( hNtFontKey,
|
||
&dwNumNTFonts,
|
||
&ftNtFontTime);
|
||
|
||
|
||
if (LocPsGetOrCreateSubstList( &hSubstKey ) != ERROR_SUCCESS) {
|
||
RegCloseKey( hNtFontKey );
|
||
return( PS_QFONT_ERROR_FONT_SUB );
|
||
}
|
||
|
||
// Get the value count and file time of the FontSubst entry
|
||
LocPsQueryTimeAndValueCount( hSubstKey,
|
||
&dwNumSubstFonts,
|
||
&ftSubstFontsTime);
|
||
|
||
|
||
|
||
// Now we have the real worker code... for each entry in our fontsubstitution
|
||
// table we will look to see if the subst font exists in the NT font section
|
||
// of the registry. If it does we will generate an enry in our current
|
||
// font list that maps a PostScript font name to an TrueType .ttf file
|
||
// with the current font.
|
||
|
||
|
||
for( i = 0 ; i < dwNumSubstFonts; i++ ) {
|
||
// Query the current font out of the list
|
||
dwPsNameSize = sizeof( sztPsName);
|
||
dwTTNameSize = sizeof( sztTTName);
|
||
|
||
if( RegEnumValue( hSubstKey,
|
||
i,
|
||
sztPsName,
|
||
&dwPsNameSize,
|
||
NULL,
|
||
&dwType,
|
||
sztTTName,
|
||
&dwTTNameSize ) == ERROR_SUCCESS) {
|
||
|
||
|
||
LocPsAddToListIfNTfont( pFontQuery,
|
||
hNtFontKey,
|
||
dwNumNTFonts,
|
||
sztPsName,
|
||
sztTTName);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
RegCloseKey(hNtFontKey);
|
||
RegCloseKey(hSubstKey);
|
||
|
||
return(0);
|
||
|
||
}
|
||
|
||
LONG LocPsQueryTimeAndValueCount( HKEY hKey,
|
||
LPDWORD lpdwValCount,
|
||
PFILETIME lpFileTime)
|
||
{
|
||
|
||
TCHAR lptClassName[500];
|
||
DWORD dwClassName=sizeof(lptClassName);
|
||
DWORD dwNumSubKeys;
|
||
DWORD dwLongestSubKeySize;
|
||
DWORD dwMaxClass;
|
||
|
||
DWORD dwBiggestValueName;
|
||
DWORD dwLongestValueName;
|
||
DWORD dwSecurityLength;
|
||
|
||
LONG lRetVal;
|
||
|
||
|
||
lRetVal = RegQueryInfoKey(hKey,
|
||
lptClassName,
|
||
&dwClassName,
|
||
(LPDWORD) NULL,
|
||
&dwNumSubKeys,
|
||
&dwLongestSubKeySize,
|
||
&dwMaxClass,
|
||
lpdwValCount,
|
||
&dwBiggestValueName,
|
||
&dwLongestValueName,
|
||
&dwSecurityLength,
|
||
lpFileTime);
|
||
|
||
return(lRetVal);
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
PS_QFONT_ERROR PsBeginFontQuery( PPS_QUERY_FONT_HANDLE pFontQueryHandle)
|
||
{
|
||
HANDLE hHeap;
|
||
PPS_FONT_QUERY pFontQuery;
|
||
HANDLE hFontMutex;
|
||
|
||
|
||
// Create the MUTEX that will guarantee us correct behaviour such that
|
||
// only one user can go through this code at any time...
|
||
//
|
||
hFontMutex = CreateMutex( NULL, FALSE, "SFMFontListMutex");
|
||
|
||
|
||
WaitForSingleObject( hFontMutex,INFINITE );
|
||
|
||
//
|
||
// 1st thing create a heap, we make all our allocations off this heap,
|
||
// that way cleanup is quick and easy.
|
||
//
|
||
|
||
hHeap = HeapCreate(0, 10000, 0);
|
||
|
||
if (hHeap == (HANDLE) NULL) {
|
||
LocPsEndMutex( hFontMutex);
|
||
return( PS_QFONT_ERROR_CANNOT_CREATE_HEAP );
|
||
}
|
||
|
||
pFontQuery = (PPS_FONT_QUERY)
|
||
HeapAlloc(
|
||
hHeap,
|
||
0,
|
||
sizeof( PS_FONT_QUERY) +
|
||
(sizeof(PS_FONT_ENTRY) * PSQFONT_MAX_FONTS));
|
||
|
||
|
||
if (pFontQuery == NULL) {
|
||
LocPsEndMutex( hFontMutex);
|
||
HeapDestroy(hHeap);
|
||
return( PS_QFONT_ERROR_NO_MEM);
|
||
}
|
||
|
||
// Now setup up the data for our font query control structure
|
||
pFontQuery->hHeap = hHeap;
|
||
pFontQuery->dwNumFonts = 0;
|
||
pFontQuery->dwSerial = PS_QFONT_SERIAL;
|
||
|
||
LocPsBuildCurrentFontList( pFontQuery );
|
||
|
||
|
||
*pFontQueryHandle = (PS_QUERY_FONT_HANDLE) pFontQuery;
|
||
|
||
LocPsEndMutex(hFontMutex);
|
||
|
||
return(PS_QFONT_SUCCESS);
|
||
|
||
}
|
||
VOID LocPsEndMutex(HANDLE hMutex)
|
||
{
|
||
|
||
// Now release the mutex
|
||
ReleaseMutex(hMutex);
|
||
|
||
// And finally delete it
|
||
CloseHandle(hMutex);
|
||
|
||
}
|
||
|
||
PS_QFONT_ERROR PsGetNumFontsAvailable( PS_QUERY_FONT_HANDLE pFontQueryHandle,
|
||
DWORD *pdwFonts)
|
||
{
|
||
|
||
PPS_FONT_QUERY pFontQuery;
|
||
pFontQuery = (PPS_FONT_QUERY) pFontQueryHandle;
|
||
|
||
if (pFontQueryHandle == NULL || pFontQuery->dwSerial != PS_QFONT_SERIAL) {
|
||
return( PS_QFONT_ERROR_INVALID_HANDLE );
|
||
}
|
||
|
||
// Handle is okay so keep going
|
||
*pdwFonts = pFontQuery->dwNumFonts;
|
||
|
||
return(PS_QFONT_SUCCESS);
|
||
|
||
}
|
||
PS_QFONT_ERROR PsGetFontInfo( PS_QUERY_FONT_HANDLE pFontQueryHandle,
|
||
DWORD dwIndex,
|
||
LPSTR lpFontName,
|
||
LPDWORD lpdwSizeOfFontName,
|
||
LPSTR lpFontFileName,
|
||
LPDWORD lpdwSizeOfFontFileName )
|
||
{
|
||
|
||
PPS_FONT_QUERY pFontQuery;
|
||
PPS_FONT_ENTRY pFontEntry;
|
||
PS_QFONT_ERROR QfontError=PS_QFONT_SUCCESS;
|
||
|
||
|
||
pFontQuery = (PPS_FONT_QUERY) pFontQueryHandle;
|
||
|
||
|
||
if (pFontQueryHandle == NULL || pFontQuery->dwSerial != PS_QFONT_SERIAL) {
|
||
return( PS_QFONT_ERROR_INVALID_HANDLE );
|
||
}
|
||
|
||
// Verify the index is in range and return the info
|
||
if (dwIndex >= pFontQuery->dwNumFonts) {
|
||
return PS_QFONT_ERROR_INDEX_OUT_OF_RANGE;
|
||
}
|
||
|
||
pFontEntry = &(pFontQuery->FontEntry[ dwIndex ]);
|
||
|
||
|
||
// Dont do the copy if the ptr is null but only return the
|
||
// required bytes
|
||
|
||
if (lpFontName != NULL) {
|
||
// Okay the user requested data so make sure there is enough
|
||
// room and return the font name
|
||
|
||
|
||
if (*lpdwSizeOfFontName >= pFontEntry->dwFontNameLen) {
|
||
lstrcpy( lpFontName, pFontEntry->lpFontName);
|
||
}else{
|
||
QfontError = PS_QFONT_ERROR_FONTNAMEBUFF_TOSMALL;
|
||
}
|
||
|
||
|
||
}
|
||
// either way set up the required size
|
||
*lpdwSizeOfFontName = pFontEntry->dwFontNameLen;
|
||
|
||
|
||
// Now handle the font file name
|
||
if (lpFontFileName != NULL) {
|
||
|
||
if (*lpdwSizeOfFontFileName >= pFontEntry->dwFontFileNameLen) {
|
||
lstrcpy( lpFontFileName, pFontEntry->lpFontFileName);
|
||
}else if (QfontError == PS_QFONT_SUCCESS ) {
|
||
|
||
QfontError = PS_QFONT_ERROR_FONTFILEBUFF_TOSMALL;
|
||
}
|
||
}
|
||
*lpdwSizeOfFontFileName = pFontEntry->dwFontFileNameLen;
|
||
|
||
|
||
return(QfontError);
|
||
|
||
|
||
}
|
||
|
||
|
||
|
||
PS_QFONT_ERROR PsEndFontQuery( PS_QUERY_FONT_HANDLE pFontQueryHandle)
|
||
{
|
||
|
||
PPS_FONT_QUERY pFontQuery;
|
||
pFontQuery = (PPS_FONT_QUERY) pFontQueryHandle;
|
||
|
||
if (pFontQueryHandle == NULL || pFontQuery->dwSerial != PS_QFONT_SERIAL) {
|
||
return( PS_QFONT_ERROR_INVALID_HANDLE );
|
||
}
|
||
|
||
|
||
// very simple verify the handle and destroy the heap, since all allocations
|
||
// were done off the heap were done...
|
||
HeapDestroy( pFontQuery->hHeap );
|
||
|
||
return(0);
|
||
|
||
}
|
||
|
||
|
||
|
||
|