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.
1064 lines
20 KiB
1064 lines
20 KiB
/*++
|
|
|
|
Copyright (c) 1997-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
umpdobj.cxx
|
|
|
|
Abstract:
|
|
|
|
Object and memory management for um-km thunking
|
|
|
|
Environment:
|
|
|
|
Windows NT user mode driver support
|
|
|
|
Revision History:
|
|
|
|
09/16/97 -davidx-
|
|
Created it.
|
|
|
|
--*/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
|
|
#if !defined(_GDIPLUS_)
|
|
|
|
//
|
|
// Maximum number of pages for UMPD user mode memory heap
|
|
//
|
|
|
|
#define MAX_UMPD_HEAP 1024
|
|
|
|
//
|
|
// Create or initialize a UMPD user mode memory heap
|
|
//
|
|
|
|
PUMPDHEAP
|
|
UMPDOBJ::CreateUMPDHeap(void)
|
|
{
|
|
PUMPDHEAP pHeap;
|
|
|
|
//
|
|
// Allocate memory to hold the UMPDHEAP structure if necessary
|
|
//
|
|
|
|
if (!(pHeap = (PUMPDHEAP) PALLOCMEM(sizeof(UMPDHEAP), UMPD_MEMORY_TAG)))
|
|
return NULL;
|
|
|
|
//
|
|
// Reserve the maximum address range if needed
|
|
//
|
|
|
|
NTSTATUS Status;
|
|
PVOID p = NULL;
|
|
SIZE_T cj = MAX_UMPD_HEAP * PAGE_SIZE;
|
|
|
|
Status = ZwAllocateVirtualMemory(
|
|
NtCurrentProcess(),
|
|
&p,
|
|
0,
|
|
&cj,
|
|
MEM_RESERVE,
|
|
PAGE_READWRITE);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
pHeap->pAddress = p;
|
|
else
|
|
{
|
|
VFREEMEM(pHeap);
|
|
return NULL;
|
|
}
|
|
|
|
pHeap->AllocSize = 0;
|
|
|
|
return pHeap;
|
|
}
|
|
|
|
VOID
|
|
UMPDOBJ::ResetHeap()
|
|
{
|
|
ASSERTGDI(bWOW64(), "UMPDOBJ__ResetHeap called by none WOW64 printing\n");
|
|
|
|
PROXYPORT proxyport(m_proxyPort);
|
|
|
|
proxyport.HeapInit();
|
|
}
|
|
|
|
PUMPDHEAP
|
|
UMPDOBJ::InitUMPDHeap(
|
|
PUMPDHEAP pHeap
|
|
)
|
|
|
|
{
|
|
pHeap->AllocSize = 0;
|
|
return pHeap;
|
|
}
|
|
|
|
//
|
|
// Grow a UMPD user mode memory heap by one more page
|
|
//
|
|
|
|
BOOL
|
|
UMPDOBJ::GrowUMPDHeap(
|
|
PUMPDHEAP pHeap,
|
|
ULONG ulBytesNeeded
|
|
)
|
|
|
|
{
|
|
PVOID p;
|
|
SIZE_T NewCommitSize;
|
|
HANDLE hNewSecure;
|
|
NTSTATUS Status;
|
|
|
|
NewCommitSize = ROUNDUP_MULTIPLE(pHeap->CommitSize + ulBytesNeeded, PAGE_SIZE);
|
|
|
|
if (NewCommitSize > MAX_UMPD_HEAP * PAGE_SIZE)
|
|
{
|
|
WARNING("Not enough space for UMPD user mode memory heap\n");
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Commit one more page and secure it
|
|
//
|
|
|
|
p = pHeap->pAddress;
|
|
|
|
Status = ZwAllocateVirtualMemory(
|
|
NtCurrentProcess(),
|
|
&p,
|
|
0,
|
|
&NewCommitSize,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE);
|
|
|
|
hNewSecure = NT_SUCCESS(Status) ?
|
|
MmSecureVirtualMemory(p, NewCommitSize, PAGE_READWRITE) :
|
|
NULL;
|
|
|
|
if (hNewSecure == NULL)
|
|
{
|
|
WARNING("Failed to commit/secure more UMPD user mode memory\n");
|
|
return FALSE;
|
|
}
|
|
|
|
if (pHeap->hSecure)
|
|
MmUnsecureVirtualMemory(pHeap->hSecure);
|
|
|
|
pHeap->hSecure = hNewSecure;
|
|
pHeap->CommitSize = NewCommitSize;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Destroy a UMPD user mode memory heap
|
|
//
|
|
|
|
VOID
|
|
DestroyUMPDHeap(
|
|
PUMPDHEAP pHeap
|
|
)
|
|
|
|
{
|
|
if (pHeap != NULL)
|
|
{
|
|
if (pHeap->hSecure)
|
|
MmUnsecureVirtualMemory(pHeap->hSecure);
|
|
|
|
if (pHeap->pAddress != NULL)
|
|
{
|
|
PVOID pv = pHeap->pAddress;
|
|
SIZE_T cj = MAX_UMPD_HEAP * PAGE_SIZE;
|
|
|
|
ZwFreeVirtualMemory(NtCurrentProcess(), &pv, &cj, MEM_RELEASE);
|
|
}
|
|
|
|
VFREEMEM(pHeap);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// UMPDOBJ constructor
|
|
//
|
|
|
|
BOOL
|
|
UMPDOBJ::Init()
|
|
{
|
|
PW32THREAD pThread;
|
|
PW32PROCESS pw32Process;
|
|
ULONG_PTR pPeb32;
|
|
#if defined(_WIN64)
|
|
BOOL bWOW64 = TRUE;
|
|
#endif
|
|
RtlZeroMemory(this, sizeof(UMPDOBJ));
|
|
|
|
m_magic = UMPD_MEMORY_TAG;
|
|
|
|
pThread = W32GetCurrentThread();
|
|
|
|
m_pNext = (PUMPDOBJ) pThread->pUMPDObjs;
|
|
#if defined(_WIN64)
|
|
if (pThread->pProxyPort == NULL)
|
|
{
|
|
pw32Process = W32GetCurrentProcess();
|
|
|
|
if (pw32Process->W32PF_Flags & W32PF_WOW64)
|
|
{
|
|
PROXYPORT proxyport(MAX_UMPD_HEAP * PAGE_SIZE);
|
|
|
|
if (proxyport.bValid())
|
|
{
|
|
pThread->pProxyPort = proxyport.GetProxyPort();
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
bWOW64 = FALSE;
|
|
}
|
|
|
|
if (bWOW64)
|
|
{
|
|
m_proxyPort = (ProxyPort *) pThread->pProxyPort;
|
|
|
|
ResetHeap();
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
// WINBUG 364408 what happens if these heaps fail to initialize?
|
|
if (m_pNext == NULL)
|
|
{
|
|
if(pThread->pUMPDHeap == NULL)
|
|
{
|
|
pThread->pUMPDHeap = m_pHeap = CreateUMPDHeap();
|
|
}
|
|
else
|
|
{
|
|
m_pHeap = InitUMPDHeap((PUMPDHEAP) pThread->pUMPDHeap);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_pHeap = CreateUMPDHeap();
|
|
}
|
|
}
|
|
|
|
m_clientTid = (PW32THREAD)PsGetCurrentThread();
|
|
m_clientPid = W32GetCurrentPID();
|
|
|
|
if (HmgInsertObject(this, HMGR_ALLOC_ALT_LOCK, UMPD_TYPE) == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pThread->pUMPDObjs = (PVOID) this;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// UMPDOBJ destructor
|
|
//
|
|
|
|
VOID UMPDOBJ::Cleanup()
|
|
{
|
|
W32GetCurrentThread()->pUMPDObjs = (PVOID) m_pNext;
|
|
|
|
if (HmgRemoveObject((HOBJ)hGet(), 0, 1, TRUE, UMPD_TYPE))
|
|
{
|
|
//
|
|
// Delete any PATHOBJ's returned by CLIPOBJ_ppoGetPath
|
|
//
|
|
|
|
if (m_poClip.kmobj != NULL)
|
|
EngDeletePath((PATHOBJ *) m_poClip.kmobj);
|
|
|
|
//
|
|
// Destroy UMPD user mode memory heap if necessary
|
|
//
|
|
|
|
if(!bWOW64())
|
|
{
|
|
if (m_pNext != NULL && m_pHeap != NULL)
|
|
DestroyUMPDHeap(m_pHeap);
|
|
}
|
|
|
|
//
|
|
// Unmap any cached font file view
|
|
//
|
|
|
|
if (m_pvFontBase != NULL)
|
|
MmUnmapViewOfSection(m_pFontProcess, m_pvFontBase);
|
|
|
|
vFreeFontLinks();
|
|
}
|
|
else
|
|
{
|
|
ASSERTGDI(FALSE, "UMPDOBJ::Cleanup() leaking UMPD handle\n");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOL UMPDOBJ::pxlo(
|
|
XLATEOBJ **ppxlo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Thunk an XLATEOBJ to user mode
|
|
|
|
Arguments:
|
|
|
|
ppxlo - Address of the variable containing the pointer to the kernel mode
|
|
XLATEOBJ to be thunked. Upon returning from this function, the variable
|
|
contains the user mode object corresponding to the specified kernel mode object.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
XLATEOBJ *kmobj;
|
|
PULONG pulXlate;
|
|
|
|
if ((kmobj = *ppxlo) == NULL)
|
|
return TRUE;
|
|
|
|
//
|
|
// Copy the color lookup table
|
|
//
|
|
|
|
if (kmobj->cEntries)
|
|
{
|
|
PULONG pulSrc;
|
|
|
|
if ((pulXlate = (PULONG) AllocUserMem(kmobj->cEntries * sizeof(ULONG))) == NULL ||
|
|
(pulSrc = kmobj->pulXlate) == NULL &&
|
|
(pulSrc = XLATEOBJ_piVector(kmobj)) == NULL)
|
|
{
|
|
WARNING("Couldn't get XLATEOBJ color lookup table\n");
|
|
return FALSE;
|
|
}
|
|
|
|
RtlCopyMemory(GetKernelPtr(pulXlate), pulSrc, kmobj->cEntries * sizeof(ULONG));
|
|
}
|
|
else
|
|
pulXlate = NULL;
|
|
|
|
//
|
|
// Perform the standard object thunk
|
|
//
|
|
|
|
if (!ThunkDDIOBJ(&m_xlo, (PVOID *) ppxlo, sizeof(XLATEOBJ)))
|
|
return FALSE;
|
|
|
|
XLATEOBJ * pxlo = (XLATEOBJ *) GetKernelPtr(*ppxlo);
|
|
|
|
pxlo->pulXlate = pulXlate;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL UMPDOBJ::pso(
|
|
PDDIOBJMAP pMap,
|
|
SURFOBJ **ppso,
|
|
BOOL bLargeBitmap
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Thunk an SURFOBJ to user mode
|
|
|
|
Arguments:
|
|
|
|
pMap - Address of the um-to-km object mapping structure
|
|
|
|
ppso - Address of the variable containing the pointer to the kernel mode
|
|
SURFOBJ to be thunked. Upon returning from this function, the variable
|
|
contains the user mode object corresponding to the specified kernel mode object.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
SURFOBJ *kmobj;
|
|
PVOID pvBits;
|
|
|
|
if ((kmobj = *ppso) == NULL)
|
|
return TRUE;
|
|
|
|
//
|
|
// If we're thunking a bitmap surface and the bitmap memory
|
|
// is in kernel address space, we need to make a copy of it
|
|
// in user address space.
|
|
//
|
|
|
|
if ((pvBits = kmobj->pvBits) != NULL &&
|
|
(kmobj->iType == STYPE_BITMAP) &&
|
|
bNeedThunk(kmobj->pvBits) &&
|
|
!(bWOW64() && bLargeBitmap))
|
|
{
|
|
if (! ThunkMemBlock(&pvBits, kmobj->cjBits))
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Perform the standard object thunk
|
|
//
|
|
|
|
if (! ThunkDDIOBJ(pMap, (PVOID *) ppso, sizeof(SURFOBJ)))
|
|
return FALSE;
|
|
|
|
SURFOBJ * pso = (SURFOBJ *) GetKernelPtr(*ppso);
|
|
|
|
if (pvBits != kmobj->pvBits)
|
|
{
|
|
pso->pvBits = pvBits;
|
|
pso->pvScan0 = (PBYTE) pvBits + ((PBYTE) kmobj->pvScan0 - (PBYTE) kmobj->pvBits);
|
|
|
|
//
|
|
// umpd64 only
|
|
//
|
|
|
|
if (bWOW64())
|
|
{
|
|
kmobj->pvBits = pvBits;
|
|
kmobj->pvScan0 = pso->pvScan0;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL UMPDOBJ::pstro(
|
|
STROBJ **ppstro
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Thunk an STROBJ to user mode
|
|
|
|
Arguments:
|
|
|
|
ppstro - Address of the variable containing the pointer to the kernel mode
|
|
STROBJ to be thunked. Upon returning from this function, the variable
|
|
contains the user mode object corresponding to the specified kernel mode object.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
STROBJ *kmobj;
|
|
PWSTR pwszOrg;
|
|
GLYPHPOS *pgp;
|
|
|
|
if ((kmobj = *ppstro) == NULL)
|
|
return TRUE;
|
|
|
|
//
|
|
// Thunk STROBJ.pwszOrg field
|
|
//
|
|
|
|
if ((pwszOrg = kmobj->pwszOrg) != NULL &&
|
|
!ThunkMemBlock((PVOID *) &pwszOrg, sizeof(WCHAR) * kmobj->cGlyphs))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Thunk STROBJ.pgp field
|
|
//
|
|
|
|
if ((pgp = kmobj->pgp) != NULL)
|
|
{
|
|
if (! ThunkMemBlock((PVOID *) &pgp, sizeof(GLYPHPOS) * kmobj->cGlyphs))
|
|
return FALSE;
|
|
|
|
//
|
|
// NULL out GLYPHPOS.pgdf field to force the driver
|
|
// to call FONTOBJ_cGetGlyphs.
|
|
//
|
|
GLYPHPOS *kmpgp = (GLYPHPOS *) GetKernelPtr(pgp);
|
|
|
|
for (ULONG i=0; i < kmobj->cGlyphs; i++)
|
|
kmpgp[i].pgdf = NULL;
|
|
}
|
|
|
|
//
|
|
// Perform the standard object thunk
|
|
//
|
|
|
|
if (!ThunkDDIOBJ(&m_stro, (PVOID *) ppstro, sizeof(STROBJ)))
|
|
return FALSE;
|
|
|
|
STROBJ * pstro = (STROBJ *) GetKernelPtr(*ppstro);
|
|
|
|
pstro->pwszOrg = pwszOrg;
|
|
pstro->pgp = pgp;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL UMPDOBJ::ThunkLINEATTRS(
|
|
PLINEATTRS *pplineattrs
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Thunk a LINEATTRS structure from kernel mode to user mode
|
|
|
|
Arguments:
|
|
|
|
pplineattrs - On input, contains the address of the kernel mode
|
|
LINEATTRS structure to be thunked. On output, contains the
|
|
address of the thunked user mode copy of LINEATTRS structure.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
PLINEATTRS plineattrsKM;
|
|
PVOID pStyle;
|
|
ULONG ulStyleSize;
|
|
|
|
if ((plineattrsKM = *pplineattrs) == NULL)
|
|
return TRUE;
|
|
|
|
pStyle = plineattrsKM->pstyle;
|
|
ulStyleSize = plineattrsKM->cstyle * sizeof(FLOAT_LONG);
|
|
|
|
if (! ThunkMemBlock((PVOID *) pplineattrs, sizeof(LINEATTRS)) ||
|
|
! ThunkMemBlock(&pStyle, ulStyleSize))
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
PLINEATTRS plineattrs = (PLINEATTRS) GetKernelPtr(*pplineattrs);
|
|
|
|
plineattrs->pstyle = (PFLOAT_LONG) pStyle;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
PATHOBJ *UMPDOBJ::GetCLIPOBJPath(
|
|
CLIPOBJ *pco
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Implement CLIPOBJ_ppoGetPath for user mode printer driver
|
|
|
|
Arguments:
|
|
|
|
pco - Points to a user mode CLIPOBJ
|
|
|
|
Return Value:
|
|
|
|
Pointer to user mode PATHOBJ structure
|
|
NULL if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
PATHOBJ *ppokm, *ppoum;
|
|
|
|
//
|
|
// Note: During the same DDI entrypoint, drivers must
|
|
// call EngDeletePath after each CLIPOBJ_ppoGetPath.
|
|
//
|
|
|
|
if (m_poClip.umobj ||
|
|
! (ppokm = ppoum = (pco = GetDDIOBJ(pco)) ? CLIPOBJ_ppoGetPath(pco) : NULL))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (! ppoClip(&ppoum))
|
|
{
|
|
EngDeletePath(ppokm);
|
|
return NULL;
|
|
}
|
|
|
|
return ppoum;
|
|
}
|
|
|
|
|
|
|
|
VOID UMPDOBJ::DeleteCLIPOBJPath(
|
|
PATHOBJ *ppo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Implement EngDeletePath for user mode printer driver
|
|
|
|
Arguments:
|
|
|
|
ppo - Points to user mode PATHOBJ to be deleted.
|
|
This pointer must come from GetCLIPOBJPath.
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
if (ppo != NULL && ppo == m_poClip.umobj)
|
|
{
|
|
EngDeletePath((PATHOBJ *) m_poClip.kmobj);
|
|
m_poClip.umobj = m_poClip.kmobj = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
CLIPOBJ *UMPDOBJ::CreateCLIPOBJ()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Implement EngCreateClip for user-mode drivers
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
Pointer to user mode CLIPOBJ structure
|
|
NULL if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
CLIPOBJ *pcokm, *pcoum;
|
|
|
|
//
|
|
// Note: During the same DDI entrypoint, drivers must
|
|
// call EngDeleteClip after each EngCreateClip.
|
|
//
|
|
|
|
if (m_coCreated.umobj ||
|
|
! (pcokm = pcoum = EngCreateClip()))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (! pcoCreated(&pcoum))
|
|
{
|
|
EngDeleteClip(pcokm);
|
|
return NULL;
|
|
}
|
|
|
|
return pcoum;
|
|
}
|
|
|
|
|
|
|
|
VOID UMPDOBJ::DeleteCLIPOBJ(
|
|
CLIPOBJ *pco
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Implement EngDeleteClip for user-mode drivers
|
|
|
|
Arguments:
|
|
|
|
pco - Points to user-mode CLIPOBJ to be deleted
|
|
This must have come from EngCreateClip.
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
if (pco != NULL && pco == m_coCreated.umobj)
|
|
{
|
|
EngDeleteClip((CLIPOBJ *) m_coCreated.kmobj);
|
|
m_coCreated.umobj = m_coCreated.kmobj = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
XFORMOBJ *UMPDOBJ::GetFONTOBJXform(
|
|
FONTOBJ *pfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Implement FONTOBJ_pxoGetXform for user mode printer driver
|
|
|
|
Arguments:
|
|
|
|
pfo - Points to a user mode FONTOBJ
|
|
|
|
Return Value:
|
|
|
|
Pointer to a user mode XFORMOBJ structure
|
|
NULL if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
XFORMOBJ *pxo;
|
|
|
|
//
|
|
// Check if this function has been called already
|
|
// during the current DDI entrypoint
|
|
//
|
|
|
|
if (! (pfo = GetDDIOBJ(pfo)))
|
|
return NULL;
|
|
|
|
if (m_xoFont.umobj != NULL)
|
|
pxo = (XFORMOBJ *) m_xoFont.umobj;
|
|
else
|
|
{
|
|
RFONTTMPOBJ rfto(PFO_TO_PRF(pfo));
|
|
|
|
UMPDAcquireRFONTSem(rfto, this, 0, 0, NULL);
|
|
|
|
if (!(pxo = FONTOBJ_pxoGetXform(pfo)) || !pxoFont(&pxo))
|
|
pxo = NULL;
|
|
|
|
UMPDReleaseRFONTSem(rfto, this, NULL, NULL, NULL);
|
|
}
|
|
|
|
return pxo;
|
|
}
|
|
|
|
|
|
|
|
GLYPHBITS *UMPDOBJ::CacheGlyphBits(
|
|
GLYPHBITS *pgb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Thunk and cache GLYPHBITS structure returned by FONTOBJ_cGetGlyphs
|
|
|
|
Arguments:
|
|
|
|
pgb - Points to kernel mode GLYPHBITS structure
|
|
|
|
Return Value:
|
|
|
|
Pointer to user mode GLYPHBITS structure
|
|
NULL if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
GLYPHBITS *pgbum = NULL;
|
|
ULONG ulSize;
|
|
|
|
ASSERTGDI(pgb != NULL, "No glyph bits!\n");
|
|
|
|
ulSize = offsetof(GLYPHBITS, aj) +
|
|
((pgb->sizlBitmap.cx + 7) / 8) * pgb->sizlBitmap.cy;
|
|
|
|
if (ulSize <= m_gbSize)
|
|
{
|
|
//
|
|
// Reuse previous GLYPHBITS buffer if possible
|
|
//
|
|
|
|
pgbum = m_pgb;
|
|
}
|
|
else
|
|
{
|
|
if ((pgbum = (GLYPHBITS *) AllocUserMem(ulSize)) != NULL)
|
|
{
|
|
m_pgb = pgbum;
|
|
m_gbSize = ulSize;
|
|
}
|
|
}
|
|
|
|
if (pgbum != NULL)
|
|
RtlCopyMemory(pgbum, pgb, ulSize);
|
|
|
|
return pgbum;
|
|
}
|
|
|
|
|
|
|
|
PATHOBJ *UMPDOBJ::CacheGlyphPath(
|
|
PATHOBJ *ppo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Thunk and cache PATHOBJ structure returned by FONTOBJ_cGetGlyphs
|
|
|
|
Arguments:
|
|
|
|
pgb - Points to kernel mode PATHOBJ structure
|
|
|
|
Return Value:
|
|
|
|
Pointer to user mode PATHOBJ structure
|
|
NULL if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
ASSERTGDI(ppo != NULL, "No glyph path!\n");
|
|
|
|
if (m_poGlyph.umobj != NULL)
|
|
{
|
|
//
|
|
// Reuse the previous PATHOBJ if possible
|
|
//
|
|
|
|
*((PATHOBJ *) m_poGlyph.umobj) = *ppo;
|
|
m_poGlyph.kmobj = ppo;
|
|
|
|
ppo = (PATHOBJ *) m_poGlyph.umobj;
|
|
}
|
|
else if (! ppoGlyph(&ppo))
|
|
ppo = NULL;
|
|
|
|
return ppo;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// User mode data structure used for storing the surface object
|
|
// thunked by UMPDOBJ::LockSurface.
|
|
//
|
|
|
|
typedef struct _UMSO {
|
|
|
|
DWORD dwSignature;
|
|
HSURF hsurf;
|
|
SURFOBJ so;
|
|
|
|
} UMSO, *PUMSO;
|
|
|
|
#define UMSO_SIGNATURE 'UMSO'
|
|
|
|
|
|
|
|
SURFOBJ *UMPDOBJ::LockSurface(
|
|
HSURF hsurf
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Implement EngLockSurface for user mode printer driver
|
|
|
|
Arguments:
|
|
|
|
hsurf - Handle to the surface to be locked
|
|
|
|
Return Value:
|
|
|
|
Pointer to a user-mode SURFOBJ structure corresponding to
|
|
the specified surface handle. NULL if there is an error.
|
|
|
|
--*/
|
|
|
|
{
|
|
SURFOBJ *psokm;
|
|
PUMSO pumso = NULL;
|
|
|
|
if (hsurf == NULL || (psokm = EngLockSurface(hsurf)) == NULL)
|
|
return NULL;
|
|
|
|
//
|
|
// Check if the surface bitmap uses kernel mode memory
|
|
//
|
|
|
|
if (psokm->pvBits != NULL &&
|
|
psokm->iType == STYPE_BITMAP &&
|
|
IS_SYSTEM_ADDRESS(psokm->pvBits))
|
|
{
|
|
WARNING("EngLockSurface can't handle kernel mode bitmap\n");
|
|
}
|
|
else if (pumso = (PUMSO) EngAllocUserMem(sizeof(UMSO), UMPD_MEMORY_TAG))
|
|
{
|
|
//
|
|
// We're can't allocate memory from our cache here because
|
|
// pso returned by EngLockSurface may potentially out-live
|
|
// the current DDI entrypoint and/or the current thread.
|
|
//
|
|
|
|
pumso->dwSignature = UMSO_SIGNATURE;
|
|
pumso->hsurf = hsurf;
|
|
pumso->so = *psokm;
|
|
|
|
//
|
|
// if this is a surface that has been called by EngAssociateSurface,
|
|
// we give them back the original dhpdev
|
|
//
|
|
if (pumso->so.dhpdev)
|
|
{
|
|
PUMDHPDEV pUMdhpdev = (PUMDHPDEV)pumso->so.dhpdev;
|
|
pumso->so.dhpdev = pUMdhpdev->dhpdev;
|
|
}
|
|
}
|
|
|
|
EngUnlockSurface(psokm);
|
|
|
|
return pumso ? &pumso->so : NULL;
|
|
}
|
|
|
|
|
|
|
|
VOID UMPDOBJ::UnlockSurface(
|
|
SURFOBJ *pso
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Implement EngUnlockSurface for user mode printer driver
|
|
|
|
Arguments:
|
|
|
|
pso - Pointer to user mode SURFOBJ to be unlocked
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
PUMSO pumso;
|
|
|
|
if (pso != NULL)
|
|
{
|
|
__try
|
|
{
|
|
pumso = (PUMSO) ((PBYTE) pso - offsetof(UMSO, so));
|
|
|
|
ProbeForRead (pumso, sizeof(UMSO), sizeof(BYTE));
|
|
|
|
if (pumso->dwSignature != UMSO_SIGNATURE ||
|
|
pumso->hsurf == NULL)
|
|
{
|
|
WARNING("Invalid surface in EngUnlockSurface\n");
|
|
return;
|
|
}
|
|
|
|
EngFreeUserMem(pumso);
|
|
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("Bad user mode SURFOBJ\n");
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
SURFOBJ *UMPDSURFOBJ::GetLockedSURFOBJ(
|
|
SURFOBJ *pso
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Map a user mode SURFOBJ to its kernel mode counterpart.
|
|
This pointer must be returned by a previous called to
|
|
UMPDOBJ::LockSurface.
|
|
|
|
Arguments:
|
|
|
|
pso - Pointer to user mode SURFOBJ
|
|
|
|
Return Value:
|
|
|
|
Pointer to kernel mode SURFOBJ corresponding to the specified
|
|
user mode SURFOBJ. NULL if there is an error.
|
|
|
|
--*/
|
|
|
|
{
|
|
PUMSO pumso;
|
|
HSURF hsurf = NULL;
|
|
|
|
if (pso != NULL)
|
|
{
|
|
__try
|
|
{
|
|
pumso = (PUMSO) ((PBYTE) pso - offsetof(UMSO, so));
|
|
|
|
ProbeForRead (pumso, sizeof(UMSO), sizeof(BYTE));
|
|
|
|
if (pumso->dwSignature == UMSO_SIGNATURE)
|
|
hsurf = pumso->hsurf;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("Bad user mode SURFOBJ\n");
|
|
hsurf = NULL;
|
|
}
|
|
}
|
|
|
|
return hsurf ? EngLockSurface(hsurf) : NULL;
|
|
}
|
|
|
|
#endif // !_GDIPLUS_
|
|
|