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.
3946 lines
122 KiB
3946 lines
122 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: font.c
|
|
*
|
|
* Created: 28-May-1991 13:01:27
|
|
* Author: Gilman Wong [gilmanw]
|
|
*
|
|
* Copyright (c) 1990-1999 Microsoft Corporation
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include "exehdr.h"
|
|
#include "fot16.h"
|
|
#include "winfont.h"
|
|
|
|
// Stuf for CreateScaleableFontResource
|
|
|
|
#define ALIGNMENTSHIFT 4
|
|
#define ALIGNMENTCOUNT (1 << ALIGNMENTSHIFT)
|
|
#define CODE_OFFSET 512
|
|
#define RESOURCE_OFFSET 1024
|
|
#define PRIVRESSIZE 0x80
|
|
#define FONTDIRSIZINDEX 6
|
|
#define NE_WINDOWS 2
|
|
|
|
static
|
|
WCHAR * pwszAllocNtMultiplePath(
|
|
LPWSTR pwszFileName,
|
|
FLONG *pfl,
|
|
ULONG *pcwc,
|
|
ULONG *pcFiles,
|
|
BOOL bAddFR, // called by add or remove fr
|
|
DWORD *pdwPidTid, // PID/TID for embedded font
|
|
BOOL bChkFOT
|
|
);
|
|
|
|
|
|
// Define an EXE header. This will be hardcoded into the resource file.
|
|
|
|
#define SIZEEXEHEADER (CJ_EXE_HDR + 25 + 39) // should be 0x80
|
|
|
|
CONST static BYTE ajExeHeader[SIZEEXEHEADER] = {
|
|
0x4d, 0x5a, // unsigned short e_magic;
|
|
0x01, 0x00, // unsigned short e_cblp;
|
|
0x02, 0x00, // unsigned short e_cp;
|
|
0x00, 0x00, // unsigned short e_crlc;
|
|
0x04, 0x00, // unsigned short e_cparhdr;
|
|
0x0f, 0x00, // unsigned short e_minalloc;
|
|
0xff, 0xff, // unsigned short e_maxalloc;
|
|
0x00, 0x00, // unsigned short e_ss;
|
|
0xb8, 0x00, // unsigned short e_sp;
|
|
0x00, 0x00, // unsigned short e_csum;
|
|
0x00, 0x00, // unsigned short e_ip;
|
|
0x00, 0x00, // unsigned short e_cs;
|
|
0x40, 0x00, // unsigned short e_lfarlc;
|
|
0x00, 0x00, // unsigned short e_ovno;
|
|
0x00, 0x00, 0x00, 0x00, // unsigned short e_res[ERESWDS];
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
SIZEEXEHEADER, 0x00, 0x00, 0x00, // long e_lfanew;
|
|
|
|
|
|
// [gilmanw]
|
|
// I don't know what the rest of this stuff is. Its not
|
|
// in the definition of EXE_HDR that we have in gdi\inc\exehdr.h.
|
|
// The string is 39 bytes, the other stuff is 25 bytes.
|
|
|
|
0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd,
|
|
0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21,
|
|
|
|
'T','h','i','s',' ',
|
|
'i','s',' ',
|
|
'a',' ',
|
|
'T','r','u','e','T','y','p','e',' ',
|
|
'f','o','n','t',',',' ',
|
|
'n','o','t',' ',
|
|
'a',' ',
|
|
'p','r','o','g','r','a','m','.',
|
|
|
|
0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x4b, 0x69, 0x65,
|
|
0x73, 0x61, 0x00
|
|
};
|
|
|
|
|
|
// Define a resource table. This will be hardcoded into the resource file.
|
|
|
|
#define SIZEFAKERESTBL 52
|
|
|
|
CONST static USHORT ausFakeResTable[SIZEFAKERESTBL/2] = {
|
|
ALIGNMENTSHIFT, 0x8007, 1, 0, 0,
|
|
(RESOURCE_OFFSET+PRIVRESSIZE) >> ALIGNMENTSHIFT,
|
|
(0x90 >> ALIGNMENTSHIFT), 0x0c50,
|
|
0x002c, 0, 0, 0x80cc, 1, 0, 0,
|
|
RESOURCE_OFFSET >> ALIGNMENTSHIFT,
|
|
(PRIVRESSIZE >> ALIGNMENTSHIFT), 0x0c50, 0x8001, 0, 0, 0,
|
|
0x4607, 0x4e4f, 0x4454, 0x5249 // counted string 'FONTDIR'
|
|
};
|
|
|
|
|
|
// Define a New EXE header. This will be hardcoded into the resource file.
|
|
|
|
#define SIZENEWEXE (CJ_NEW_EXE)
|
|
|
|
CONST static USHORT ausNewExe[SIZENEWEXE/2] = {
|
|
NEMAGIC, //dw NEMAGIC ;magic number
|
|
0x1005, //db 5, 10h ;version #, revision #
|
|
0xffff, //dw -1 ;offset to table entry (to be filled)
|
|
0x0002, //dw 2 ;# of bytes in entry table
|
|
0x0000, 0x0000, //dd 0 ;checksum of whole file
|
|
0x8000, 0x0000, //dw 8000h, 0, 0, 0
|
|
0x0000, 0x0000,
|
|
0x0000, 0x0000, //dd 0, 0
|
|
0x0000, 0x0000,
|
|
0x0000, 0x0000, //dw 0, 0
|
|
0xffff, //dw -1 ;size of non-resident name table
|
|
SIZENEWEXE, //dw (size NewExe) ;offset to segment table
|
|
SIZENEWEXE, //dw (size NewExe) ;offset to resource table
|
|
SIZENEWEXE+SIZEFAKERESTBL, //dw (size NewExe)+SIZEFAKERESTBL ;off to resident name table
|
|
0xffff, //dw -1 ;offset to module reference table
|
|
0xffff, //dw -1 ;offset to imported names table
|
|
0xffff, 0x0000, //dd 0ffffh ;offset to non-resident names table
|
|
0x0000, ALIGNMENTSHIFT, //dw 0, ALIGNMENTSHIFT, 2
|
|
0x0002,
|
|
NE_WINDOWS, //db NE_WINDOWS, 0
|
|
0x0000, 0x0000, //dw 0, 0, 0, 300h
|
|
0x0000, 0x0300
|
|
};
|
|
|
|
|
|
#define OFF_FONTDIRSIZINDEX ((2*FONTDIRSIZINDEX)+SIZEEXEHEADER+SIZENEWEXE)
|
|
|
|
|
|
// Define font res string.
|
|
|
|
#define SIZEFONTRES 8
|
|
|
|
CONST static BYTE ajFontRes[SIZEFONTRES] = {
|
|
'F','O','N','T','R','E','S',':'
|
|
};
|
|
|
|
#define CJ_OUTOBJ (SIZEFFH + LF_FACESIZE + LF_FULLFACESIZE + LF_FACESIZE + PRIVRESSIZE + 1024 + 16)
|
|
|
|
|
|
|
|
|
|
static
|
|
VOID vNewTextMetricExWToNewTextMetricExA (
|
|
NEWTEXTMETRICEXA *pntm,
|
|
NTMW_INTERNAL *pntmi
|
|
);
|
|
|
|
typedef struct _AFRTRACKNODE
|
|
{
|
|
WCHAR *pwszPath;
|
|
struct _AFRTRACKNODE *pafrnNext;
|
|
UINT id;
|
|
UINT cLoadCount;
|
|
} AFRTRACKNODE;
|
|
|
|
extern AFRTRACKNODE *pAFRTNodeList;
|
|
|
|
AFRTRACKNODE *pAFRTNodeList;
|
|
|
|
|
|
static
|
|
VOID vConvertLogicalFont(
|
|
ENUMLOGFONTEXDVW *pelfw,
|
|
PVOID pv
|
|
);
|
|
|
|
|
|
|
|
ULONG cchCutOffStrLen(PSZ psz, ULONG cCutOff);
|
|
|
|
ULONG
|
|
cwcCutOffStrLen (
|
|
PWSZ pwsz,
|
|
ULONG cCutOff
|
|
);
|
|
|
|
|
|
// GETS ushort at (PBYTE)pv + off. both pv and off must be even
|
|
|
|
#define US_GET(pv,off) ( *(PUSHORT)((PBYTE)(pv) + (off)) )
|
|
#define S_GET(pv,off) ((SHORT)US_GET((pv),(off)))
|
|
|
|
#if TRACK_GDI_ALLOC
|
|
|
|
// Now access to these guys insn't sycnronized but they
|
|
// don't ever collide anyhow, and since it's debug stuff who cares.
|
|
|
|
ULONG bmgulNumMappedViews = 0;
|
|
ULONG bmgulTotalSizeViews = 0;
|
|
|
|
#endif
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bMapFileUNICODEClideSide
|
|
*
|
|
* Similar to PosMapFile except that it takes unicode file name
|
|
*
|
|
* History:
|
|
* Feb-05-1997 -by- Xudong Wu [tessiew]
|
|
* Extend the function by adding an extra parameter bNtPath to handle the
|
|
* NT path name for file mapping.
|
|
*
|
|
* 21-May-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bMapFileUNICODEClideSide
|
|
(
|
|
PWSTR pwszFileName,
|
|
CLIENT_SIDE_FILEVIEW *pfvw,
|
|
BOOL bNtPath
|
|
)
|
|
{
|
|
UNICODE_STRING ObFileName;
|
|
OBJECT_ATTRIBUTES ObjA;
|
|
NTSTATUS rc = 0L;
|
|
IO_STATUS_BLOCK iosb; // IO Status Block
|
|
|
|
PWSTR pszFilePart = NULL;
|
|
|
|
// NOTE PERF: this is the mode I want, but appears to be broken, so I had to
|
|
// put the slower FILE_STANDARD_INFORMATION mode of query which appears to
|
|
// work correctly [bodind]
|
|
// FILE_END_OF_FILE_INFORMATION eof;
|
|
|
|
FILE_STANDARD_INFORMATION eof;
|
|
SIZE_T cjView;
|
|
|
|
pfvw->hf = (HANDLE)0; // file handle
|
|
pfvw->hSection = (HANDLE)0; // section handle
|
|
|
|
ObFileName.Buffer = NULL;
|
|
|
|
// section offset must be initialized to 0 for NtMapViewOfSection to work
|
|
|
|
if (bNtPath)
|
|
{
|
|
RtlInitUnicodeString(&ObFileName, pwszFileName);
|
|
}
|
|
else //Dos path name converted to NtpathName
|
|
{
|
|
RtlDosPathNameToNtPathName_U(pwszFileName, &ObFileName, &pszFilePart, NULL);
|
|
}
|
|
|
|
InitializeObjectAttributes( &ObjA,
|
|
&ObFileName,
|
|
OBJ_CASE_INSENSITIVE, // case insensitive file search
|
|
NULL,
|
|
NULL );
|
|
|
|
// NtOpenFile fails for some reason if the file is on the net unless I put this
|
|
// InpersonateClient/RevertToSelf stuff around it
|
|
|
|
// peform open call
|
|
|
|
rc = NtOpenFile
|
|
(
|
|
&pfvw->hf, // store file handle here
|
|
FILE_READ_DATA | SYNCHRONIZE, // desired read access
|
|
&ObjA, // filename
|
|
&iosb, // io result goes here
|
|
FILE_SHARE_READ,
|
|
FILE_SYNCHRONOUS_IO_NONALERT
|
|
);
|
|
|
|
if (!bNtPath && ObFileName.Buffer)
|
|
{
|
|
RtlFreeHeap(RtlProcessHeap(),0,ObFileName.Buffer);
|
|
}
|
|
|
|
// check success or fail
|
|
|
|
if (!NT_SUCCESS(rc) || !NT_SUCCESS(iosb.Status))
|
|
{
|
|
#ifdef DEBUG_THIS_JUNK
|
|
DbgPrint("bMapFileUNICODEClideSide(): NtOpenFile error code , rc = 0x%08lx , 0x%08lx\n", rc, iosb.Status);
|
|
#endif // DEBUG_THIS_JUNK
|
|
return FALSE;
|
|
}
|
|
|
|
// get the size of the file, the view should be size of the file rounded up
|
|
// to a page bdry
|
|
|
|
rc = NtQueryInformationFile
|
|
(
|
|
pfvw->hf, // IN file handle
|
|
&iosb, // OUT io status block
|
|
(PVOID)&eof, // OUT buffer to retrun info into
|
|
sizeof(eof), // IN size of the buffer
|
|
FileStandardInformation // IN query mode
|
|
);
|
|
|
|
// dont really want the view size, but eof file
|
|
|
|
pfvw->cjView = eof.EndOfFile.LowPart;
|
|
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
#ifdef DEBUG_THIS_JUNK
|
|
DbgPrint("bMapFileUNICODEClideSide(): NtQueryInformationFile error code 0x%08lx\n", rc);
|
|
#endif // DEBUG_THIS_JUNK
|
|
NtClose(pfvw->hf);
|
|
return FALSE;
|
|
}
|
|
|
|
rc = NtCreateSection
|
|
(
|
|
&pfvw->hSection, // return section handle here
|
|
SECTION_MAP_READ, // read access to the section
|
|
(POBJECT_ATTRIBUTES)NULL, // default
|
|
NULL, // size is set to the size of the file when hf != 0
|
|
PAGE_READONLY, // read access to commited pages
|
|
SEC_COMMIT, // all pages set to the commit state
|
|
pfvw->hf // that's the file we are mapping
|
|
);
|
|
|
|
// check success, close the file if failed
|
|
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
#ifdef DEBUG_THIS_JUNK
|
|
DbgPrint("bMapFileUNICODEClideSide(): NtCreateSection error code 0x%08lx\n", rc);
|
|
#endif // DEBUG_THIS_JUNK
|
|
NtClose(pfvw->hf);
|
|
return FALSE;
|
|
}
|
|
|
|
// zero out *ppv so as to force the operating system to determine
|
|
// the base address to be returned
|
|
|
|
pfvw->pvView = (PVOID)NULL;
|
|
cjView = 0L;
|
|
|
|
rc = NtMapViewOfSection
|
|
(
|
|
pfvw->hSection, // section we are mapping
|
|
NtCurrentProcess(), // process handle
|
|
&pfvw->pvView, // place to return the base address of view
|
|
0L, // requested # of zero bits in the base address
|
|
0L, // commit size, (all of them commited already)
|
|
NULL,
|
|
&cjView, // size of the view should is returned here
|
|
ViewUnmap, // do not map the view to child processess
|
|
0L, // allocation type flags
|
|
PAGE_READONLY // read access to commited pages
|
|
);
|
|
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
#ifdef DEBUG_THIS_JUNK
|
|
DbgPrint("bMapFileUNICODEClideSide(): NtMapViewOfSection error code 0x%08lx\n", rc);
|
|
#endif // DEBUG_THIS_JUNK
|
|
|
|
NtClose(pfvw->hSection);
|
|
NtClose(pfvw->hf);
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef DEBUG_THIS_JUNK
|
|
DbgPrint("cjView = 0x%lx, eof.Low = 0x%lx, eof.High = 0x%lx\n",
|
|
cjView,
|
|
eof.EndOfFile.LowPart,
|
|
eof.EndOfFile.HighPart);
|
|
#endif // DEBUG_THIS_JUNK
|
|
|
|
// #define PAGE_SIZE 4096 --- this is now defined in local.h
|
|
#define PAGE_ROUNDUP(x) (((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
|
|
|
|
if (
|
|
(eof.EndOfFile.HighPart != 0) ||
|
|
(PAGE_ROUNDUP(eof.EndOfFile.LowPart) > cjView)
|
|
)
|
|
{
|
|
#ifdef DEBUG_THIS_JUNK
|
|
DbgPrint(
|
|
"bMapFileUNICODEClideSide(): eof.HighPart = 0x%lx, eof.LowPart = 0x%lx, cjView = 0x%lx\n",
|
|
eof.EndOfFile.HighPart, PAGE_ROUNDUP(eof.EndOfFile.LowPart), cjView
|
|
);
|
|
#endif // DEBUG_THIS_JUNK
|
|
|
|
rc = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
if (!NT_SUCCESS(rc) || (pfvw->cjView == 0))
|
|
{
|
|
NtClose(pfvw->hSection);
|
|
NtClose(pfvw->hf);
|
|
return FALSE;
|
|
}
|
|
else if (pfvw->cjView == 0)
|
|
{
|
|
#if DBG
|
|
DbgPrint("gdisrvl!bMapFileUNICODEClideSide(): WARNING--empty file %ws\n", pwszFileName);
|
|
#endif
|
|
|
|
vUnmapFileClideSide(pfvw);
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vUnmapFileClideSide
|
|
*
|
|
* Unmaps file whose view is based at pv
|
|
*
|
|
* 14-Dec-1990 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vUnmapFileClideSide(PCLIENT_SIDE_FILEVIEW pfvw)
|
|
{
|
|
|
|
#if TRACK_GDI_ALLOC
|
|
|
|
// Now access to these guys insn't sycnronized but they (we hope)
|
|
// don't ever collide anyhow, and since it's debug stuff who cares.
|
|
|
|
bmgulNumMappedViews -= 1;
|
|
bmgulTotalSizeViews -= PAGE_ROUNDUP(pfvw->cjView);
|
|
// DbgPrint("UnMapping %lu %lu\n",pfvw->cjView,PAGE_ROUNDUP(pfvw->cjView));
|
|
|
|
#endif
|
|
|
|
NtUnmapViewOfSection(NtCurrentProcess(),pfvw->pvView);
|
|
|
|
//
|
|
// now close section handle
|
|
//
|
|
|
|
NtClose(pfvw->hSection);
|
|
|
|
//
|
|
// close file handle. other processes can now open this file for access
|
|
//
|
|
|
|
NtClose(pfvw->hf);
|
|
|
|
//
|
|
// prevent accidental use
|
|
//
|
|
|
|
pfvw->pvView = NULL;
|
|
pfvw->hf = (HANDLE)0;
|
|
pfvw->hSection = (HANDLE)0;
|
|
pfvw->cjView = 0;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL bVerifyFOT
|
|
*
|
|
* Effects: verify that that a file is valid fot file
|
|
*
|
|
*
|
|
* History:
|
|
* 29-Jan-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
|
|
static
|
|
BOOL bVerifyFOT
|
|
(
|
|
PCLIENT_SIDE_FILEVIEW pfvw,
|
|
PWINRESDATA pwrd,
|
|
FLONG *pflEmbed,
|
|
DWORD *pdwPidTid
|
|
)
|
|
{
|
|
PBYTE pjNewExe; // ptr to the beginning of the new exe hdr
|
|
PBYTE pjResType; // ptr to the beginning of TYPEINFO struct
|
|
ULONG iResID; // resource type id
|
|
PBYTE pjData;
|
|
ULONG ulLength;
|
|
ULONG ulNameID;
|
|
ULONG crn;
|
|
|
|
pwrd->pvView = pfvw->pvView;
|
|
pwrd->cjView = pfvw->cjView;
|
|
|
|
// Initialize embed flag to FALSE (not hidden).
|
|
|
|
*pflEmbed = 0;
|
|
*pdwPidTid = 0;
|
|
|
|
// check the magic # at the beginning of the old header
|
|
|
|
// *.TTF FILES are eliminated on the following check
|
|
|
|
if (US_GET(pfvw->pvView, OFF_e_magic) != EMAGIC)
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
pwrd->dpNewExe = (PTRDIFF)READ_DWORD((PBYTE)pfvw->pvView + OFF_e_lfanew);
|
|
|
|
// make sure that offset is consistent
|
|
|
|
if ((ULONG)pwrd->dpNewExe > pwrd->cjView)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pjNewExe = (PBYTE)pfvw->pvView + pwrd->dpNewExe;
|
|
|
|
if (US_GET(pjNewExe, OFF_ne_magic) != NEMAGIC)
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
pwrd->cjResTab = (ULONG)(US_GET(pjNewExe, OFF_ne_restab) -
|
|
US_GET(pjNewExe, OFF_ne_rsrctab));
|
|
|
|
if (pwrd->cjResTab == 0L)
|
|
{
|
|
// The following test is applied by DOS, so I presume that it is
|
|
// legitimate. The assumption is that the resident name table
|
|
// FOLLOWS the resource table directly, and that if it points to
|
|
// the same location as the resource table, then there are no
|
|
// resources. [bodind]
|
|
|
|
WARNING("No resources in *.fot file\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
// want offset from pvView, not from pjNewExe => must add dpNewExe
|
|
|
|
pwrd->dpResTab = (PTRDIFF)US_GET(pjNewExe, OFF_ne_rsrctab) + pwrd->dpNewExe;
|
|
|
|
// make sure that offset is consistent
|
|
|
|
if ((ULONG)pwrd->dpResTab > pwrd->cjView)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// what really lies at the offset OFF_ne_rsrctab is a NEW_RSRC.rs_align field
|
|
// that is used in computing resource data offsets and sizes as a shift factor.
|
|
// This field occupies two bytes on the disk and the first TYPEINFO structure
|
|
// follows right after. We want pwrd->dpResTab to point to the first
|
|
// TYPEINFO structure, so we must add 2 to get there and subtract 2 from
|
|
// the length
|
|
|
|
pwrd->ulShift = (ULONG) US_GET(pfvw->pvView, pwrd->dpResTab);
|
|
pwrd->dpResTab += 2;
|
|
pwrd->cjResTab -= 2;
|
|
|
|
// Now we want to determine where the resource data is located.
|
|
// The data consists of a RSRC_TYPEINFO structure, followed by
|
|
// an array of RSRC_NAMEINFO structures, which are then followed
|
|
// by a RSRC_TYPEINFO structure, again followed by an array of
|
|
// RSRC_NAMEINFO structures. This continues until an RSRC_TYPEINFO
|
|
// structure which has a 0 in the rt_id field.
|
|
|
|
pjResType = (PBYTE)pfvw->pvView + pwrd->dpResTab;
|
|
iResID = (ULONG) US_GET(pjResType,OFF_rt_id);
|
|
|
|
while(iResID)
|
|
{
|
|
// # of NAMEINFO structures that follow = resources of this type
|
|
|
|
crn = (ULONG)US_GET(pjResType, OFF_rt_nres);
|
|
|
|
if ((crn == 1) && ((iResID == RT_FDIR) || (iResID == RT_PSZ)))
|
|
{
|
|
// this is the only interesting case, we only want a single
|
|
// font directory and a single string resource for a ttf file name
|
|
|
|
pjData = (PBYTE)pfvw->pvView +
|
|
(US_GET(pjResType,CJ_TYPEINFO + OFF_rn_offset) << pwrd->ulShift);
|
|
ulLength = (ULONG)US_GET(pjResType,CJ_TYPEINFO + OFF_rn_length) << pwrd->ulShift;
|
|
ulNameID = (ULONG)US_GET(pjResType,CJ_TYPEINFO + OFF_rn_id);
|
|
|
|
if (iResID == RT_FDIR)
|
|
{
|
|
if (ulNameID != RN_ID_FDIR)
|
|
{
|
|
return (FALSE); // *.fon files get eliminated here
|
|
}
|
|
|
|
pwrd->pjHdr = pjData + 4; // 4 bytes to the beginning of font device header
|
|
pwrd->cjHdr = ulLength - 4;
|
|
|
|
//
|
|
// Used to check if the client thread or process is allowed to
|
|
// load this font and get the FRW_EMB_PID and FRW_EMB_TID flags
|
|
//
|
|
// Any client thread or process is authorized to load a font if
|
|
// the font isn't ebmeded ( i.e. hidden ). If
|
|
// FRW_EMB_PID is set then the PID written in the
|
|
// copyright string of the must equal that of the client
|
|
// process. If the FRW_EMB_TID flag is set then the
|
|
// TID written into the copyright
|
|
// string must equal that of the client thread.
|
|
//
|
|
// Returns TRUE if this client process or thread is authorized
|
|
// to load this font or FALSE if it isn't.
|
|
//
|
|
|
|
// Note: Win 3.1 hack. The LSB of Type is used by Win 3.1 as an engine type
|
|
// and font embedding flag. Font embedding is a form of a "hidden
|
|
// font file". The MSB of Type is the same as the fsSelection from
|
|
// IFIMETRICS. (Strictly speaking, the MSB of Type is equal to the
|
|
// LSB of IFIMETRICS.fsSelection).
|
|
|
|
// now convert flags from the font file format to the ifi format
|
|
|
|
*pflEmbed = ((READ_WORD(pwrd->pjHdr + OFF_Type) & 0x00ff) &
|
|
( PF_TID | PF_ENCAPSULATED));
|
|
|
|
if (*pflEmbed)
|
|
{
|
|
*pflEmbed = (*pflEmbed & PF_TID) ? FRW_EMB_TID : FRW_EMB_PID;
|
|
|
|
WARNING("bVerifyFOT(): notification--embedded (hidden) TT font\n");
|
|
|
|
*pdwPidTid = READ_DWORD( pwrd->pjHdr + OFF_Copyright );
|
|
}
|
|
}
|
|
else // iResID == RT_PSZ
|
|
{
|
|
ASSERTGDI(iResID == RT_PSZ, "bVerifyFOT!_not RT_PSZ\n");
|
|
|
|
if (ulNameID != RN_ID_PSZ)
|
|
{
|
|
WARNING("bVerifyFOT!_RN_ID_PSZ\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
pwrd->pszNameTTF = (PSZ)pjData;
|
|
pwrd->cchNameTTF = strlen(pwrd->pszNameTTF);
|
|
|
|
if (ulLength < (pwrd->cchNameTTF + 1)) // 1 for terminating '\0'
|
|
{
|
|
WARNING("bVerifyFOT!_ pwrd->cchNameTTF\n");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
}
|
|
else // this is something we do not recognize as an fot file
|
|
{
|
|
WARNING("bVerifyFOT!_fot file with crn != 1\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
// get ptr to the new TYPEINFO struc and the new resource id
|
|
|
|
pjResType = pjResType + CJ_TYPEINFO + crn * CJ_NAMEINFO;
|
|
iResID = (ULONG) US_GET(pjResType,OFF_rt_id);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* cGetTTFFromFOT
|
|
*
|
|
* Attempts to extract the TTF pathname from a given FOT file. If a return
|
|
* buffer is provided (pwszTTFName !NULL), then the pathname is copied into
|
|
* the buffer. Otherwise, if the buffer is NULL, the size of the buffer
|
|
* (in WCHARs) needed is returned.
|
|
*
|
|
* Returns:
|
|
* The number of characters copied into the return buffer. The number
|
|
* of WCHARs needed in the buffer if the buffer is NULL. If an error
|
|
* occurs, zero is returned.
|
|
*
|
|
* History:
|
|
* 22-Apr-1992 -by- Gilman Wong [gilmanw]
|
|
* Adapted from TTFD.
|
|
\**************************************************************************/
|
|
|
|
#define FOT_EXCEPTED 0
|
|
#define FOT_NOT_FOT 1
|
|
#define FOT_IS_FOT 2
|
|
|
|
ULONG cGetTTFFromFOT (
|
|
WCHAR *pwszFOT, // pointer to incoming FOT name
|
|
ULONG cwcTTF, // size of buffer (in WCHAR)
|
|
WCHAR *pwszTTF, // return TTF name in this buffer
|
|
FLONG *pfl, // flags, indicate the location of the .ttf
|
|
FLONG *pflEmbed, // flag, indicating PID or TID
|
|
DWORD *pdwPidTid, // PID/TID for embedded font
|
|
BOOL bChkFOT
|
|
)
|
|
{
|
|
CLIENT_SIDE_FILEVIEW fvw;
|
|
WINRESDATA wrd;
|
|
UINT Result;
|
|
WCHAR awcPath[MAX_PATH],awcFile[MAX_PATH];
|
|
ULONG cNeed = 0;
|
|
WCHAR *pwszTmp = NULL;
|
|
|
|
ULONG cwcFOT = wcslen(pwszFOT);
|
|
|
|
if (cwcFOT >= 5) // fot file has to have a form x.fot, which is at least 5 wchars long
|
|
pwszTmp = &pwszFOT[cwcFOT - 4];
|
|
|
|
// here we are making the exception for FOT files and we require that the file has an .FOT
|
|
// extension for us to even try to recognize it as a valid FOT file.
|
|
|
|
if
|
|
(bChkFOT || ( pwszTmp &&
|
|
(pwszTmp[0] == L'.') &&
|
|
(pwszTmp[1] == L'F' || pwszTmp[1] == L'f') &&
|
|
(pwszTmp[2] == L'O' || pwszTmp[2] == L'o') &&
|
|
(pwszTmp[3] == L'T' || pwszTmp[3] == L't'))
|
|
)
|
|
{
|
|
// Map the file into memory.
|
|
|
|
if (bMapFileUNICODEClideSide(pwszFOT,&fvw,FALSE))
|
|
{
|
|
//
|
|
// Check the validity of this file as fot file
|
|
// and if a valid fot file, must extract the name of an underlining ttf
|
|
// file. The file could be on the net so we need try excepts.
|
|
//
|
|
|
|
try
|
|
{
|
|
if(bVerifyFOT(&fvw,&wrd,pflEmbed,pdwPidTid))
|
|
{
|
|
// this could except which is why we do it here
|
|
vToUnicodeN(awcFile, MAX_PATH, wrd.pszNameTTF, strlen(wrd.pszNameTTF)+1);
|
|
Result = FOT_IS_FOT;
|
|
}
|
|
else
|
|
{
|
|
Result = FOT_NOT_FOT;
|
|
}
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("bVerifyFOT exception accessing font file\n");
|
|
Result = FOT_EXCEPTED;
|
|
}
|
|
|
|
if(Result == FOT_IS_FOT)
|
|
{
|
|
|
|
if (bMakePathNameW(awcPath,awcFile,NULL, pfl))
|
|
{
|
|
//
|
|
// Determine pathname length
|
|
//
|
|
|
|
cNeed = wcslen(awcPath) + 1;
|
|
pwszFOT = awcPath;
|
|
}
|
|
|
|
// cGetTTFFromFOT called by font sweeper.
|
|
// TTF file might exist over net but connection has not been established yet.
|
|
|
|
else if (pfl)
|
|
{
|
|
cNeed = wcslen(awcFile) + 1;
|
|
pwszFOT = awcFile;
|
|
}
|
|
}
|
|
else if(Result != FOT_EXCEPTED)
|
|
{
|
|
//
|
|
// We have to assume it is another type of file.
|
|
// just copy the name in the buffer
|
|
//
|
|
|
|
cNeed = wcslen(pwszFOT) + 1;
|
|
|
|
if (pfl)
|
|
{
|
|
KdPrint(("cGetTTFFromFOT: Invalid FOT file: %ws\n", pwszFOT));
|
|
*pfl |= FONT_ISNOT_FOT;
|
|
}
|
|
}
|
|
|
|
vUnmapFileClideSide(&fvw);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cNeed = cwcFOT + 1;
|
|
|
|
if (pfl)
|
|
{
|
|
KdPrint(("cGetTTFFromFOT: Invalid FOT file: %ws\n", pwszFOT));
|
|
*pfl |= FONT_ISNOT_FOT;
|
|
}
|
|
}
|
|
|
|
if (cNeed == 0)
|
|
{
|
|
KdPrint(("cGetTTFFromFOT failed for font file %ws\n", pwszFOT));
|
|
}
|
|
|
|
//
|
|
// If return buffer exists and we succeded, copy pathname to it.
|
|
//
|
|
|
|
if (cNeed &&
|
|
(pwszTTF != (PWSZ) NULL))
|
|
{
|
|
if (cNeed <= cwcTTF)
|
|
{
|
|
wcscpy(pwszTTF, pwszFOT);
|
|
}
|
|
else
|
|
{
|
|
WARNING("gdisrv!cGetTTFFromFOT(): buffer too small\n");
|
|
cNeed = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Otherwise, caller just wants us to return the number of characters.
|
|
//
|
|
}
|
|
|
|
return cNeed;
|
|
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL bInitSystemAndFontsDirectoriesW(WCHAR **ppwcSystemDir, WCHAR **ppwcFontsDir)
|
|
*
|
|
* Effects:
|
|
*
|
|
* Warnings:
|
|
*
|
|
* History:
|
|
* 30-Oct-1995 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
WCHAR *gpwcSystemDir = NULL;
|
|
WCHAR *gpwcFontsDir = NULL;
|
|
|
|
#define WSTR_SYSTEM_SUBDIR L"\\system"
|
|
#define WSTR_FONT_SUBDIR L"\\fonts"
|
|
|
|
BOOL bInitSystemAndFontsDirectoriesW(WCHAR **ppwcSystemDir, WCHAR **ppwcFontsDir)
|
|
{
|
|
WCHAR awcWindowsDir[MAX_PATH];
|
|
UINT cwchWinPath, cwchSystem, cwchFonts;
|
|
BOOL bRet = TRUE;
|
|
|
|
// see if already initialized, if yes we are done.
|
|
|
|
if (!(*ppwcSystemDir))
|
|
{
|
|
// Compute the windows and font directory pathname lengths (including NULL).
|
|
// Note that cwchWinPath may have a trailing '\', in which case we will
|
|
// have computed the path length to be one greater than it should be.
|
|
|
|
cwchWinPath = GetSystemWindowsDirectoryW(awcWindowsDir, MAX_PATH);
|
|
|
|
if( cwchWinPath ){
|
|
|
|
// the cwchWinPath value does not include the terminating zero
|
|
|
|
if (awcWindowsDir[cwchWinPath - 1] == L'\\')
|
|
{
|
|
cwchWinPath -= 1;
|
|
}
|
|
awcWindowsDir[cwchWinPath] = L'\0'; // make sure to zero terminate
|
|
|
|
cwchSystem = cwchWinPath + sizeof(WSTR_SYSTEM_SUBDIR)/sizeof(WCHAR);
|
|
cwchFonts = cwchWinPath + sizeof(WSTR_FONT_SUBDIR)/sizeof(WCHAR);
|
|
|
|
if (*ppwcSystemDir = LocalAlloc(LMEM_FIXED, (cwchSystem+cwchFonts) * sizeof(WCHAR)))
|
|
{
|
|
*ppwcFontsDir = &((*ppwcSystemDir)[cwchSystem]);
|
|
wcscpy(*ppwcSystemDir,awcWindowsDir);
|
|
wcscpy(*ppwcFontsDir,awcWindowsDir);
|
|
|
|
// Append the system and font subdirectories
|
|
|
|
lstrcatW(*ppwcSystemDir, WSTR_SYSTEM_SUBDIR);
|
|
lstrcatW(*ppwcFontsDir, WSTR_FONT_SUBDIR);
|
|
}
|
|
else
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vConverLogFont *
|
|
* *
|
|
* Converts a LOGFONTA into an equivalent ENUMLOGFONTEXDVW structure. *
|
|
* *
|
|
* History: *
|
|
* Thu 15-Aug-1991 13:01:33 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
VOID vConvertLogFont(
|
|
ENUMLOGFONTEXDVW *pelfexdvw,
|
|
LOGFONTA *plf
|
|
)
|
|
{
|
|
ENUMLOGFONTEXW *pelfw = &pelfexdvw->elfEnumLogfontEx;
|
|
ULONG cchMax;
|
|
|
|
// this one does everyting but the lfFaceName;
|
|
|
|
vConvertLogicalFont(pelfexdvw,plf);
|
|
|
|
// do lfFaceName
|
|
|
|
cchMax = cchCutOffStrLen((PSZ) plf->lfFaceName, LF_FACESIZE);
|
|
RtlZeroMemory(pelfw->elfLogFont.lfFaceName , LF_FACESIZE * sizeof(WCHAR) );
|
|
|
|
// translate the face name
|
|
|
|
vToUnicodeN((LPWSTR) pelfw->elfLogFont.lfFaceName,
|
|
cchMax,
|
|
(LPSTR) plf->lfFaceName,
|
|
cchMax);
|
|
if (cchMax == LF_FACESIZE)
|
|
pelfw->elfLogFont.lfFaceName[LF_FACESIZE - 1] = L'\0'; // truncate so NULL will fit
|
|
else
|
|
pelfw->elfLogFont.lfFaceName[cchMax] = L'\0';
|
|
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vConvertLogFontW *
|
|
* *
|
|
* Converts a LOGFONTW to an ENUMLOGFONTEXDVW *
|
|
* *
|
|
* History: *
|
|
* Fri 16-Aug-1991 14:02:05 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vConvertLogFontW(
|
|
ENUMLOGFONTEXDVW *pelfw,
|
|
LOGFONTW *plfw
|
|
)
|
|
{
|
|
// this one does everything except for lfFaceName
|
|
|
|
vConvertLogicalFont(pelfw,plfw);
|
|
|
|
// do lfFaceName
|
|
|
|
RtlCopyMemory(
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfFaceName,
|
|
plfw->lfFaceName,
|
|
LF_FACESIZE * sizeof(WCHAR)
|
|
);
|
|
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vConvertLogicalFont *
|
|
* *
|
|
* Simply copies over all of the fields of a LOGFONTA or LOGFONTW *
|
|
* to the fields of a target ENUMLOGFONTEXDVW. The only exception is *
|
|
* the FaceName which must be dealt with by another routine. *
|
|
* *
|
|
* History: *
|
|
* Fri 16-Aug-1991 14:02:14 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
static
|
|
VOID vConvertLogicalFont(
|
|
ENUMLOGFONTEXDVW *pelfw,
|
|
PVOID pv
|
|
)
|
|
{
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfHeight = ((LOGFONTA*)pv)->lfHeight;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfWidth = ((LOGFONTA*)pv)->lfWidth;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfEscapement = ((LOGFONTA*)pv)->lfEscapement;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfOrientation = ((LOGFONTA*)pv)->lfOrientation;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfWeight = ((LOGFONTA*)pv)->lfWeight;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfItalic = ((LOGFONTA*)pv)->lfItalic;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfUnderline = ((LOGFONTA*)pv)->lfUnderline;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfStrikeOut = ((LOGFONTA*)pv)->lfStrikeOut;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfCharSet = ((LOGFONTA*)pv)->lfCharSet;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfOutPrecision = ((LOGFONTA*)pv)->lfOutPrecision;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfClipPrecision = ((LOGFONTA*)pv)->lfClipPrecision;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfQuality = ((LOGFONTA*)pv)->lfQuality;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfPitchAndFamily = ((LOGFONTA*)pv)->lfPitchAndFamily;
|
|
|
|
// lfFaceName is done in the calling routine
|
|
|
|
pelfw->elfEnumLogfontEx.elfFullName[0] = 0;
|
|
pelfw->elfEnumLogfontEx.elfStyle[0] = 0;
|
|
pelfw->elfEnumLogfontEx.elfScript[0] = 0;
|
|
|
|
pelfw->elfDesignVector.dvReserved = STAMP_DESIGNVECTOR;
|
|
pelfw->elfDesignVector.dvNumAxes = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL bConvertLogFontWToLogFontA(LOGFONTA *plfw, LOGFONTW *plfa)
|
|
*
|
|
* History:
|
|
* 10-Dec-1996 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
|
|
|
|
BOOL bConvertLogFontWToLogFontA(LOGFONTA *plfa, LOGFONTW *plfw)
|
|
{
|
|
ULONG cchMax;
|
|
|
|
plfa->lfHeight = plfw->lfHeight ;
|
|
plfa->lfWidth = plfw->lfWidth ;
|
|
plfa->lfEscapement = plfw->lfEscapement ;
|
|
plfa->lfOrientation = plfw->lfOrientation ;
|
|
plfa->lfWeight = plfw->lfWeight ;
|
|
plfa->lfItalic = plfw->lfItalic ;
|
|
plfa->lfUnderline = plfw->lfUnderline ;
|
|
plfa->lfStrikeOut = plfw->lfStrikeOut ;
|
|
plfa->lfCharSet = plfw->lfCharSet ;
|
|
plfa->lfOutPrecision = plfw->lfOutPrecision ;
|
|
plfa->lfClipPrecision = plfw->lfClipPrecision ;
|
|
plfa->lfQuality = plfw->lfQuality ;
|
|
plfa->lfPitchAndFamily = plfw->lfPitchAndFamily ;
|
|
|
|
cchMax = cwcCutOffStrLen(plfw->lfFaceName, LF_FACESIZE);
|
|
|
|
return (bToASCII_N(plfa->lfFaceName, LF_FACESIZE,
|
|
plfw->lfFaceName, cchMax));
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bConvertEnumLogFontExWToEnumLogFontExA *
|
|
* *
|
|
* Simply copies over all of the fields of ENUMLOGFONTEXDVW *
|
|
* to the fields of a target ENUMLOGFONTEXDVA. It is all wrapped up here *
|
|
* because the ENUMLOGFONTEXDV may move around a bit. This makes *
|
|
* using MOVEMEM a little tricky. *
|
|
* *
|
|
* History: *
|
|
* Fri 16-Aug-1991 14:02:14 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
BOOL bConvertEnumLogFontExWToEnumLogFontExA(ENUMLOGFONTEXA *pelfexa,ENUMLOGFONTEXW *pelfexw)
|
|
{
|
|
ULONG cchMax;
|
|
|
|
if (!bConvertLogFontWToLogFontA(&pelfexa->elfLogFont,
|
|
&pelfexw->elfLogFont))
|
|
{
|
|
// conversion to ascii failed, return error
|
|
|
|
WARNING("bConvertLogFontWToLogFontA failed\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
cchMax = cwcCutOffStrLen(pelfexw->elfFullName, LF_FULLFACESIZE);
|
|
|
|
if(!bToASCII_N(pelfexa->elfFullName, LF_FULLFACESIZE,
|
|
pelfexw->elfFullName, cchMax
|
|
))
|
|
{
|
|
// conversion to ascii failed, return error
|
|
WARNING("bConvertEnumLogFontExWToEnumLogFontExA: bToASCII failed\n");
|
|
return(FALSE);
|
|
}
|
|
pelfexa->elfFullName[LF_FULLFACESIZE-1]=0; // zero terminate
|
|
|
|
|
|
cchMax = cwcCutOffStrLen(pelfexw->elfStyle, LF_FACESIZE);
|
|
|
|
if(!bToASCII_N(pelfexa->elfStyle, LF_FACESIZE,
|
|
pelfexw->elfStyle, cchMax))
|
|
{
|
|
// conversion to ascii failed, return error
|
|
|
|
WARNING("bConvertEnumLogFontExWToEnumLogFontExA: bToASCII failed\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
cchMax = cwcCutOffStrLen(pelfexw->elfScript, LF_FACESIZE);
|
|
|
|
if(!bToASCII_N(pelfexa->elfScript, LF_FACESIZE,
|
|
pelfexw->elfScript, cchMax
|
|
))
|
|
{
|
|
// conversion to ascii failed, return error
|
|
WARNING("bConvertEnumLogFontExWToEnumLogFontExA: bToASCII_N failed\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bConvertEnumLogFontExDv_AtoW *
|
|
* *
|
|
* Simply copies over all of the fields of ENUMLOGFONTEXDVW *
|
|
* to the fields of a target ENUMLOGFONTEXDV. It is all wrapped up here *
|
|
* because the fields may move around a bit. This make *
|
|
* using MOVEMEM a little tricky. *
|
|
* *
|
|
* History: *
|
|
* Fri 16-Aug-1991 14:02:14 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
|
|
VOID vConvertEnumLogFontExDvAtoW(
|
|
ENUMLOGFONTEXDVW *pelfw,
|
|
ENUMLOGFONTEXDVA *pelfa
|
|
)
|
|
{
|
|
ULONG cchMax;
|
|
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfHeight = pelfa->elfEnumLogfontEx.elfLogFont.lfHeight ;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfWidth = pelfa->elfEnumLogfontEx.elfLogFont.lfWidth ;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfEscapement = pelfa->elfEnumLogfontEx.elfLogFont.lfEscapement ;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfOrientation = pelfa->elfEnumLogfontEx.elfLogFont.lfOrientation ;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfWeight = pelfa->elfEnumLogfontEx.elfLogFont.lfWeight ;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfItalic = pelfa->elfEnumLogfontEx.elfLogFont.lfItalic ;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfUnderline = pelfa->elfEnumLogfontEx.elfLogFont.lfUnderline ;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfStrikeOut = pelfa->elfEnumLogfontEx.elfLogFont.lfStrikeOut ;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfCharSet = pelfa->elfEnumLogfontEx.elfLogFont.lfCharSet ;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfOutPrecision = pelfa->elfEnumLogfontEx.elfLogFont.lfOutPrecision ;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfClipPrecision = pelfa->elfEnumLogfontEx.elfLogFont.lfClipPrecision ;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfQuality = pelfa->elfEnumLogfontEx.elfLogFont.lfQuality ;
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfPitchAndFamily = pelfa->elfEnumLogfontEx.elfLogFont.lfPitchAndFamily ;
|
|
|
|
|
|
RtlZeroMemory( pelfw->elfEnumLogfontEx.elfLogFont.lfFaceName , LF_FACESIZE * sizeof(WCHAR) );
|
|
cchMax = cchCutOffStrLen((PSZ)pelfa->elfEnumLogfontEx.elfLogFont.lfFaceName, LF_FACESIZE);
|
|
|
|
vToUnicodeN (
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfFaceName, cchMax,
|
|
pelfa->elfEnumLogfontEx.elfLogFont.lfFaceName, cchMax
|
|
);
|
|
|
|
if (cchMax == LF_FACESIZE)
|
|
{
|
|
// truncate so NULL will fit
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfFaceName[LF_FACESIZE - 1] = L'\0';
|
|
}
|
|
else
|
|
{
|
|
pelfw->elfEnumLogfontEx.elfLogFont.lfFaceName[cchMax] = L'\0';
|
|
}
|
|
|
|
RtlZeroMemory( pelfw->elfEnumLogfontEx.elfFullName , LF_FACESIZE * sizeof(WCHAR) );
|
|
|
|
cchMax = cchCutOffStrLen((PSZ)pelfa->elfEnumLogfontEx.elfFullName, LF_FULLFACESIZE);
|
|
vToUnicodeN (
|
|
pelfw->elfEnumLogfontEx.elfFullName, cchMax,
|
|
pelfa->elfEnumLogfontEx.elfFullName, cchMax
|
|
);
|
|
|
|
if (cchMax == LF_FULLFACESIZE)
|
|
{
|
|
// truncate so NULL will fit
|
|
pelfw->elfEnumLogfontEx.elfFullName[LF_FULLFACESIZE - 1] = L'\0';
|
|
}
|
|
else
|
|
{
|
|
pelfw->elfEnumLogfontEx.elfFullName[cchMax] = L'\0';
|
|
}
|
|
|
|
RtlZeroMemory( pelfw->elfEnumLogfontEx.elfStyle , LF_FACESIZE * sizeof(WCHAR) );
|
|
cchMax = cchCutOffStrLen((PSZ)pelfa->elfEnumLogfontEx.elfStyle, LF_FACESIZE);
|
|
vToUnicodeN (
|
|
pelfw->elfEnumLogfontEx.elfStyle, cchMax,
|
|
pelfa->elfEnumLogfontEx.elfStyle, cchMax
|
|
);
|
|
if (cchMax == LF_FACESIZE)
|
|
{
|
|
// truncate so NULL will fit
|
|
pelfw->elfEnumLogfontEx.elfStyle[LF_FACESIZE - 1] = L'\0';
|
|
}
|
|
else
|
|
{
|
|
pelfw->elfEnumLogfontEx.elfStyle[cchMax] = L'\0';
|
|
}
|
|
|
|
RtlZeroMemory( pelfw->elfEnumLogfontEx.elfScript , LF_FACESIZE * sizeof(WCHAR) );
|
|
cchMax = cchCutOffStrLen((PSZ)pelfa->elfEnumLogfontEx.elfScript, LF_FACESIZE);
|
|
vToUnicodeN (
|
|
pelfw->elfEnumLogfontEx.elfScript, cchMax,
|
|
pelfa->elfEnumLogfontEx.elfScript, cchMax
|
|
);
|
|
if (cchMax == LF_FACESIZE)
|
|
{
|
|
// truncate so NULL will fit
|
|
pelfw->elfEnumLogfontEx.elfScript[LF_FACESIZE - 1] = L'\0';
|
|
}
|
|
else
|
|
{
|
|
pelfw->elfEnumLogfontEx.elfScript[cchMax] = L'\0';
|
|
}
|
|
|
|
// copy minimal amount of stuff from design vector
|
|
|
|
RtlCopyMemory(&pelfw->elfDesignVector,
|
|
&pelfa->elfDesignVector,
|
|
SIZEOFDV(pelfa->elfDesignVector.dvNumAxes));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ulEnumFontsOpen
|
|
*
|
|
* History:
|
|
* 08-Aug-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
ULONG_PTR ulEnumFontsOpen (
|
|
HDC hdc,
|
|
LPWSTR pwszFaceName,
|
|
ULONG lfCharSet,
|
|
ULONG iEnumType, // enumfonts, enumfontfamilies or enumfontfamiliesex
|
|
FLONG flWin31Compat,
|
|
ULONG *pulCount
|
|
)
|
|
{
|
|
|
|
|
|
ULONG cwchFaceName;
|
|
|
|
ULONG cjData;
|
|
|
|
cwchFaceName = (pwszFaceName != (PWSZ) NULL) ? (wcslen(pwszFaceName) + 1) : 0;
|
|
|
|
return NtGdiEnumFontOpen(hdc,iEnumType,flWin31Compat,
|
|
cwchFaceName,pwszFaceName, lfCharSet,pulCount);
|
|
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vEnumFontsClose
|
|
*
|
|
* History:
|
|
* 08-Aug-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vEnumFontsClose (ULONG_PTR ulEnumHandle)
|
|
{
|
|
NtGdiEnumFontClose(ulEnumHandle);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* vConvertAxesListW2AxesListA
|
|
*
|
|
*
|
|
* History:
|
|
* 18-Nov-1996 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
VOID vConvertAxesListW2AxesListA(AXESLISTA *paxlA, AXESLISTW *paxlW)
|
|
{
|
|
ULONG iAxis = 0;
|
|
|
|
paxlA->axlReserved = paxlW->axlReserved;
|
|
paxlA->axlNumAxes = paxlW->axlNumAxes;
|
|
|
|
for (iAxis = 0; iAxis < paxlW->axlNumAxes; iAxis ++)
|
|
{
|
|
ULONG cch;
|
|
|
|
paxlA->axlAxisInfo[iAxis].axMinValue = paxlW->axlAxisInfo[iAxis].axMinValue;
|
|
paxlA->axlAxisInfo[iAxis].axMaxValue = paxlW->axlAxisInfo[iAxis].axMaxValue;
|
|
|
|
cch = cwcCutOffStrLen(paxlW->axlAxisInfo[iAxis].axAxisName,
|
|
MM_MAX_AXES_NAMELEN);
|
|
|
|
bToASCII_N(paxlA->axlAxisInfo[iAxis].axAxisName, MM_MAX_AXES_NAMELEN,
|
|
paxlW->axlAxisInfo[iAxis].axAxisName, cch);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* int iAnsiCallback (
|
|
*
|
|
* History:
|
|
* 28-Jan-1993 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
int iAnsiCallback (
|
|
ENUMFONTDATAW *pefdw,
|
|
ULONG iEnumType,
|
|
FONTENUMPROCA lpFontFunc,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
// full size structures with MAX_MM_AXES arrays
|
|
// on the stack, probably bigger then needed.
|
|
|
|
ENUMLOGFONTEXDVA elfexa ;
|
|
ENUMTEXTMETRICA ntma;
|
|
|
|
NTMW_INTERNAL *pntmi = (NTMW_INTERNAL *)((BYTE*)pefdw + pefdw->dpNtmi);
|
|
DESIGNVECTOR *pdvSrc = &(pefdw->elfexw.elfDesignVector);
|
|
|
|
// copy out design vector
|
|
|
|
RtlCopyMemory(&elfexa.elfDesignVector, pdvSrc, SIZEOFDV(pdvSrc->dvNumAxes));
|
|
|
|
// convert AXESLIST to ansi
|
|
|
|
vConvertAxesListW2AxesListA(&ntma.etmAxesList, &pntmi->entmw.etmAxesList);
|
|
|
|
// Convert ENUMLOGFONTEX
|
|
|
|
if (!bConvertEnumLogFontExWToEnumLogFontExA(&elfexa.elfEnumLogfontEx, &pefdw->elfexw.elfEnumLogfontEx))
|
|
{
|
|
WARNING("gdi32!EFCallbackWtoA(): ENUMLOGFONT conversion failed\n");
|
|
return 0;
|
|
}
|
|
|
|
// Convert NEWTEXTMETRIC.
|
|
|
|
vNewTextMetricExWToNewTextMetricExA(&ntma.etmNewTextMetricEx, pntmi);
|
|
|
|
return lpFontFunc(
|
|
(LOGFONTA *)&elfexa,
|
|
(TEXTMETRICA *)&ntma,
|
|
pefdw->flType,
|
|
lParam
|
|
);
|
|
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* iScaleEnum
|
|
*
|
|
* The Win95 Universal printer driver (UNIDRV) has scalable fonts, but does
|
|
* not set the scalable capability flags in TEXTCAPS. Instead, it enumerates
|
|
* back scalable printer fonts at several different (fixed) point sizes.
|
|
*
|
|
* We support this by detecting, on the server-side, when we are enumerating
|
|
* a scalable printer and setting the ENUMFONT_SCALE_HACK flag in the flType
|
|
* field of the ENUMFONTDATAW structure.
|
|
*
|
|
* For more details, refer to the Win95 sources found on \\tal\msdos in
|
|
* \src\win\drivers\printer\universa\unidrv\enumobj.c. Specifically, the
|
|
* function of interest is UniEnumDFonts().
|
|
*
|
|
* Returns:
|
|
* Value returned by callback if successful, 0 otherwise.
|
|
*
|
|
* History:
|
|
* 08-Jan-1996 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
#define EFI_UNICODE 1
|
|
|
|
CONST int giEnumPointList[] =
|
|
{6, 8, 10, 11, 12, 14, 18, 24, 30, 36, 48};
|
|
|
|
int iScaleEnum(
|
|
HDC hdc,
|
|
FONTENUMPROCW lpFontFunc,
|
|
ENUMFONTDATAW *pefd,
|
|
LPARAM lParam,
|
|
ULONG iEnumType,
|
|
FLONG fl
|
|
)
|
|
{
|
|
int i, cPointSizes = sizeof(giEnumPointList) / sizeof(int);
|
|
int iHeight;
|
|
int iXdpi, iYdpi;
|
|
int iRet;
|
|
|
|
// make the structure on the stack is DWORD aligned
|
|
|
|
DWORD efd[CJ_EFDW0/sizeof(DWORD)];
|
|
|
|
ENUMFONTDATAW *pefdLocal = (ENUMFONTDATAW *)efd;
|
|
|
|
iXdpi = GetDeviceCaps(hdc, LOGPIXELSX);
|
|
iYdpi = GetDeviceCaps(hdc, LOGPIXELSY);
|
|
|
|
for (i = 0; i < cPointSizes; i++)
|
|
{
|
|
// this has to be true because for these device fonts no
|
|
// extra mm data will ever be needed, only logfont and ntmi
|
|
|
|
NTMW_INTERNAL *pntmi, *pntmiDef;
|
|
TEXTMETRICW *ptmw, *ptmwDef;
|
|
LOGFONTW *plfw, *plfwDef;
|
|
|
|
ASSERTGDI(pefd->cjEfdw <= sizeof(efd), "iScaleEnum size problem\n");
|
|
RtlCopyMemory(pefdLocal, pefd, pefd->cjEfdw);
|
|
|
|
pntmi = (NTMW_INTERNAL *)((BYTE*)pefdLocal + pefdLocal->dpNtmi);
|
|
pntmiDef = (NTMW_INTERNAL *)((BYTE*)pefd + pefd->dpNtmi);
|
|
ptmw = (TEXTMETRICW *) &pntmi->entmw.etmNewTextMetricEx;
|
|
ptmwDef = (TEXTMETRICW *) &pntmiDef->entmw.etmNewTextMetricEx;
|
|
plfw = (LOGFONTW *) &pefdLocal->elfexw;
|
|
plfwDef = (LOGFONTW *) &pefd->elfexw;
|
|
|
|
// Scale TEXTMETRIC to match enumerated height.
|
|
|
|
iHeight = MulDiv(giEnumPointList[i], iYdpi, 72);
|
|
ptmw->tmHeight = iHeight;
|
|
ptmw->tmAscent = MulDiv(ptmwDef->tmAscent, iHeight, ptmwDef->tmHeight);
|
|
ptmw->tmInternalLeading = MulDiv(ptmwDef->tmInternalLeading, iHeight,
|
|
ptmwDef->tmHeight);
|
|
ptmw->tmExternalLeading = MulDiv(ptmwDef->tmExternalLeading, iHeight,
|
|
ptmwDef->tmHeight);
|
|
ptmw->tmAveCharWidth = MulDiv(ptmwDef->tmAveCharWidth, iHeight,
|
|
ptmwDef->tmHeight);
|
|
ptmw->tmMaxCharWidth = MulDiv(ptmwDef->tmMaxCharWidth, iHeight,
|
|
ptmwDef->tmHeight);
|
|
|
|
// Scale LOGFONT to match enumerated height.
|
|
|
|
plfw->lfHeight = MulDiv(plfwDef->lfHeight, iHeight, ptmwDef->tmHeight);
|
|
plfw->lfWidth = MulDiv(plfwDef->lfWidth, iHeight, ptmwDef->tmHeight);
|
|
|
|
// Invoke the callback function.
|
|
|
|
if (fl & EFI_UNICODE)
|
|
{
|
|
iRet = lpFontFunc(
|
|
(LOGFONTW *) plfw,
|
|
(TEXTMETRICW *) ptmw,
|
|
pefd->flType,
|
|
lParam );
|
|
}
|
|
else
|
|
{
|
|
iRet = iAnsiCallback (pefdLocal,
|
|
iEnumType,
|
|
(FONTENUMPROCA)lpFontFunc,
|
|
lParam);
|
|
}
|
|
|
|
// Break out early if callback returned error.
|
|
|
|
if (!iRet)
|
|
break;
|
|
}
|
|
|
|
return iRet;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* EnumFontsInternalW
|
|
*
|
|
* History:
|
|
* Mon 17-Aug-1998 -by- Bodin Dresevic [BodinD]
|
|
* update: since 1992 this function was rewritten quite a few times
|
|
*
|
|
* 08-Aug-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int WINAPI EnumFontsInternalW (
|
|
HDC hdc, // enumerate for this device
|
|
LPCWSTR pwszFaceName, // use this family name (but Windows erroneously calls in face name *sigh*)
|
|
ULONG lfCharSet, // only used with EnumFontFamiliesEx,
|
|
FONTENUMPROCW lpFontFunc, // callback
|
|
LPARAM lParam, // user defined data
|
|
ULONG iEnumType, // who is calling....
|
|
FLONG fl
|
|
)
|
|
{
|
|
BOOL bMore; // set TRUE if more data to process
|
|
ULONG_PTR ulEnumID; // server side font enumeration handle
|
|
int iRet = 1; // return value from callback
|
|
ULONG cjEfdw; // capacity of memory data window
|
|
ULONG cjEfdwRet; // size of data returned
|
|
|
|
PENUMFONTDATAW pefdw; // font enumeration data buffer
|
|
PENUMFONTDATAW pefdwScan; // use to parse data buffer
|
|
PENUMFONTDATAW pefdwEnd; // limit of data buffer
|
|
|
|
FLONG flWin31Compat; // Win3.1 app hack backward compatibility flags
|
|
|
|
// Get the compatibility flags.
|
|
|
|
flWin31Compat = (FLONG) GetAppCompatFlags(NULL);
|
|
|
|
// Open a font enumeration. The font enumeration is uniquely identified
|
|
// by the identifier returned by ulEnumFontOpen().
|
|
|
|
ulEnumID = ulEnumFontsOpen(
|
|
hdc, (LPWSTR)pwszFaceName, lfCharSet,
|
|
iEnumType, flWin31Compat, &cjEfdw);
|
|
|
|
if (!ulEnumID)
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_HANDLE);
|
|
return 0;
|
|
}
|
|
|
|
if (cjEfdw == 0)
|
|
{
|
|
vEnumFontsClose(ulEnumID);
|
|
return iRet;
|
|
}
|
|
|
|
// alloc memory
|
|
|
|
if (!(pefdw = (PENUMFONTDATAW) LOCALALLOC(cjEfdw)))
|
|
{
|
|
WARNING("gdi32!EnumFontsInternalW(): could not allocate memory for enumeration\n");
|
|
GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
vEnumFontsClose(ulEnumID);
|
|
return 0;
|
|
}
|
|
|
|
if (NtGdiEnumFontChunk(hdc,ulEnumID,cjEfdw,&cjEfdwRet,pefdw))
|
|
{
|
|
|
|
// Scan through the data buffer.
|
|
|
|
ASSERTGDI(cjEfdwRet <= cjEfdw, "NtGdiEnumFontChunk problem\n");
|
|
|
|
pefdwScan = pefdw;
|
|
pefdwEnd = (ENUMFONTDATAW *)((BYTE *)pefdw + cjEfdwRet);
|
|
|
|
while (pefdwScan < pefdwEnd)
|
|
{
|
|
// GACF_ENUMTTNOTDEVICE backward compatibility hack.
|
|
// If this flag is set, we need to mask out the DEVICE_FONTTYPE
|
|
// if this is a TrueType font.
|
|
|
|
if ( (flWin31Compat & GACF_ENUMTTNOTDEVICE)
|
|
&& (pefdwScan->flType & TRUETYPE_FONTTYPE) )
|
|
pefdwScan->flType &= ~DEVICE_FONTTYPE;
|
|
|
|
// The Win95 UNIDRV printer driver enumerates scalable fonts at
|
|
// several different sizes. The server sets the ENUMFONT_SCALE_HACK
|
|
// flag if we need to emulate that behavior.
|
|
|
|
if ( pwszFaceName && (pefdwScan->flType & ENUMFONT_SCALE_HACK))
|
|
{
|
|
// Clear the hack flag before calling. Caller doesn't need to
|
|
// see this (internal use only) flag.
|
|
|
|
pefdwScan->flType &= ~ENUMFONT_SCALE_HACK;
|
|
|
|
iRet = iScaleEnum(hdc, lpFontFunc, pefdwScan, lParam,
|
|
iEnumType, fl);
|
|
|
|
}
|
|
else
|
|
{
|
|
// Do the callback with data pointed to by pefdwScan.
|
|
|
|
if (fl & EFI_UNICODE)
|
|
{
|
|
NTMW_INTERNAL *pntmi =
|
|
(NTMW_INTERNAL *)((BYTE*)pefdwScan + pefdwScan->dpNtmi);
|
|
|
|
iRet = lpFontFunc(
|
|
(LOGFONTW *)&pefdwScan->elfexw,
|
|
(TEXTMETRICW *)&pntmi->entmw,
|
|
pefdwScan->flType,
|
|
lParam );
|
|
|
|
}
|
|
else
|
|
{
|
|
iRet = iAnsiCallback (pefdwScan,
|
|
iEnumType,
|
|
(FONTENUMPROCA)lpFontFunc,
|
|
lParam);
|
|
|
|
}
|
|
}
|
|
|
|
// Break out of for-loop if callback returned 0.
|
|
|
|
if (!iRet)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Next ENUMFONTDATAW.
|
|
|
|
pefdwScan = (ENUMFONTDATAW *)((BYTE *)pefdwScan + pefdwScan->cjEfdw);
|
|
}
|
|
}
|
|
|
|
// Deallocate font enumeration data.
|
|
|
|
LOCALFREE(pefdw);
|
|
|
|
// Remember to close the font enumeration handle.
|
|
|
|
vEnumFontsClose(ulEnumID);
|
|
|
|
// Leave.
|
|
|
|
return iRet;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* EnumFontsW
|
|
*
|
|
* History:
|
|
* 08-Aug-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int WINAPI EnumFontsW
|
|
(
|
|
HDC hdc, // enumerate for this device
|
|
LPCWSTR pwszFaceName, // use this family name (but Windows erroneously calls in face name *sigh*)
|
|
FONTENUMPROCW lpFontFunc, // callback
|
|
LPARAM lParam // user defined data
|
|
)
|
|
{
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
return EnumFontsInternalW(
|
|
hdc,
|
|
pwszFaceName,
|
|
DEFAULT_CHARSET,
|
|
lpFontFunc,
|
|
lParam,
|
|
TYPE_ENUMFONTS,
|
|
EFI_UNICODE
|
|
);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* EnumFontFamiliesW
|
|
*
|
|
* History:
|
|
* 08-Aug-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int WINAPI EnumFontFamiliesW
|
|
(
|
|
HDC hdc, // enumerate for this device
|
|
LPCWSTR pwszFaceName, // use this family name (but Windows erroneously calls in face name *sigh*)
|
|
FONTENUMPROCW lpFontFunc, // callback
|
|
LPARAM lParam // user defined data
|
|
)
|
|
{
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
return EnumFontsInternalW(
|
|
hdc,
|
|
pwszFaceName,
|
|
DEFAULT_CHARSET,
|
|
lpFontFunc,
|
|
lParam,
|
|
TYPE_ENUMFONTFAMILIES,
|
|
EFI_UNICODE
|
|
);
|
|
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* EnumFontFamiliesExW
|
|
*
|
|
* History:
|
|
*
|
|
* Mon 10-Jul-1995 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it:
|
|
*
|
|
\**************************************************************************/
|
|
|
|
int WINAPI EnumFontFamiliesExW
|
|
(
|
|
HDC hdc,
|
|
LPLOGFONTW plf,
|
|
FONTENUMPROCW lpFontFunc,
|
|
LPARAM lParam,
|
|
DWORD dw
|
|
)
|
|
{
|
|
PWSZ pwszFaceName = NULL;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
if (plf && (plf->lfFaceName[0] != L'\0'))
|
|
pwszFaceName = plf->lfFaceName;
|
|
|
|
|
|
return EnumFontsInternalW(
|
|
hdc,
|
|
pwszFaceName,
|
|
plf ? plf->lfCharSet : DEFAULT_CHARSET,
|
|
lpFontFunc,
|
|
lParam,
|
|
TYPE_ENUMFONTFAMILIESEX,
|
|
EFI_UNICODE
|
|
);
|
|
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* int EnumFontsInternalA
|
|
*
|
|
* History:
|
|
* 28-Jan-1993 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int EnumFontsInternalA
|
|
(
|
|
HDC hdc, // enumerate for this device
|
|
LPCSTR pszFaceName, // use this family name (but Windows erroneously calls in face name *sigh*),
|
|
ULONG lfCharSet,
|
|
FONTENUMPROCA lpFontFunc, // callback
|
|
LPARAM lParam, // user defined data
|
|
ULONG iEnumType
|
|
)
|
|
{
|
|
PWSZ pwszFaceName;
|
|
int iRet;
|
|
ULONG cchFaceName;
|
|
|
|
// If a string was passed in, we need to convert it to UNICODE.
|
|
|
|
if ( pszFaceName != (PSZ) NULL )
|
|
{
|
|
// Allocate memory for Unicode string.
|
|
|
|
cchFaceName = lstrlenA(pszFaceName) + 1;
|
|
|
|
if ( (pwszFaceName = (PWSZ) LOCALALLOC(cchFaceName * sizeof(WCHAR))) == (PWSZ) NULL )
|
|
{
|
|
WARNING("gdi32!EnumFontsA(): could not allocate memory for Unicode string\n");
|
|
GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return 0;
|
|
}
|
|
|
|
// Convert string to Unicode.
|
|
|
|
vToUnicodeN (
|
|
pwszFaceName,
|
|
cchFaceName,
|
|
pszFaceName,
|
|
cchFaceName
|
|
);
|
|
}
|
|
|
|
// Otherwise, keep it NULL.
|
|
|
|
else
|
|
{
|
|
pwszFaceName = (PWSZ) NULL;
|
|
}
|
|
|
|
// Call Unicode version.
|
|
|
|
iRet = EnumFontsInternalW(
|
|
hdc,
|
|
pwszFaceName,
|
|
lfCharSet,
|
|
(FONTENUMPROCW)lpFontFunc,
|
|
lParam,
|
|
iEnumType,
|
|
0 // not unicode
|
|
);
|
|
|
|
// Release Unicode string buffer.
|
|
|
|
if ( pwszFaceName != (PWSZ) NULL )
|
|
{
|
|
LOCALFREE(pwszFaceName);
|
|
}
|
|
|
|
return iRet;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* int WINAPI EnumFontsA
|
|
*
|
|
*
|
|
* History:
|
|
* 28-Jan-1993 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int WINAPI EnumFontsA
|
|
(
|
|
HDC hdc, // enumerate for this device
|
|
LPCSTR pszFaceName, // use this family name (but Windows erroneously calls in face name *sigh*)
|
|
FONTENUMPROCA lpFontFunc, // callback
|
|
LPARAM lParam // user defined data
|
|
)
|
|
{
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
return EnumFontsInternalA (
|
|
hdc,
|
|
pszFaceName,
|
|
DEFAULT_CHARSET,
|
|
lpFontFunc,
|
|
lParam,
|
|
TYPE_ENUMFONTS
|
|
);
|
|
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* EnumFontFamiliesA
|
|
*
|
|
* History:
|
|
* 28-Jan-1993 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int WINAPI EnumFontFamiliesA
|
|
(
|
|
HDC hdc, // enumerate for this device
|
|
LPCSTR pszFaceName, // use this family name (but Windows erroneously calls in face name *sigh*)
|
|
FONTENUMPROCA lpFontFunc, // callback
|
|
LPARAM lParam // user defined data
|
|
)
|
|
{
|
|
return EnumFontsInternalA (
|
|
hdc, // enumerate for this device
|
|
pszFaceName, // use this family name (but Windows erroneously calls in face name *sigh*)
|
|
DEFAULT_CHARSET,
|
|
lpFontFunc, // callback
|
|
lParam, // user defined data
|
|
TYPE_ENUMFONTFAMILIES
|
|
);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* EnumFontFamiliesExA
|
|
*
|
|
* History:
|
|
*
|
|
* Mon 10-Jul-1995 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it:
|
|
*
|
|
\**************************************************************************/
|
|
|
|
int WINAPI EnumFontFamiliesExA
|
|
(
|
|
HDC hdc,
|
|
LPLOGFONTA plf,
|
|
FONTENUMPROCA lpFontFunc,
|
|
LPARAM lParam,
|
|
DWORD dw
|
|
)
|
|
{
|
|
LPSTR pszFaceName = NULL;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
if (plf && (plf->lfFaceName[0] != '\0'))
|
|
pszFaceName = plf->lfFaceName;
|
|
|
|
return EnumFontsInternalA (
|
|
hdc, // enumerate for this device
|
|
pszFaceName, // use this family name (but Windows erroneously calls in face name *sigh*)
|
|
plf ? plf->lfCharSet : DEFAULT_CHARSET,
|
|
lpFontFunc, // callback
|
|
lParam, // user defined data
|
|
TYPE_ENUMFONTFAMILIESEX
|
|
);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetFontResourceInfoW
|
|
*
|
|
* Client side stub.
|
|
*
|
|
* History:
|
|
* 2-Sep-1993 -by- Gerrit van Wingerden [gerritv]
|
|
* Made this a "W" function.
|
|
* 15-Jul-1991 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
BOOL GetFontResourceInfoW (
|
|
LPWSTR lpPathname,
|
|
LPDWORD lpBytes,
|
|
LPVOID lpBuffer,
|
|
DWORD iType)
|
|
{
|
|
ULONG cjBuffer = *lpBytes;
|
|
int cRet = 0;
|
|
FLONG flEmbed;
|
|
DWORD dwPidTid;
|
|
|
|
if ( (lpPathname != NULL) &&
|
|
((cjBuffer == 0) || (lpBuffer != NULL)) )
|
|
{
|
|
if( iType == GFRI_TTFILENAME )
|
|
{
|
|
WCHAR awcPathname[MAX_PATH];
|
|
WCHAR awcTTF[MAX_PATH];
|
|
|
|
if (bMakePathNameW(awcPathname, lpPathname, NULL, NULL))
|
|
{
|
|
ULONG size;
|
|
|
|
if (size = cGetTTFFromFOT(awcPathname, MAX_PATH, awcTTF, NULL, &flEmbed, &dwPidTid, TRUE))
|
|
{
|
|
// For the case of GFRI_TTFILENAME, the file need not be already
|
|
// loaded. Which means a PFF may or may not exist for this file.
|
|
|
|
*lpBytes = size * sizeof(WCHAR);
|
|
|
|
if (cjBuffer)
|
|
{
|
|
// Also return the name if it fits
|
|
|
|
// if awcPathnmae points to a bad FOT file, awcTTF will contain the same FOT file name
|
|
// passed to the cGetTTTFromFOT. In this case, we want to return FALSE.
|
|
|
|
if ((cjBuffer >= *lpBytes) &&
|
|
((size < 5) || _wcsicmp(&awcTTF[size-5], L".FOT")))
|
|
{
|
|
RtlMoveMemory(lpBuffer, awcTTF, *lpBytes);
|
|
}
|
|
else
|
|
{
|
|
// Buffer is too small - error !
|
|
// or bad FOT file, no TTF file
|
|
|
|
*lpBytes = 0;
|
|
}
|
|
}
|
|
|
|
cRet = (*lpBytes != 0);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// First get a real NT path Name before calling to the kernel
|
|
|
|
ULONG cwc,cFiles;
|
|
FLONG fl = 0; // essential initialization
|
|
WCHAR *pwszNtPath;
|
|
|
|
if (pwszNtPath = pwszAllocNtMultiplePath(lpPathname,
|
|
&fl,
|
|
&cwc,
|
|
&cFiles,
|
|
FALSE,
|
|
&dwPidTid,
|
|
TRUE))
|
|
{
|
|
cRet = NtGdiGetFontResourceInfoInternalW(
|
|
pwszNtPath,
|
|
cwc,
|
|
cFiles,
|
|
cjBuffer,
|
|
lpBytes,
|
|
lpBuffer,
|
|
iType);
|
|
LOCALFREE(pwszNtPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
return( cRet );
|
|
}
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bMakePathNameW (PWSZ pwszDst, PWSZ pwszSrc, PWSZ *ppwszFilePart)
|
|
*
|
|
* Converts the filename pszSrc into a fully qualified pathname pszDst.
|
|
* The parameter pszDst must point to a WCHAR buffer at least
|
|
* MAX_PATH*sizeof(WCHAR) bytes in size.
|
|
*
|
|
* An attempt is made find the file first in the new win95 directory
|
|
* %windows%\fonts (which also is the first directory in secure font path,
|
|
* if one is defined) and then we do the old fashioned windows stuff
|
|
* where SearchPathW searches directories in usual order
|
|
*
|
|
* ppwszFilePart is set to point to the last component of the pathname (i.e.,
|
|
* the filename part) in pwszDst. If this is null it is ignored.
|
|
*
|
|
* Returns:
|
|
* TRUE if sucessful, FALSE if an error occurs.
|
|
*
|
|
* History:
|
|
* Mon 02-Oct-1995 -by- Bodin Dresevic [BodinD]
|
|
* update: added font path stuff
|
|
* 30-Sep-1991 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
|
|
BOOL bMakePathNameW (
|
|
WCHAR *pwszDst,
|
|
WCHAR *pwszSrc,
|
|
WCHAR **ppwszFilePart,
|
|
FLONG *pfl
|
|
)
|
|
{
|
|
WCHAR * pwszD, * pwszS, * pwszF;
|
|
BOOL bOk;
|
|
ULONG ulPathLength = 0; // essential to initialize
|
|
ULONG cwcSystem;
|
|
ULONG cwcDst;
|
|
WCHAR *pwcTmp;
|
|
|
|
if (pfl)
|
|
*pfl = 0;
|
|
|
|
if (ppwszFilePart == NULL)
|
|
{
|
|
ppwszFilePart = &pwszF;
|
|
}
|
|
|
|
// init unicode path for the fonts directory, %windir%\fonts that is:
|
|
// This is always defined in NT versions > 3.51.
|
|
|
|
ENTERCRITICALSECTION(&semLocal);
|
|
bOk = bInitSystemAndFontsDirectoriesW(&gpwcSystemDir, &gpwcFontsDir);
|
|
LEAVECRITICALSECTION(&semLocal);
|
|
|
|
// bInitFontDirectoryW logs the error code and prints warning, just exit
|
|
|
|
if (!bOk)
|
|
return FALSE;
|
|
|
|
ASSERTGDI(gpwcFontsDir, "gpwcFontsDir not initialized\n");
|
|
|
|
// if relative path
|
|
|
|
if
|
|
(
|
|
(pwszSrc[0] != L'\\') &&
|
|
!((pwszSrc[1] == L':') && (pwszSrc[2] == L'\\'))
|
|
)
|
|
{
|
|
if (pfl)
|
|
{
|
|
*pfl |= FONT_RELATIVE_PATH;
|
|
}
|
|
|
|
// find out if the font file is in %windir%\fonts
|
|
|
|
ulPathLength = SearchPathW (
|
|
gpwcFontsDir,
|
|
pwszSrc,
|
|
NULL,
|
|
MAX_PATH,
|
|
pwszDst,
|
|
ppwszFilePart);
|
|
|
|
if (ulPathLength >= MAX_PATH)
|
|
{
|
|
WARNING("bMakePathNameW: path from SearchPathW is too long\n");
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef DEBUG_PATH
|
|
DbgPrint("SPW1: pwszSrc = %ws\n", pwszSrc);
|
|
if (ulPathLength)
|
|
DbgPrint("SPW1: pwszDst = %ws\n", pwszDst);
|
|
#endif // DEBUG_PATH
|
|
}
|
|
|
|
// Search for file using default windows path and return full pathname.
|
|
// We will only do so if we did not already find the font in the
|
|
// %windir%\fonts directory or if pswzSrc points to the full path
|
|
// in which case search path is ignored
|
|
|
|
if (ulPathLength == 0)
|
|
{
|
|
if (ulPathLength = SearchPathW (
|
|
NULL,
|
|
pwszSrc,
|
|
NULL,
|
|
MAX_PATH,
|
|
pwszDst,
|
|
ppwszFilePart))
|
|
{
|
|
if (ulPathLength >= MAX_PATH)
|
|
{
|
|
WARNING("bMakePathNameW: path from SearchPathW is too long\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// let us figure it out if the font is in the
|
|
// system directory, or somewhere else along the path:
|
|
|
|
if (pfl)
|
|
{
|
|
cwcSystem = wcslen(gpwcSystemDir);
|
|
cwcDst = wcslen(pwszDst);
|
|
|
|
if (cwcDst > (cwcSystem + 1)) // + 1 for L'\\'
|
|
{
|
|
if (!_wcsnicmp(pwszDst, gpwcSystemDir, cwcSystem))
|
|
{
|
|
pwcTmp = &pwszDst[cwcSystem];
|
|
if (*pwcTmp == L'\\')
|
|
{
|
|
pwcTmp++; // skip it and see if there are any more of these in pszDst
|
|
for (;(pwcTmp < &pwszDst[cwcDst]) && (*pwcTmp != L'\\'); pwcTmp++)
|
|
;
|
|
if (*pwcTmp != L'\\')
|
|
*pfl |= FONT_IN_SYSTEM_DIR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef DEBUG_PATH
|
|
DbgPrint("SPW2: pwszSrc = %ws\n", pwszSrc);
|
|
if (ulPathLength)
|
|
DbgPrint("SPW2: pwszDst = %ws\n", pwszDst);
|
|
#endif // DEBUG_PATH
|
|
}
|
|
else
|
|
{
|
|
if (pfl)
|
|
{
|
|
*pfl |= FONT_IN_FONTS_DIR;
|
|
}
|
|
}
|
|
|
|
// finally we test to see if this is one of these fonts that were moved
|
|
// by setup during upgrade from system to fonts dir,
|
|
// but the registry entry for that font
|
|
// contained full path to system so that the code above would not have found
|
|
// this font. This code is only called by font sweeper as signified by
|
|
// pfl != NULL. More desription follows below
|
|
|
|
// This part of routine handles the upgrade situation where NT 3.51 font applet
|
|
// wrote the full path of the .fot file that lives in %windir%\system
|
|
// directory in the registry. This redundant situation happens
|
|
// when tt fonts are installed under 3.51 but ttf's are not copied
|
|
// to %windir%\system directory. Some ill behaved apps also write the
|
|
// full path of .fot files in the system directory in the registry.
|
|
// On upgrade for 4.0 the system setup copies all .fot files from
|
|
// system to fonts directory. bMakePathNameW will therefore fail to find
|
|
// the fot file because the file was moved to fonts by setup AND full,
|
|
// no longer correct path to fot file, is passed to this routine.
|
|
// That is why we try to find out if the full path is the one
|
|
// describing system dir and if so, retry to find .fot in fonts dir.
|
|
|
|
if (pfl && (ulPathLength == 0))
|
|
{
|
|
// first check if the full path to .fot file points to the
|
|
// file which USED to be in the system directory.
|
|
|
|
ULONG cwcFileName = wcslen(pwszSrc);
|
|
cwcSystem = wcslen(gpwcSystemDir);
|
|
|
|
if ((cwcFileName + 1) > cwcSystem) // + 1 for L'\\'
|
|
{
|
|
if (!_wcsnicmp(gpwcSystemDir, pwszSrc, cwcSystem))
|
|
{
|
|
pwszSrc += cwcSystem;
|
|
if (pwszSrc[0] == L'\\')
|
|
{
|
|
pwszSrc += 1; // skip L'\\'
|
|
|
|
// make sure there are no more directory separators L'\\' in
|
|
// the remaining path, ie. that this is indeed a relative path
|
|
|
|
for (pwcTmp = pwszSrc; *pwcTmp != L'\0'; pwcTmp++)
|
|
if (*pwcTmp == L'\\')
|
|
break;
|
|
|
|
// now check if the .fot file has been moved to fonts dir
|
|
|
|
if (*pwcTmp == L'\0')
|
|
{
|
|
ulPathLength = SearchPathW (
|
|
gpwcFontsDir,
|
|
pwszSrc,
|
|
NULL,
|
|
MAX_PATH,
|
|
pwszDst,
|
|
ppwszFilePart);
|
|
|
|
if (ulPathLength >= MAX_PATH)
|
|
{
|
|
WARNING("bMakePathNameW: path from SearchPathW is too long\n");
|
|
return FALSE;
|
|
}
|
|
|
|
if (ulPathLength)
|
|
*pfl |= FONT_IN_FONTS_DIR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If search was successful return TRUE:
|
|
|
|
return (ulPathLength != 0);
|
|
}
|
|
|
|
|
|
/******************************Private*Routine******************************\
|
|
*
|
|
* BOOL IsWinPERemoteBootDrive( PCWSTR Drive )
|
|
*
|
|
* History:
|
|
* July 19, 2001. acosma - Added routine.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
static BOOL IsWinPERemoteBootDrive( PCWSTR Drive )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds out if we are currently running on WinPE booted remotely.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return value:
|
|
|
|
TRUE if this is a WinPE remote boot otherwise FALSE.
|
|
|
|
--*/
|
|
{
|
|
static BOOL Result = FALSE;
|
|
static BOOL Initialized = FALSE;
|
|
static WCHAR WindowsDrive = 0;
|
|
|
|
|
|
if (!Initialized) {
|
|
WCHAR WindowsDir[MAX_PATH] = {0};
|
|
|
|
Initialized = TRUE;
|
|
|
|
if (GetWindowsDirectoryW(WindowsDir, sizeof(WindowsDir)/sizeof(WCHAR))) {
|
|
WindowsDir[3] = 0;
|
|
|
|
WindowsDrive = WindowsDir[0];
|
|
|
|
//
|
|
// If the drive type is DRIVE_REMOTE then we have booted from
|
|
// network.
|
|
//
|
|
Result = (GetDriveTypeW(WindowsDir) == DRIVE_REMOTE);
|
|
|
|
if (Result) {
|
|
OBJECT_ATTRIBUTES Obja;
|
|
UNICODE_STRING KeyName;
|
|
HKEY hKey = NULL;
|
|
NTSTATUS Status;
|
|
|
|
RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\MiniNT");
|
|
InitializeObjectAttributes(&Obja, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
|
|
|
Status = NtOpenKey(&hKey, KEY_READ, &Obja);
|
|
|
|
if ( NT_SUCCESS (Status) ) {
|
|
Result = TRUE;
|
|
NtClose(hKey);
|
|
} else {
|
|
Result = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Is this WinPE remote boot and is the passed in drive valid & its windows drive?
|
|
//
|
|
return (Result && Drive && Drive[0] && (WindowsDrive == Drive[0]));
|
|
}
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL bFileIsOnTheHardDrive(PWCHAR pwszFullPathName)
|
|
*
|
|
* History:
|
|
* Fri 22-Jul-1994 -by- Gerrit van Wingerden [gerritv]
|
|
* Stole it from BodinD
|
|
\**************************************************************************/
|
|
|
|
|
|
|
|
BOOL bFileIsOnTheHardDrive(WCHAR *inputpwszFullPathName)
|
|
{
|
|
const WCHAR * pwszFullPathName = inputpwszFullPathName;
|
|
WCHAR awcDrive[4];
|
|
|
|
if (pwszFullPathName[1] != (WCHAR)':')
|
|
{
|
|
// the file path has the form \\foo\goo. Even though this could be
|
|
// a share on the local hard drive, this is not very likely. It is ok
|
|
// for the sake of simplicity to consider this a remote drive.
|
|
// The only side effect of this is that in this unlikely case the font
|
|
// would get unloaded at logoff and reloaded at logon time
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// make a zero terminated string with drive string
|
|
// to be feed into GetDriveType api. The string has to have the form: "x:\"
|
|
|
|
awcDrive[0] = pwszFullPathName[0]; // COPY DRIVE LETTER
|
|
awcDrive[1] = pwszFullPathName[1]; // COPY ':'
|
|
awcDrive[2] = (CHAR)'\\'; // obvious
|
|
awcDrive[3] = (CHAR)'\0'; // zero terminate
|
|
|
|
if ( IsWinPERemoteBootDrive(awcDrive) )
|
|
{
|
|
// If we are in WinPE and this is a remote boot then always return true
|
|
// to this so that we don't wait until logon to load fonts, since in
|
|
// WinPE we don't logon, and the system drive is a net drive but we
|
|
// already have credentials to access it since the OS is booting from
|
|
// there
|
|
// Doing this after checking for the \\foo\goo so that we don't accidentaly
|
|
// try to load fonts that ARE really on some net share in the
|
|
// Remote boot WinPE case.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
// for this pupose, only net drives are not considered hard drives
|
|
// so that we can boot of Bernoulli removable drives
|
|
|
|
switch (GetDriveTypeW((LPCWSTR)awcDrive))
|
|
{
|
|
case DRIVE_REMOVABLE:
|
|
case DRIVE_FIXED:
|
|
case DRIVE_CDROM:
|
|
case DRIVE_RAMDISK:
|
|
return 1;
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
|
|
static
|
|
WCHAR * pwszAllocNtMultiplePath(
|
|
LPWSTR pwszFileName,
|
|
FLONG *pfl,
|
|
ULONG *pcwc,
|
|
ULONG *pcFiles,
|
|
BOOL bAddFR, // called by add or remove fr
|
|
DWORD *pdwPidTid, // PID/TID for embedded font
|
|
BOOL bChkFOT
|
|
)
|
|
{
|
|
|
|
BOOL bDoIt = FALSE;
|
|
BOOL bReturn = TRUE;
|
|
ULONG cwc;
|
|
ULONG iFile;
|
|
ULONG cFiles = 1; // number of paths separated by | separator
|
|
WCHAR *pwszOneFile;
|
|
WCHAR *pwchMem;
|
|
WCHAR *pwcNtPaths;
|
|
FLONG flTmp = 0; // essential initialization
|
|
FLONG fl = (pfl ? *pfl : 0); // essential initialization
|
|
FLONG flEmbed = 0;
|
|
UINT cbCombinedPaths = 0;
|
|
|
|
// scan the string to figure out how many individual file names are
|
|
// in the input string:
|
|
|
|
for (pwszOneFile = pwszFileName; *pwszOneFile; pwszOneFile++)
|
|
{
|
|
if (*pwszOneFile == PATH_SEPARATOR)
|
|
cFiles++;
|
|
}
|
|
|
|
// allocate memory where NtPathNames are going to be stored:
|
|
// we allow only file names with MAX_PATH-1 characters or less
|
|
// after all the path transformations
|
|
cbCombinedPaths = cFiles * sizeof(WCHAR) * MAX_PATH;
|
|
pwchMem = (WCHAR *)LOCALALLOC(cbCombinedPaths);
|
|
|
|
if (pwchMem)
|
|
{
|
|
// set the pointers for the loop:
|
|
|
|
pwcNtPaths = pwchMem;
|
|
pwszOneFile = pwszFileName; // reset this from the loop above
|
|
cwc = 0; // measure the whole NtPaths string
|
|
bDoIt = TRUE;
|
|
|
|
for (iFile = 0; iFile < cFiles; iFile++)
|
|
{
|
|
WCHAR awchOneFile[MAX_PATH];
|
|
WCHAR awcPathName[MAX_PATH];
|
|
WCHAR awcTTF[MAX_PATH];
|
|
|
|
WCHAR *pwcTmp = awchOneFile;
|
|
|
|
// copy the file to the buffer on the stack and zero terminate it
|
|
// the whole point of this is just to ensure zero termination
|
|
while ((*pwszOneFile != L'\0') && (*pwszOneFile != PATH_SEPARATOR))
|
|
{
|
|
*pwcTmp = *pwszOneFile;
|
|
++pwcTmp, ++pwszOneFile;
|
|
|
|
if (pwcTmp - awchOneFile >= MAX_PATH)
|
|
{
|
|
WARNING("pwszAllocNtMultiplePath: source path is too long\n");
|
|
bDoIt = FALSE;
|
|
goto failure;
|
|
}
|
|
}
|
|
|
|
pwszOneFile++; // skip the separator or terminating zero
|
|
|
|
*pwcTmp = L'\0'; // zero terminate
|
|
|
|
if
|
|
(
|
|
bMakePathNameW(awcPathName, awchOneFile,NULL,NULL) &&
|
|
cGetTTFFromFOT(awcPathName, MAX_PATH, awcTTF, NULL, &flEmbed, pdwPidTid, bChkFOT)
|
|
)
|
|
{
|
|
// we have to make sure that the font lies in the font path
|
|
// if one is defined. This needs to be done before converting
|
|
// to NtPathNames because the names in the registry are "dos"
|
|
// path names, not Nt path names
|
|
|
|
UNICODE_STRING UniStr;
|
|
ULONG cwcThis;
|
|
|
|
// the next portion of code is only done for AddFontResourceCase
|
|
|
|
if (bAddFR)
|
|
{
|
|
if (bFileIsOnTheHardDrive(awcTTF))
|
|
flTmp |= AFRW_ADD_LOCAL_FONT;
|
|
else
|
|
flTmp |= AFRW_ADD_REMOTE_FONT;
|
|
}
|
|
|
|
// let us check the error return here:
|
|
|
|
bReturn = RtlDosPathNameToNtPathName_U(awcTTF,
|
|
&UniStr,
|
|
NULL,
|
|
NULL);
|
|
|
|
// get the size out of the unicode string,
|
|
// update cwc, copy out, and then free the memory
|
|
|
|
if (bReturn && (UniStr.Buffer))
|
|
{
|
|
cwcThis = (UniStr.Length/sizeof(WCHAR) + 1);
|
|
if (cwcThis <= MAX_PATH)
|
|
{
|
|
cwc += cwcThis;
|
|
|
|
RtlCopyMemory(pwcNtPaths, UniStr.Buffer, UniStr.Length);
|
|
|
|
if (iFile < (cFiles - 1))
|
|
pwcNtPaths[cwcThis - 1] = PATH_SEPARATOR;
|
|
else
|
|
pwcNtPaths[cwcThis - 1] = L'\0';
|
|
|
|
|
|
pwcNtPaths += cwcThis;
|
|
}
|
|
else
|
|
{
|
|
WARNING("pwszAllocNtMultiplePath: path from RtlDosPathNameToNtPathName_U is too long\n");
|
|
bDoIt = FALSE;
|
|
}
|
|
|
|
RtlFreeHeap(RtlProcessHeap(),0,UniStr.Buffer);
|
|
}
|
|
else
|
|
{
|
|
bDoIt = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bDoIt = FALSE;
|
|
}
|
|
if (!bDoIt)
|
|
break;
|
|
} // end of the "for" loop
|
|
|
|
failure:
|
|
|
|
// now check if we are going to reject the font because
|
|
// only local or only remote fonts are requested to be loaded
|
|
|
|
if (bDoIt && bAddFR)
|
|
{
|
|
switch (fl & (AFRW_ADD_REMOTE_FONT|AFRW_ADD_LOCAL_FONT))
|
|
{
|
|
case AFRW_ADD_REMOTE_FONT:
|
|
// we say that the font is remote if AT LEAST ONE of the files
|
|
// is remote.
|
|
|
|
if (!(flTmp & AFRW_ADD_REMOTE_FONT))
|
|
bDoIt = FALSE;
|
|
break;
|
|
case AFRW_ADD_LOCAL_FONT:
|
|
// conversely, we say that it is local when it is not remote,
|
|
// that is when ALL files are local
|
|
|
|
if (flTmp & AFRW_ADD_REMOTE_FONT)
|
|
bDoIt = FALSE;
|
|
break;
|
|
|
|
case (AFRW_ADD_REMOTE_FONT|AFRW_ADD_LOCAL_FONT):
|
|
RIP("AddFontResourceW, bogus flag combination");
|
|
bDoIt = FALSE;
|
|
break;
|
|
default:
|
|
|
|
// flag if this font should be removed at the log off time
|
|
|
|
if (flTmp & AFRW_ADD_REMOTE_FONT)
|
|
{
|
|
// always remove fonts on the net on the log off,
|
|
// whether they be listed in the registry or not.
|
|
// The point is that even if they are listed, drive letters
|
|
// may change if a different user logs on. If this font is
|
|
// NOT in the registry, it is a temporary remote font added
|
|
// by an app, so we want it removed on the next log off.
|
|
|
|
*pfl |= AFRW_ADD_REMOTE_FONT;
|
|
}
|
|
else
|
|
{
|
|
// do not remove, even if not in the registry, i.e. even
|
|
// if this is a temp. font added by some app. This is ok
|
|
// since this is a local font, drive letter destinations
|
|
// do not change even when a different user logs on. Note
|
|
// that this is little bit different that 3.51 behavior.
|
|
// This way every font is marked at AddFontResource time
|
|
// for whether it should be removed or not at log off time.
|
|
// This makes time consuming registry searches at log off
|
|
// time unnecessary. The drawback is that the next user
|
|
// to log on may still have local temp fonts loaded
|
|
// from a previous user's session
|
|
|
|
*pfl |= AFRW_ADD_LOCAL_FONT;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bDoIt)
|
|
{
|
|
*pcwc = 0;
|
|
*pcFiles = 0;
|
|
|
|
if (pwchMem)
|
|
{
|
|
LOCALFREE(pwchMem);
|
|
pwchMem = NULL;
|
|
}
|
|
}
|
|
else // success
|
|
{
|
|
*pcwc = cwc;
|
|
*pcFiles = cFiles;
|
|
|
|
// set flag for embedded fonts
|
|
|
|
*pfl |= flEmbed;
|
|
|
|
ASSERTGDI((flEmbed & (FRW_EMB_PID|FRW_EMB_TID)) == flEmbed, "Embedded fonts: flEmbed\n");
|
|
ASSERTGDI((!flEmbed) || (cFiles == 1), "Embedded fonts but cFiles != 1\n");
|
|
}
|
|
|
|
return pwchMem;
|
|
}
|
|
|
|
|
|
int GdiAddFontResourceW (
|
|
LPWSTR pwszFileName, // ptr. to unicode filename string
|
|
FLONG fl,
|
|
DESIGNVECTOR *pdv
|
|
)
|
|
{
|
|
int iRet = 0;
|
|
ULONG cFiles, cwc;
|
|
WCHAR *pwszNtPath;
|
|
DWORD dwPidTid;
|
|
|
|
|
|
if (pwszNtPath = pwszAllocNtMultiplePath(pwszFileName,
|
|
&fl,
|
|
&cwc,
|
|
&cFiles,
|
|
TRUE,
|
|
&dwPidTid, FALSE))
|
|
{
|
|
|
|
iRet = NtGdiAddFontResourceW(pwszNtPath,cwc,
|
|
cFiles,fl,dwPidTid, pdv);
|
|
|
|
LOCALFREE(pwszNtPath);
|
|
|
|
if (!iRet)
|
|
{
|
|
pwszNtPath = NULL;
|
|
cFiles = 0;
|
|
cwc = 0;
|
|
dwPidTid = 0;
|
|
if (pwszNtPath = pwszAllocNtMultiplePath(pwszFileName,
|
|
&fl,
|
|
&cwc,
|
|
&cFiles,
|
|
TRUE,
|
|
&dwPidTid, TRUE))
|
|
{
|
|
|
|
iRet = NtGdiAddFontResourceW(pwszNtPath,cwc,
|
|
cFiles,fl,dwPidTid, pdv);
|
|
|
|
LOCALFREE(pwszNtPath);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return iRet;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* int WINAPI AddFontResource(LPSTR psz)
|
|
*
|
|
* History:
|
|
* 13-Aug-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
int WINAPI AddFontResourceA(LPCSTR psz)
|
|
{
|
|
return AddFontResourceExA(psz,0, NULL);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* int WINAPI AddFontResourceExA(LPSTR psz, DWORD dwFlag, PVOID NULL)
|
|
*
|
|
* History:
|
|
* 29-Aug-1996 -by- Xudong Wu [TessieW]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
int WINAPI AddFontResourceExA(LPCSTR psz, DWORD fl, PVOID pvResrved)
|
|
{
|
|
int iRet = 0;
|
|
WCHAR awcPathName[MAX_PATH];
|
|
ULONG cch, cwc;
|
|
WCHAR *pwcPathName = NULL;
|
|
DESIGNVECTOR * pdv = NULL;
|
|
|
|
// check invalid flag
|
|
|
|
if ( fl & ~(FR_PRIVATE | FR_NOT_ENUM) )
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
// protect ourselves from bogus pointers, win95 does it
|
|
|
|
try
|
|
{
|
|
cch = lstrlenA(psz) + 1;
|
|
if (cch <= MAX_PATH)
|
|
{
|
|
pwcPathName = awcPathName;
|
|
cwc = MAX_PATH;
|
|
}
|
|
else
|
|
{
|
|
pwcPathName = (WCHAR *)LOCALALLOC(cch * sizeof(WCHAR));
|
|
cwc = cch;
|
|
}
|
|
|
|
if (pwcPathName)
|
|
{
|
|
vToUnicodeN(pwcPathName, cwc, psz, cch);
|
|
iRet = 1;
|
|
}
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
iRet = 0;
|
|
}
|
|
|
|
if (iRet)
|
|
iRet = GdiAddFontResourceW(pwcPathName,(FLONG)fl, pdv);
|
|
|
|
if (pwcPathName && (pwcPathName != awcPathName))
|
|
LOCALFREE(pwcPathName);
|
|
|
|
return iRet;
|
|
}
|
|
|
|
|
|
/**************************Public*Routine************************\
|
|
* int WINAPI AddFontMemResourceEx()
|
|
*
|
|
* Font image pointed by pFileView is loaded as private font
|
|
* (FR_PRIVATE | FR_NOT_ENUM) to the system private font tale.
|
|
*
|
|
* If succeeds, it returns an index to the global memory font
|
|
* link list, otherwise it returns zero.
|
|
*
|
|
* History:
|
|
* 20-May-1997 -by- Xudong Wu [TessieW]
|
|
* Wrote it.
|
|
\****************************************************************/
|
|
|
|
HANDLE WINAPI AddFontMemResourceEx
|
|
(
|
|
PVOID pFileView,
|
|
DWORD cjSize,
|
|
PVOID pvResrved,
|
|
DWORD* pNumFonts)
|
|
{
|
|
DWORD cjDV = 0;
|
|
DESIGNVECTOR * pdv = NULL;
|
|
|
|
// check size and pointer
|
|
|
|
if ((cjSize == 0) || (pFileView == NULL) || (pNumFonts == NULL))
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
if (pdv)
|
|
{
|
|
cjDV = SIZEOFDV(pdv->dvNumAxes);
|
|
}
|
|
|
|
return (NtGdiAddFontMemResourceEx(pFileView, cjSize, pdv, cjDV, pNumFonts));
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* int WINAPI AddFontResourceTracking(LPSTR psz)
|
|
*
|
|
* This routine calls AddFontResource and, if succesful, keeps track of the
|
|
* call along with an unique id identifying the apps. Later when the app
|
|
* goes away, WOW will call RemoveNetFonts to remove all of these added fonts
|
|
* if there are on a net share.
|
|
*
|
|
* History:
|
|
* Fri 22-Jul-1994 -by- Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int AddFontResourceTracking(LPCSTR psz, UINT id)
|
|
{
|
|
INT iRet;
|
|
AFRTRACKNODE *afrtnNext;
|
|
WCHAR awcPathBuffer[MAX_PATH],*pTmp;
|
|
WCHAR awcPathName[MAX_PATH];
|
|
BOOL bResult;
|
|
|
|
vToUnicodeN(awcPathName, MAX_PATH, psz, lstrlenA(psz) + 1);
|
|
|
|
iRet = GdiAddFontResourceW(awcPathName, 0 , NULL);
|
|
|
|
if( iRet == 0 )
|
|
{
|
|
// we failed so just return
|
|
|
|
return(iRet);
|
|
}
|
|
|
|
// now get the full pathname of the font
|
|
|
|
if (!bMakePathNameW(awcPathBuffer,awcPathName, &pTmp, NULL))
|
|
{
|
|
WARNING("AddFontResourceTracking unable to create path\n");
|
|
return(iRet);
|
|
}
|
|
|
|
// if this isn't a network font just return
|
|
|
|
if( bFileIsOnTheHardDrive( awcPathBuffer ) )
|
|
{
|
|
return(iRet);
|
|
}
|
|
|
|
// now search the list
|
|
|
|
for( afrtnNext = pAFRTNodeList;
|
|
afrtnNext != NULL;
|
|
afrtnNext = afrtnNext->pafrnNext
|
|
)
|
|
{
|
|
if( ( !_wcsicmp( awcPathBuffer, afrtnNext->pwszPath ) ) &&
|
|
( id == afrtnNext->id ))
|
|
{
|
|
// we've found an entry so update the count and get out of here
|
|
|
|
afrtnNext->cLoadCount += 1;
|
|
return(iRet);
|
|
}
|
|
}
|
|
|
|
// if we got here this font isn't yet in the list so we need to add it
|
|
|
|
afrtnNext = (AFRTRACKNODE *) LOCALALLOC( sizeof(AFRTRACKNODE) +
|
|
( sizeof(WCHAR) * ( wcslen( awcPathBuffer ) + 1)) );
|
|
|
|
if( afrtnNext == NULL )
|
|
{
|
|
WARNING("AddFontResourceTracking unable to allocate memory\n");
|
|
return(iRet);
|
|
}
|
|
|
|
// link it in
|
|
|
|
afrtnNext->pafrnNext = pAFRTNodeList;
|
|
pAFRTNodeList = afrtnNext;
|
|
|
|
// the path string starts just past afrtnNext in our recently allocated buffer
|
|
|
|
afrtnNext->pwszPath = (WCHAR*) (&afrtnNext[1]);
|
|
lstrcpyW( afrtnNext->pwszPath, awcPathBuffer );
|
|
|
|
afrtnNext->id = id;
|
|
afrtnNext->cLoadCount = 1;
|
|
|
|
return(iRet);
|
|
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* int RemoveFontResourceEntry( UINT id, CHAR *pszFaceName )
|
|
*
|
|
* Either search for an entry for a particlur task id and font file or and
|
|
* decrement the load count for it or, if pszPathName is NULL unload all
|
|
* fonts loaded by the task.
|
|
*
|
|
* History:
|
|
* Fri 22-Jul-1994 -by- Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
void RemoveFontResourceEntry( UINT id, WCHAR *pwszPathName )
|
|
{
|
|
AFRTRACKNODE *afrtnNext,**ppafrtnPrev;
|
|
BOOL bMore = TRUE;
|
|
|
|
while( bMore )
|
|
{
|
|
|
|
for( afrtnNext = pAFRTNodeList, ppafrtnPrev = &pAFRTNodeList;
|
|
afrtnNext != NULL;
|
|
afrtnNext = afrtnNext->pafrnNext )
|
|
{
|
|
if( (( pwszPathName == NULL ) ||
|
|
( !_wcsicmp( pwszPathName, afrtnNext->pwszPath ))) &&
|
|
( id == afrtnNext->id ))
|
|
{
|
|
// we've found an entry so break
|
|
break;
|
|
}
|
|
|
|
ppafrtnPrev = &(afrtnNext->pafrnNext);
|
|
|
|
}
|
|
|
|
if( afrtnNext == NULL )
|
|
{
|
|
bMore = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if( pwszPathName == NULL )
|
|
{
|
|
// we need to call RemoveFontResource LoadCount times to remove this font
|
|
|
|
while( afrtnNext->cLoadCount )
|
|
{
|
|
RemoveFontResourceW( afrtnNext->pwszPath );
|
|
afrtnNext->cLoadCount -= 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
afrtnNext->cLoadCount -= 1;
|
|
|
|
// we're only decrementing the ref count so we are done
|
|
|
|
bMore = FALSE;
|
|
}
|
|
|
|
// now unlink it and a free the memory if the ref count is zero
|
|
|
|
if( afrtnNext->cLoadCount == 0 )
|
|
{
|
|
*ppafrtnPrev = afrtnNext->pafrnNext;
|
|
LOCALFREE(afrtnNext);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* int RemoveFontResourceTracking(LPSTR psz)
|
|
*
|
|
* History:
|
|
* Fri 22-Jul-1994 -by- Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int RemoveFontResourceTracking(LPCSTR psz, UINT id)
|
|
{
|
|
INT iRet;
|
|
WCHAR awcPathBuffer[MAX_PATH],*pTmp;
|
|
WCHAR awcPathName[MAX_PATH];
|
|
BOOL bResult;
|
|
|
|
vToUnicodeN(awcPathName, MAX_PATH, psz, lstrlenA(psz) + 1);
|
|
|
|
#if DBG
|
|
DbgPrint("We made it to RemoveFontsResourceTracking %s\n", psz);
|
|
#endif
|
|
iRet = RemoveFontResourceW( awcPathName );
|
|
|
|
if( iRet == 0 )
|
|
{
|
|
// we failed so just return
|
|
|
|
return(iRet);
|
|
}
|
|
|
|
// now get the full pathname of the font
|
|
|
|
if (!bMakePathNameW(awcPathBuffer, awcPathName, &pTmp, NULL))
|
|
{
|
|
WARNING("RemoveFontResourceTracking unable to create path\n");
|
|
return(iRet);
|
|
}
|
|
|
|
#if DBG
|
|
DbgPrint("Path is %ws\n", awcPathBuffer);
|
|
#endif
|
|
|
|
// if this isn't a network font just return
|
|
|
|
if( bFileIsOnTheHardDrive( awcPathBuffer ) )
|
|
{
|
|
return(iRet);
|
|
}
|
|
|
|
// now search the list decrement the reference count
|
|
|
|
RemoveFontResourceEntry( id, awcPathBuffer );
|
|
|
|
return(iRet);
|
|
}
|
|
|
|
|
|
void UnloadNetworkFonts( UINT id )
|
|
{
|
|
RemoveFontResourceEntry( id, NULL );
|
|
}
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* int WINAPI AddFontResourceW(LPWSTR pwsz)
|
|
*
|
|
* History:
|
|
* 13-Aug-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int WINAPI AddFontResourceW(LPCWSTR pwsz)
|
|
{
|
|
return GdiAddFontResourceW((LPWSTR) pwsz, 0 , NULL);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* int WINAPI AddFontResourceExW
|
|
*
|
|
* History:
|
|
* 29-Aug-1996 -by- Xudong Wu [TessieW]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int WINAPI AddFontResourceExW(LPCWSTR pwsz, DWORD fl, PVOID pvResrved)
|
|
{
|
|
DESIGNVECTOR * pdv = NULL;
|
|
|
|
// check invalid flag
|
|
|
|
if (fl & ~(FR_PRIVATE | FR_NOT_ENUM))
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
return GdiAddFontResourceW((LPWSTR) pwsz, (FLONG)fl , pdv);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL WINAPI RemoveFontResource(LPSTR psz)
|
|
*
|
|
*
|
|
* History:
|
|
* 13-Aug-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
BOOL WINAPI RemoveFontResourceA(LPCSTR psz)
|
|
{
|
|
return RemoveFontResourceExA(psz,0, NULL);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL WINAPI RemoveFontResourceExA
|
|
*
|
|
* Note: Process should use the same flag with the one for AddFontResourceExA
|
|
* to remove the font resource
|
|
*
|
|
* History:
|
|
* 27-Sept-1996 -by- Xudong Wu [TessieW]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL WINAPI RemoveFontResourceExA(LPCSTR psz, DWORD fl, PVOID pvResrved)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
WCHAR awcPathName[MAX_PATH];
|
|
ULONG cch, cwc;
|
|
WCHAR *pwcPathName = NULL;
|
|
DESIGNVECTOR * pdv = NULL;
|
|
|
|
// check invalid flag
|
|
|
|
if (fl & ~(FR_PRIVATE | FR_NOT_ENUM))
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
// protect ourselves from bogus pointers, win95 does it
|
|
|
|
try
|
|
{
|
|
cch = lstrlenA(psz) + 1;
|
|
if (cch <= MAX_PATH)
|
|
{
|
|
pwcPathName = awcPathName;
|
|
cwc = MAX_PATH;
|
|
}
|
|
else
|
|
{
|
|
pwcPathName = (WCHAR *)LOCALALLOC(cch * sizeof(WCHAR));
|
|
cwc = cch;
|
|
}
|
|
|
|
if (pwcPathName)
|
|
{
|
|
vToUnicodeN(pwcPathName, cwc, psz, lstrlenA(psz) + 1);
|
|
bRet = 1;
|
|
}
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
bRet = 0;
|
|
}
|
|
|
|
if (bRet)
|
|
bRet = RemoveFontResourceExW(pwcPathName,fl, NULL);
|
|
|
|
if (pwcPathName && (pwcPathName != awcPathName))
|
|
LOCALFREE(pwcPathName);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL WINAPI RemoveFontResourceW(LPWSTR pwsz)
|
|
*
|
|
* History:
|
|
* 13-Aug-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
BOOL WINAPI RemoveFontResourceW(LPCWSTR pwsz)
|
|
{
|
|
return RemoveFontResourceExW(pwsz,0, NULL);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL WINAPI RemoveFontResourceExW
|
|
*
|
|
* Note: needs to pass fl and dwPidTid for Embedded fonts
|
|
* History:
|
|
* 27-Sept-1996 -by- Xudong Wu [TessieW]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
BOOL WINAPI RemoveFontResourceExW(LPCWSTR pwsz, DWORD dwfl, PVOID pvResrved)
|
|
{
|
|
|
|
BOOL bRet = FALSE;
|
|
ULONG cFiles, cwc;
|
|
FLONG fl = dwfl;
|
|
WCHAR *pwszNtPath;
|
|
DWORD dwPidTid;
|
|
DESIGNVECTOR * pdv = NULL;
|
|
|
|
// check invalid flag
|
|
|
|
if (fl & ~(FR_PRIVATE | FR_NOT_ENUM))
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
if (pwsz)
|
|
{
|
|
if (pwszNtPath = pwszAllocNtMultiplePath((LPWSTR)pwsz,
|
|
&fl,
|
|
&cwc,
|
|
&cFiles,
|
|
FALSE,
|
|
&dwPidTid, TRUE))
|
|
{
|
|
bRet = NtGdiRemoveFontResourceW(pwszNtPath, cwc,
|
|
cFiles, fl, dwPidTid,
|
|
pdv);
|
|
LOCALFREE(pwszNtPath);
|
|
}
|
|
}
|
|
return bRet;
|
|
|
|
}
|
|
|
|
|
|
/**************************Public*Routine************************\
|
|
*
|
|
* BOOL WINAPI RemoveFontMemResourceEx()
|
|
*
|
|
* Note: current process can only remove the memory fonts loaded
|
|
* by itself.
|
|
*
|
|
* History:
|
|
* 20-May-1997 -by- Xudong Wu [TessieW]
|
|
* Wrote it.
|
|
\****************************************************************/
|
|
|
|
BOOL WINAPI RemoveFontMemResourceEx(HANDLE hMMFont)
|
|
{
|
|
if (hMMFont == 0)
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
return (NtGdiRemoveFontMemResourceEx(hMMFont));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* CreateScalableFontResourceA
|
|
*
|
|
* Client side stub (ANSI version) to GreCreateScalableFontResourceW.
|
|
*
|
|
* History:
|
|
* 16-Feb-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY CreateScalableFontResourceA(
|
|
DWORD flHidden, // mark file as embedded font
|
|
LPCSTR lpszResourceFile, // name of file to create
|
|
LPCSTR lpszFontFile, // name of font file to use
|
|
LPCSTR lpszCurrentPath) // path to font file
|
|
{
|
|
// Allocate stack space for UNICODE version of input strings.
|
|
|
|
WCHAR awchResourceFile[MAX_PATH];
|
|
WCHAR awchFontFile[MAX_PATH];
|
|
WCHAR awchCurrentPath[MAX_PATH];
|
|
|
|
// Parameter checking.
|
|
|
|
if ( (lpszFontFile == (LPSTR) NULL) ||
|
|
(lpszResourceFile == (LPSTR) NULL)
|
|
)
|
|
{
|
|
WARNING("gdi!CreateScalableFontResourceA(): bad parameter\n");
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return (FALSE);
|
|
}
|
|
|
|
// Convert input strings to UNICODE.
|
|
|
|
vToUnicodeN(awchResourceFile, MAX_PATH, lpszResourceFile, lstrlenA(lpszResourceFile)+1);
|
|
vToUnicodeN(awchFontFile, MAX_PATH, lpszFontFile, lstrlenA(lpszFontFile)+1);
|
|
|
|
// Note: Whereas the other parameters may be not NULL, lpszCurrentPath
|
|
// may be NULL. Therefore, we need to treat it a little
|
|
// differently.
|
|
|
|
if ( lpszCurrentPath != (LPSTR) NULL )
|
|
{
|
|
vToUnicodeN(awchCurrentPath, MAX_PATH, lpszCurrentPath, lstrlenA(lpszCurrentPath)+1);
|
|
}
|
|
else
|
|
{
|
|
awchCurrentPath[0] = L'\0'; // equivalent to NULL pointer for this call
|
|
}
|
|
|
|
// Call to UNICODE version of call.
|
|
|
|
return (CreateScalableFontResourceW (
|
|
flHidden,
|
|
awchResourceFile,
|
|
awchFontFile,
|
|
awchCurrentPath
|
|
)
|
|
);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* CreateScalableFontResourceInternalW
|
|
*
|
|
* Creates a font resource file that contains the font directory and the name
|
|
* of the name of the scalable font file.
|
|
*
|
|
* The flEmbed flag marks the created file as hidden (or embedded). When an
|
|
* embedded font file is added to the system, it is hidden from enumeration
|
|
* and may be mapped to only if the bit is set in the LOGFONT.
|
|
*
|
|
* With regard to pwszCurrentPath and pwszFontFile, two cases are valid:
|
|
*
|
|
* 1. pwszCurrentPath is a path (relative, full, etc.)
|
|
* pwszFontFile is only FILENAME.EXT
|
|
*
|
|
* In this case, pwszFontFile is stored in the resource file. The caller
|
|
* is responsible for copying the .TTF file to the \windows\system
|
|
* directory.
|
|
*
|
|
* 2. pwszCurrentPath is NULL or a pointer to NULL
|
|
* pwszFontFile is a FULL pathname
|
|
*
|
|
* In this case, pwszFontFile is stored in the resource file. The
|
|
* file must always exist at this pathname.
|
|
*
|
|
* Returns:
|
|
* TRUE if successful, FALSE otherwise.
|
|
*
|
|
* History:
|
|
* 12-Apr-1995 Gerrit van Wingerden [gerritv]
|
|
* Moved it to client side for kernel mode.
|
|
* 10-Feb-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
#define vToASCIIN( pszDst, cch, pwszSrc, cwch) \
|
|
{ \
|
|
RtlUnicodeToMultiByteN((PCH)(pszDst), (ULONG)(cch), (PULONG)NULL, \
|
|
(PWSZ)(pwszSrc), (ULONG)((cwch)*sizeof(WCHAR))); \
|
|
(pszDst)[(cch)-1] = 0; \
|
|
}
|
|
|
|
BOOL CreateScalableFontResourceInternalW (
|
|
FLONG flEmbed, // fl
|
|
LPCWSTR lpwszResourceFile,
|
|
LPCWSTR lpwszFontFile,
|
|
LPCWSTR lpwszCurrentPath
|
|
)
|
|
{
|
|
BOOL bFullPath = TRUE; //!localW nIsNotFullPath
|
|
ULONG cwchFileName = 0; // localW nFileNameLength
|
|
ULONG cwchFullPath = 0; // localW nFullPathLength
|
|
ULONG cwchModuleName = 0; // localW nModuleNameLength
|
|
PWSZ pwszModuleName; // localD lpModuleName
|
|
PTRDIFF dpwszFullPath; // lovalW wFullPath
|
|
ULONG cjFontDir; // localW nSizeFontDir
|
|
ULONG cchFaceName; // localW nFaceNameLength
|
|
PSZ pszFaceName; // localD lpFaceName
|
|
PBYTE pjOutObj; // localD <lpFontDir, lpOutObj>
|
|
HANDLE hResFile; // localW hResFile
|
|
WCHAR awchFullPath[MAX_PATH]; // localV pFullPath, PATH_LENGTH
|
|
PWSZ pwszFullPath;
|
|
PWSZ pwszTmp;
|
|
ULONG cwch;
|
|
BYTE ajFontDir[CJ_FONTDIR];
|
|
PSZ pszTmp;
|
|
BYTE ajOutObj[CJ_OUTOBJ];
|
|
USHORT usTmp;
|
|
|
|
// Parameter check.
|
|
|
|
if ( (lpwszFontFile == (LPWSTR) NULL) ||
|
|
(lpwszResourceFile == (LPWSTR) NULL)
|
|
)
|
|
{
|
|
WARNING("CreateScalableFontResourceInternalW(): bad parameter\n");
|
|
return (FALSE);
|
|
}
|
|
|
|
// If not a NULL ptr, put current path in the full path.
|
|
|
|
pwszFullPath = awchFullPath;
|
|
|
|
if ( lpwszCurrentPath != (LPWSTR) NULL )
|
|
{
|
|
// Copy current path including the NULL.
|
|
|
|
pwszTmp = (PWSZ) lpwszCurrentPath;
|
|
|
|
while ( *pwszFullPath++ = *pwszTmp++ );
|
|
cwchFullPath = (ULONG) (pwszTmp - lpwszCurrentPath); // number of characters copied
|
|
|
|
// Back up pointer to the terminating NULL (we have to append here).
|
|
|
|
pwszFullPath--;
|
|
cwchFullPath--;
|
|
|
|
// If any non-NULL characters were copied, then check to make sure path ends with '\'.
|
|
|
|
if (cwchFullPath != 0)
|
|
{
|
|
if (awchFullPath[cwchFullPath - 1] != L'\\')
|
|
{
|
|
// Put in the '\' and NULL and update character count.
|
|
|
|
*pwszFullPath++ = L'\\';
|
|
*pwszFullPath = 0x0000;
|
|
cwchFullPath++;
|
|
|
|
}
|
|
|
|
// Path info was copied, so we didn't have a full path.
|
|
|
|
bFullPath = FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
// Append the file name
|
|
|
|
pwszTmp = (PWSZ) lpwszFontFile;
|
|
|
|
while ( *pwszFullPath++ = *pwszTmp++ );
|
|
|
|
// Note: lengths include the NULL.
|
|
cwchFullPath += (ULONG) (pwszTmp - lpwszFontFile); // add on number of characters copied
|
|
cwchFileName = (ULONG) (pwszTmp - lpwszFontFile); // number of characters copied
|
|
|
|
// [Win 3.1 compatibility]
|
|
// Win 3.1 is paranoid. They parse the full pathname backward to look for
|
|
// filename (without path), just in case both lpwszCurrentPath and
|
|
// pwszFileName (with a path) is passed in.
|
|
|
|
// Adjust pointer to terminating NULL.
|
|
|
|
pwszFullPath--;
|
|
|
|
// Move pointer to beginning of filename alone. Figure out the length
|
|
// of just the filename.
|
|
|
|
pwszTmp = pwszFullPath;
|
|
|
|
// Note: loop terminates when beginning of string is reached or
|
|
// the first '\' is encountered.
|
|
|
|
for (cwch = cwchFullPath;
|
|
(cwch != 0) && (*pwszTmp != L'\\');
|
|
cwch--, pwszTmp--
|
|
);
|
|
|
|
pwszTmp++; // backed up one too far
|
|
|
|
cwchFileName = cwchFullPath - cwch; // cwch is length of just path
|
|
|
|
// The filename is the module name, so set the pointer at current position.
|
|
|
|
pwszModuleName = pwszTmp;
|
|
|
|
// Figure out the length of module name (filename with no extention).
|
|
// NULL is not counted (nor does it exist!).
|
|
|
|
// Note: loop terminates when end of string is reached or
|
|
// '.' is encountered.
|
|
|
|
for (cwch = 0;
|
|
(cwch < cwchFileName) && (*pwszTmp != L'.');
|
|
cwch++, pwszTmp++
|
|
);
|
|
|
|
// Truncate length to 8 because Win 3.1 does (probably an EXE format
|
|
// requirement).
|
|
|
|
cwchModuleName = min(cwch, 8);
|
|
|
|
// If a full path was passed in via pwszFileName, then set offset to it.
|
|
|
|
if ( bFullPath )
|
|
{
|
|
dpwszFullPath = 0;
|
|
}
|
|
|
|
// Otherwise, set offset to filename alone.
|
|
|
|
else
|
|
{
|
|
dpwszFullPath = (PTRDIFF)(pwszModuleName - awchFullPath); // this is win64 safe cast!
|
|
cwchFullPath = cwchFileName;
|
|
}
|
|
|
|
// Allocate memory on the stack for the Font Directory resource structure.
|
|
|
|
RtlZeroMemory((PVOID) ajFontDir, (UINT) CJ_FONTDIR);
|
|
|
|
// Call GreMakeFontDir to create a Font Directory resource.
|
|
|
|
{
|
|
UNICODE_STRING unicodeString;
|
|
PWSZ pwsz;
|
|
|
|
RtlDosPathNameToNtPathName_U(awchFullPath,
|
|
&unicodeString,
|
|
NULL,
|
|
NULL);
|
|
|
|
cjFontDir = NtGdiMakeFontDir(flEmbed,
|
|
ajFontDir,
|
|
sizeof(ajFontDir),
|
|
unicodeString.Buffer,
|
|
(unicodeString.Length + 1) * sizeof(*(unicodeString.Buffer))
|
|
);
|
|
|
|
if (unicodeString.Buffer)
|
|
{
|
|
RtlFreeHeap(RtlProcessHeap(),0,unicodeString.Buffer);
|
|
}
|
|
}
|
|
|
|
if ( cjFontDir == (ULONG ) 0 )
|
|
{
|
|
WARNING("CreateScalableFontResourceInternalW(): fontdir creation failed\n");
|
|
return (FALSE);
|
|
}
|
|
|
|
// Find the facename and facename length in the font directory.
|
|
|
|
pszTmp = (PSZ) (ajFontDir + SIZEFFH + 4 + 1);
|
|
|
|
while (*pszTmp++); // skip the family name.
|
|
|
|
pszFaceName = pszTmp;
|
|
|
|
// Note: count does not include NULL in this case.
|
|
|
|
for (cchFaceName = 0; *pszTmp; pszTmp++, cchFaceName++);
|
|
|
|
// Allocate memory on the stack for the font resource file memory image.
|
|
|
|
RtlZeroMemory((PVOID) ajOutObj, (UINT) CJ_OUTOBJ);
|
|
|
|
pjOutObj = ajOutObj;
|
|
|
|
// Copy generic EXE header into output image.
|
|
|
|
RtlCopyMemory(pjOutObj, ajExeHeader, SIZEEXEHEADER);
|
|
|
|
// Copy generic New EXE header into output image.
|
|
|
|
RtlCopyMemory(pjOutObj + SIZEEXEHEADER, ausNewExe, SIZENEWEXE);
|
|
|
|
// Copy the fake resource table into output image.
|
|
|
|
RtlCopyMemory(pjOutObj + SIZEEXEHEADER + SIZENEWEXE, ausFakeResTable, SIZEFAKERESTBL);
|
|
|
|
// Patch up field, Font Directory Size Index (as a count of aligned pages).
|
|
|
|
WRITE_WORD(pjOutObj + OFF_FONTDIRSIZINDEX, (cjFontDir + ALIGNMENTCOUNT - 1) >> ALIGNMENTSHIFT);
|
|
|
|
// Patch offsets to imported names table and module reference table.
|
|
|
|
usTmp = (USHORT) (cwchModuleName +
|
|
READ_WORD(pjOutObj + SIZEEXEHEADER + OFF_ne_restab) +
|
|
6);
|
|
|
|
WRITE_WORD((pjOutObj + SIZEEXEHEADER + OFF_ne_imptab), usTmp);
|
|
WRITE_WORD((pjOutObj + SIZEEXEHEADER + OFF_ne_modtab), usTmp);
|
|
|
|
// Patch offset to entry table.
|
|
|
|
usTmp += (USHORT) cwchFileName + 1;
|
|
WRITE_WORD((pjOutObj + SIZEEXEHEADER + OFF_ne_enttab), usTmp);
|
|
|
|
// Patch offset to and size of non-resident name table.
|
|
|
|
usTmp += SIZEEXEHEADER + 4;
|
|
WRITE_DWORD((pjOutObj + SIZEEXEHEADER + OFF_ne_nrestab), (DWORD) usTmp);
|
|
|
|
WRITE_WORD((pjOutObj + SIZEEXEHEADER + OFF_ne_cbnrestab), SIZEFONTRES + 4 + cchFaceName);
|
|
|
|
// Now write some data after the exe headers and fake resource table.
|
|
|
|
pjOutObj += SIZEEXEHEADER + SIZENEWEXE + SIZEFAKERESTBL;
|
|
|
|
// Write out module name length and module name.
|
|
|
|
*pjOutObj++ = (BYTE) cwchModuleName; // win 3.1 assumes < 256, so will we
|
|
|
|
// Note: Writing cwchModuleName+1 characters because cwchModuleName
|
|
// does not include space for a NULL character.
|
|
|
|
vToASCIIN((PSZ) pjOutObj, (UINT) cwchModuleName + 1, pwszModuleName, (UINT) cwchModuleName + 1);
|
|
|
|
pjOutObj += cwchModuleName & 0x00ff; // enforce < 256 assumption
|
|
|
|
// Pad with 5 bytes of zeroes.
|
|
|
|
*pjOutObj++ = 0;
|
|
*pjOutObj++ = 0;
|
|
*pjOutObj++ = 0;
|
|
*pjOutObj++ = 0;
|
|
*pjOutObj++ = 0;
|
|
|
|
// Write out file name length and file name.
|
|
|
|
*pjOutObj++ = (BYTE) cwchFileName; // win 3.1 assumes < 256, so will we
|
|
|
|
vToASCIIN((PSZ) pjOutObj, (UINT) cwchFileName, pwszModuleName, (UINT) cwchFileName);
|
|
|
|
pjOutObj += cwchFileName & 0x00ff; // enforce < 256 assumption
|
|
|
|
// Pad with 4 bytes of zeroes.
|
|
|
|
*pjOutObj++ = 0;
|
|
*pjOutObj++ = 0;
|
|
*pjOutObj++ = 0;
|
|
*pjOutObj++ = 0;
|
|
|
|
// Write out size of non-resident name table and the table itself.
|
|
|
|
*pjOutObj++ = (BYTE) (SIZEFONTRES + 4 + cchFaceName);
|
|
|
|
RtlCopyMemory(pjOutObj, ajFontRes, SIZEFONTRES);
|
|
pjOutObj += SIZEFONTRES;
|
|
|
|
RtlCopyMemory(pjOutObj, pszFaceName, (UINT) cchFaceName);
|
|
pjOutObj += cchFaceName;
|
|
|
|
// Pad with 8 bytes of zeroes.
|
|
|
|
RtlZeroMemory(pjOutObj, 8);
|
|
pjOutObj += 8;
|
|
|
|
// Store some bogus code. (Just an x86 RET instruction).
|
|
|
|
pjOutObj = ajOutObj + CODE_OFFSET;
|
|
*pjOutObj++ = 0xc3; // RET OpCode.
|
|
*pjOutObj++ = 0x00;
|
|
|
|
// Copy the "full path name" into the resource position.
|
|
|
|
pjOutObj = ajOutObj + RESOURCE_OFFSET;
|
|
|
|
vToASCIIN((PSZ) pjOutObj, (UINT) cwchFullPath, awchFullPath + dpwszFullPath, (UINT) cwchFullPath);
|
|
|
|
pjOutObj += cwchFullPath;
|
|
|
|
// Pad to paragraph boundary with zeroes.
|
|
|
|
RtlZeroMemory(pjOutObj, PRIVRESSIZE - cwchFullPath);
|
|
|
|
pjOutObj += PRIVRESSIZE - cwchFullPath;
|
|
|
|
// Finally, copy the font directory.
|
|
|
|
RtlCopyMemory(pjOutObj, ajFontDir, cjFontDir);
|
|
pjOutObj += cjFontDir;
|
|
|
|
// Add add a one paragraph padding of zeroes.
|
|
|
|
RtlZeroMemory(pjOutObj, 16);
|
|
|
|
// Create the file.
|
|
|
|
if ( (hResFile = CreateFileW(lpwszResourceFile,
|
|
GENERIC_WRITE | GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
CREATE_NEW,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL)) != (HANDLE) -1 )
|
|
{
|
|
//
|
|
// Write memory image to the file.
|
|
//
|
|
|
|
ULONG cjWasWritten;
|
|
|
|
if (WriteFile(hResFile,
|
|
ajOutObj,
|
|
CJ_OUTOBJ,
|
|
(LPDWORD) &cjWasWritten,
|
|
NULL) )
|
|
{
|
|
if (CloseHandle(hResFile) != 0)
|
|
{
|
|
return (TRUE);
|
|
}
|
|
else
|
|
{
|
|
WARNING("CreateScalableFontResourceInternalW(): error closing file\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("CreateScalableFontResourceInternalW(): error writing to file\n");
|
|
}
|
|
|
|
//
|
|
// Close the file on error
|
|
//
|
|
|
|
CloseHandle(hResFile);
|
|
}
|
|
|
|
return (FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* CreateScalableFontResourceW
|
|
*
|
|
* Client side stub to GreCreateScalableFontResourceW.
|
|
*
|
|
* History:
|
|
* 16-Feb-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY CreateScalableFontResourceW (
|
|
DWORD flHidden, // mark file as embedded font
|
|
LPCWSTR lpwszResourceFile, // name of file to create
|
|
LPCWSTR lpwszFontFile, // name of font file to use
|
|
LPCWSTR lpwszCurrentPath) // path to font file
|
|
{
|
|
BOOL bRet = FALSE;
|
|
ULONG cjData;
|
|
|
|
ULONG cwchResourceFile;
|
|
ULONG cwchFontFile;
|
|
ULONG cwchCurrentPath;
|
|
|
|
WCHAR awchResourcePathName[MAX_PATH];
|
|
WCHAR awcPathName[MAX_PATH];
|
|
WCHAR awcFileName[MAX_PATH];
|
|
PWSZ pwszFilePart;
|
|
BOOL bMadePath;
|
|
|
|
// Parameter checking.
|
|
|
|
if ( (lpwszFontFile == (LPWSTR) NULL) ||
|
|
(lpwszResourceFile == (LPWSTR) NULL)
|
|
)
|
|
{
|
|
WARNING("gdi!CreateScalableFontResourceW(): bad parameter\n");
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return (FALSE);
|
|
}
|
|
|
|
// To simplify the client server parameter validation, if lpwszCurrentPath
|
|
// is NULL, make it instead point to NULL.
|
|
|
|
if ( lpwszCurrentPath == (LPWSTR) NULL )
|
|
lpwszCurrentPath = L"";
|
|
|
|
// Need to convert paths and pathnames to full qualified paths and pathnames
|
|
// here on the client side because the "current directory" is not the same
|
|
// on the server side.
|
|
|
|
// Case 1: lpwszCurrentPath is NULL, so we want to transform lpwszFontFile
|
|
// into a fully qualified path name and keep lpwszCurrentPath NULL.
|
|
|
|
if ( *lpwszCurrentPath == L'\0' )
|
|
{
|
|
// Construct a fully qualified path name.
|
|
|
|
if (!bMakePathNameW(awcPathName, (LPWSTR) lpwszFontFile, &pwszFilePart, NULL))
|
|
{
|
|
WARNING("gdi!CreateScalableFontResourceW(): could not construct src full pathname (1)\n");
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return (FALSE);
|
|
}
|
|
|
|
lpwszFontFile = awcPathName;
|
|
}
|
|
|
|
// Case 2: lpwszCurrentPath points to path of font file, so we want to make
|
|
// lpwszCurrentPath into a fully qualified path (not pathnmame) and
|
|
// lpwszFontFile into the file part of the fully qualified path NAME.
|
|
|
|
else
|
|
{
|
|
// Concatenate lpwszCurrentPath and lpwszFontFile to make a partial (maybe
|
|
// even full) path. Keep it temporarily in awcFileName.
|
|
|
|
lstrcpyW(awcFileName, lpwszCurrentPath);
|
|
if ( lpwszCurrentPath[wcslen(lpwszCurrentPath) - 1] != L'\\' )
|
|
lstrcatW(awcFileName, L"\\"); // append '\' to path if needed
|
|
lstrcatW(awcFileName, lpwszFontFile);
|
|
|
|
// Construct a fully qualified path name.
|
|
|
|
if (!bMakePathNameW(awcPathName, awcFileName, &pwszFilePart,NULL))
|
|
{
|
|
WARNING("gdi!CreateScalableFontResourceW(): could not construct src full pathname (2)\n");
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return (FALSE);
|
|
}
|
|
|
|
// Copy out the filename part.
|
|
|
|
lstrcpyW(awcFileName, pwszFilePart);
|
|
|
|
// Remove the filename part from the path name (so that it is now just
|
|
// a fully qualified PATH). We do this by turning the first character
|
|
// of the filename part into a NULL, effectively cutting this part off.
|
|
|
|
*pwszFilePart = L'\0';
|
|
|
|
// Change the pointers to point at our buffers.
|
|
|
|
lpwszCurrentPath = awcPathName;
|
|
lpwszFontFile = awcFileName;
|
|
}
|
|
|
|
// Convert the resource filename to a fully qualified path name.
|
|
|
|
if ( !GetFullPathNameW(lpwszResourceFile, MAX_PATH, awchResourcePathName, &pwszFilePart) )
|
|
{
|
|
WARNING("gdi!CreateScalableFontResourceW(): could not construct dest full pathname\n");
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return (FALSE);
|
|
}
|
|
else
|
|
{
|
|
lpwszResourceFile = awchResourcePathName;
|
|
}
|
|
|
|
return(CreateScalableFontResourceInternalW( flHidden,
|
|
lpwszResourceFile,
|
|
lpwszFontFile,
|
|
lpwszCurrentPath ));
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetRasterizerCaps
|
|
*
|
|
* Client side stub to GreGetRasterizerCaps.
|
|
*
|
|
* History:
|
|
* 17-Feb-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY GetRasterizerCaps (
|
|
OUT LPRASTERIZER_STATUS lpraststat, // pointer to struct
|
|
IN UINT cjBytes // copy this many bytes into struct
|
|
)
|
|
{
|
|
return(NtGdiGetRasterizerCaps(lpraststat,cjBytes));
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* SetFontEnumeration *
|
|
* *
|
|
* Client side stub to GreSetFontEnumeration. *
|
|
* *
|
|
* History: *
|
|
* 09-Mar-1992 -by- Gilman Wong [gilmanw] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
ULONG SetFontEnumeration(ULONG ulType)
|
|
{
|
|
return(NtGdiSetFontEnumeration(ulType));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vNewTextMetricWToNewTextMetric
|
|
*
|
|
* History:
|
|
* 20-Aug-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
static
|
|
VOID vNewTextMetricExWToNewTextMetricExA (
|
|
NEWTEXTMETRICEXA *pntmexa,
|
|
NTMW_INTERNAL *pntmi
|
|
)
|
|
{
|
|
NEWTEXTMETRICW *pntmw = &pntmi->entmw.etmNewTextMetricEx.ntmTm;
|
|
NEWTEXTMETRICA *pntma = &pntmexa->ntmTm;
|
|
|
|
pntma->tmHeight = pntmw->tmHeight ; // DWORD
|
|
pntma->tmAscent = pntmw->tmAscent ; // DWORD
|
|
pntma->tmDescent = pntmw->tmDescent ; // DWORD
|
|
pntma->tmInternalLeading = pntmw->tmInternalLeading ; // DWORD
|
|
pntma->tmExternalLeading = pntmw->tmExternalLeading ; // DWORD
|
|
pntma->tmAveCharWidth = pntmw->tmAveCharWidth ; // DWORD
|
|
pntma->tmMaxCharWidth = pntmw->tmMaxCharWidth ; // DWORD
|
|
pntma->tmWeight = pntmw->tmWeight ; // DWORD
|
|
pntma->tmOverhang = pntmw->tmOverhang ; // DWORD
|
|
pntma->tmDigitizedAspectX = pntmw->tmDigitizedAspectX ; // DWORD
|
|
pntma->tmDigitizedAspectY = pntmw->tmDigitizedAspectY ; // DWORD
|
|
pntma->tmItalic = pntmw->tmItalic ; // BYTE
|
|
pntma->tmUnderlined = pntmw->tmUnderlined ; // BYTE
|
|
pntma->tmStruckOut = pntmw->tmStruckOut ; // BYTE
|
|
pntma->ntmFlags = pntmw->ntmFlags ;
|
|
pntma->ntmSizeEM = pntmw->ntmSizeEM ;
|
|
pntma->ntmCellHeight = pntmw->ntmCellHeight ;
|
|
pntma->ntmAvgWidth = pntmw->ntmAvgWidth ;
|
|
pntma->tmPitchAndFamily = pntmw->tmPitchAndFamily ; // BYTE
|
|
pntma->tmCharSet = pntmw->tmCharSet ; // BYTE
|
|
|
|
pntma->tmFirstChar = pntmi->tmdNtmw.chFirst;
|
|
pntma->tmLastChar = pntmi->tmdNtmw.chLast ;
|
|
pntma->tmDefaultChar = pntmi->tmdNtmw.chDefault;
|
|
pntma->tmBreakChar = pntmi->tmdNtmw.chBreak;
|
|
|
|
// finally copy font signature, required by EnumFontFamiliesEx
|
|
|
|
pntmexa->ntmFontSig = pntmi->entmw.etmNewTextMetricEx.ntmFontSig;
|
|
}
|
|
|