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

851 lines
22 KiB

/*++
Copyright (c) 1997-1999 Microsoft Corporation
Module Name:
umpd.cxx
Abstract:
User-mode printer driver support
Environment:
Windows NT 5.0
Revision History:
07/8/97 -lingyunw-
Created it.
--*/
#include "precomp.hxx"
#if !defined(_GDIPLUS_)
extern PFN gpUMDriverFunc[];
static const ULONG aiFuncRequired[] =
{
INDEX_DrvEnablePDEV,
INDEX_DrvCompletePDEV,
INDEX_DrvDisablePDEV,
};
//
// ()---()
// / o o \
// ___-( )-___
// --------------(,,,----\_/----,,,)--------------------------------------
// O
//
// BOOL UMPD_ldevFillTable
// Fill the ldev function dispatch table for user mode printer drivers
//
// Returns
// BOOLEAN
//
// History:
// 7/17/97 -- Lingyun Wang [lingyunw] -- Wrote it.
//
// -----------------------------------------------------------------------
// | |---| |
// _-+ | | +-_
// (,,,/ \,,,)
UMPD_ldevFillTable(
PLDEV pldev,
BOOL * pbDrvFn)
{
//
// Put the UMPD kernel stubs in the function table.
//
ULONG i;
PFN *ppfnTable = pldev->apfn;
BOOL bRet = TRUE;
//
// fill with zero pointers to avoid possibility of accessing
// incorrect fields later
//
RtlZeroMemory(ppfnTable, INDEX_LAST*sizeof(PFN));
//
// Set UMPD thunk pointers in pldev->apfn.
//
for (i = 0; i < INDEX_LAST; i++)
{
if (pbDrvFn[i])
{
ppfnTable[i] = gpUMDriverFunc[i];
}
}
if (bRet)
{
//
// Check for required driver functions.
//
i = sizeof(aiFuncRequired) / sizeof(ULONG);
while (i--)
{
if (ppfnTable[aiFuncRequired[i]] == (PFN) NULL)
{
ASSERTGDI(FALSE,"UMPDldevFillTable: a required function is missing from driver\n");
return(FALSE);
}
}
}
//
// Always hook up UMPDDRVFREE so we can free our kernel copies
//
ppfnTable[INDEX_DrvFree] = gpUMDriverFunc[INDEX_DrvFree];
return(bRet);
}
//
// ()---()
// / o o \
// ___-( )-___
// --------------(,,,----\_/----,,,)--------------------------------------
// O
//
// BOOL UMPD_ldevLoadDriver
// User mode printer drivers load driver routine. Create a ldev and
// fill up the function table.
//
// Returns
// BOOLEAN
//
// History:
// 7/17/97 -- Lingyun Wang [lingyunw] -- Wrote it.
//
// -----------------------------------------------------------------------
// | |---| |
// _-+ | | +-_
// (,,,/ \,,,)
PLDEV
UMPD_ldevLoadDriver(
LPWSTR pwszDriver,
LDEVTYPE ldt)
{
PLDEV pldev;
PFN *ppdrvfn;
TRACE_INIT(("ldevLoadInternal ENTERING\n"));
//
// Allocate memory for the LDEV.
//
pldev = (PLDEV) EngAllocMem(FL_ZERO_MEMORY, sizeof(LDEV), UMPD_MEMORY_TAG);
if (pldev)
{
//
// Call the Enable entry point.
//
PVOID umpdCookie;
BOOL bRet = FALSE;
bRet = UMPDDrvEnableDriver (pwszDriver, &umpdCookie);
if (bRet)
{
//
// fill info and apfn into pldev
//
pldev->pldevNext = NULL;
pldev->pldevPrev = NULL;
pldev->ldevType = ldt;
pldev->cldevRefs = 1;
pldev->pGdiDriverInfo = NULL;
pldev->umpdCookie = umpdCookie;
pldev->pid = (PW32PROCESS)W32GetCurrentProcess();
BOOL bDrvfn[INDEX_LAST];
if(!UMPDDrvDriverFn(umpdCookie, bDrvfn))
{
WARNING("UMPD -- unable to get driver fn support\n");
bRet = FALSE;
}
if(bRet)
{
bRet = UMPD_ldevFillTable(pldev, bDrvfn);
}
}
if (!bRet)
{
EngFreeMem(pldev);
pldev = NULL;
}
}
return pldev;
}
PPORT_MESSAGE
PROXYPORT::InitMsg(
PPROXYMSG Msg,
UM64_PVOID pvIn,
ULONG cjIn,
UM64_PVOID pvOut,
ULONG cjOut
)
{
Msg->h.u1.s1.DataLength = (short) (sizeof(*Msg) - sizeof(Msg->h));
Msg->h.u1.s1.TotalLength = (short) (sizeof(*Msg));
Msg->h.u2.ZeroInit = 0;
if(pvOut == NULL) cjOut = 0;
Msg->cjIn = cjIn;
Msg->pvIn = pvIn;
Msg->cjOut = cjOut;
Msg->pvOut = pvOut;
return( (PPORT_MESSAGE)Msg );
}
BOOL
PROXYPORT::CheckMsg(
NTSTATUS Status,
PPROXYMSG Msg,
UM64_PVOID pvOut,
ULONG cjOut
)
{
ULONG cbData = Msg->h.u1.s1.DataLength;
if (cbData == (sizeof(*Msg) - sizeof(Msg->h)))
{
if(pvOut != Msg->pvOut)
{
return(FALSE);
}
if(cjOut != Msg->cjOut)
{
return(FALSE);
}
}
else
{
return(FALSE);
}
return( TRUE );
}
NTSTATUS
PROXYPORT::SendRequest(
UM64_PVOID pvIn,
ULONG cjIn,
UM64_PVOID pvOut,
ULONG cjOut
)
{
NTSTATUS Status;
PROXYMSG Request;
PROXYMSG Reply;
InitMsg( &Request, pvIn, cjIn, pvOut, cjOut );
Status = ZwRequestWaitReplyPort( pp->PortHandle,
(PPORT_MESSAGE)&Request,
(PPORT_MESSAGE)&Reply
);
if (!NT_SUCCESS( Status ))
{
return( Status );
}
if (Reply.h.u2.s2.Type == LPC_REPLY)
{
if (!CheckMsg( Status, &Reply, pvOut, cjOut ))
{
return(STATUS_UNSUCCESSFUL);
}
}
else
{
return(STATUS_UNSUCCESSFUL);
}
return( Status );
}
UM64_PVOID
PROXYPORT::HeapAlloc(ULONG inSize)
{
SSIZE_T ptr;
if(pp->ClientMemoryAllocSize + inSize > pp->ClientMemorySize)
return NULL;
ptr = pp->ClientMemoryBase + (SSIZE_T)pp->ClientMemoryAllocSize + pp->ServerMemoryDelta;
pp->ClientMemoryAllocSize += inSize;
return (UM64_PVOID)ptr;
}
PROXYPORT::PROXYPORT(ULONGLONG inMaxSize)
{
NTSTATUS Status;
PORT_VIEW ClientView;
ULONG MaxMessageLength;
LARGE_INTEGER MaximumSize;
UNICODE_STRING PortName;
SECURITY_QUALITY_OF_SERVICE DynamicQos;
PROCESS_SESSION_INFORMATION Info;
WCHAR awcPortName[MAX_PATH] = {0};
DWORD CurrSessionId;
OBJECT_ATTRIBUTES ObjectAttributes;
pp = NULL;
if (NT_SUCCESS(Status = ZwQueryInformationProcess(NtCurrentProcess(),
ProcessSessionInformation,
&Info,
sizeof(Info),
NULL)))
{
CurrSessionId = Info.SessionId;
swprintf(awcPortName, L"%s_%x",L"\\RPC Control\\UmpdProxy", CurrSessionId);
DynamicQos.Length = 0;
DynamicQos.ImpersonationLevel = SecurityImpersonation;
DynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
DynamicQos.EffectiveOnly = TRUE;
pp = (ProxyPort *) PALLOCMEM(sizeof(ProxyPort), 'tppG');
if(pp != NULL)
{
pp->ClientMemoryBase = 0;
pp->ClientMemorySize = 0;
pp->ClientMemoryAllocSize = 0;
pp->PortHandle = NULL;
pp->ServerMemoryBase = 0;
pp->ServerMemoryDelta = 0;
pp->hSecure = 0;
Status = STATUS_SUCCESS;
RtlInitUnicodeString( &PortName, awcPortName );
MaximumSize.QuadPart = inMaxSize;
ClientView.SectionHandle = 0;
InitializeObjectAttributes(&ObjectAttributes,
0,
OBJ_KERNEL_HANDLE,
0,
0);
Status = ZwCreateSection( &ClientView.SectionHandle,
SECTION_MAP_READ | SECTION_MAP_WRITE,
&ObjectAttributes,
&MaximumSize,
PAGE_READWRITE,
SEC_COMMIT,
NULL
);
if (NT_SUCCESS( Status ))
{
ClientView.Length = sizeof( ClientView );
ClientView.SectionOffset = 0;
ClientView.ViewSize = (LPC_SIZE_T) inMaxSize;
ClientView.ViewBase = 0;
ClientView.ViewRemoteBase = 0;
Status = ZwConnectPort( &pp->PortHandle,
&PortName,
&DynamicQos,
&ClientView,
NULL,
(PULONG)&MaxMessageLength,
NULL,
0
);
if (NT_SUCCESS( Status ))
{
pp->hSecure = MmSecureVirtualMemory(ClientView.ViewBase, ClientView.ViewSize, PAGE_READWRITE);
if (pp->hSecure)
{
pp->SectionHandle = ClientView.SectionHandle;
pp->ClientMemoryBase = (SSIZE_T)ClientView.ViewBase;
pp->ClientMemorySize = ClientView.ViewSize;
pp->ServerMemoryBase = (SSIZE_T)ClientView.ViewRemoteBase;
pp->ServerMemoryDelta = pp->ServerMemoryBase - pp->ClientMemoryBase;
}
}
else
{
WARNING("PROXYPORT::PROXYPORT failed to connect lpc port\n");
}
}
else
{
WARNING("PROXYPORT::PROXYPORT failed to create section\n");
}
if(!NT_SUCCESS( Status ) || pp->hSecure == 0)
{
if (ClientView.SectionHandle)
{
ZwClose(ClientView.SectionHandle);
}
if (pp->PortHandle)
{
ZwClose( pp->PortHandle );
}
VFREEMEM(pp);
pp = NULL;
}
}
}
}
VOID
PROXYPORT::Close()
{
ASSERTGDI(pp->PortHandle, "PROXYPORT::Close() invalid port handle\n");
ASSERTGDI(pp->SectionHandle, "PROXYPORT::Close() invalid shared section handle\n");
ASSERTGDI(pp->hSecure, "PROXYPORT::Close() invalid hSecure handle\n");
if (pp->hSecure)
{
MmUnsecureVirtualMemory(pp->hSecure);
}
if (pp->SectionHandle)
{
if (!ZwClose(pp->SectionHandle))
{
WARNING("ZwClose failed to close the shred section handle in PROXYPORT::Close\n");
}
}
if (pp->PortHandle != NULL)
{
if (!ZwClose( pp->PortHandle ))
{
WARNING("ZwClose failed to close the lpc port handle in PROXYPORT::Close\n");
}
}
VFREEMEM(pp);
}
/*
BOOL UMPDReleaseRFONTSem()
Used by umpd printing, releasing RFONT caching semaphores
*/
BOOL UMPDReleaseRFONTSem(
RFONTOBJ& rfo,
PUMPDOBJ pumpdobj,
ULONG* pfl,
ULONG* pnumLinks,
BOOL** ppFaceLink
)
{
BOOL bUMPDOBJ, *pFaceLink = NULL;
ULONG numLinks = 0;
if (!rfo.bValid())
return FALSE;
if (pumpdobj && pfl == NULL && pnumLinks == NULL && ppFaceLink == NULL)
{
bUMPDOBJ = TRUE;
}
else if (pumpdobj == NULL && pfl && pnumLinks && ppFaceLink)
{
bUMPDOBJ = FALSE;
*pfl = 0;
*pnumLinks = 0;
}
else
{
ASSERTGDI(0, "UMPD_ReleaseRFONTSem: it neither umpdobj nor TextOutDrvBitBlt\n");
return FALSE;
}
if (rfo.prfnt->hsemEUDC)
{
GreAcquireSemaphore(rfo.prfnt->hsemEUDC);
if (rfo.prfnt->prfntSystemTT && rfo.prfnt->prfntSystemTT->hsemCache &&
GreIsSemaphoreOwnedByCurrentThread(rfo.prfnt->prfntSystemTT->hsemCache))
{
GreReleaseSemaphore(rfo.prfnt->prfntSystemTT->hsemCache);
if (bUMPDOBJ)
pumpdobj->vSetFlags(RELEASE_SYSTTFONT);
else
*pfl |= RELEASE_SYSTTFONT;
}
if (rfo.prfnt->prfntSysEUDC && rfo.prfnt->prfntSysEUDC->hsemCache &&
GreIsSemaphoreOwnedByCurrentThread(rfo.prfnt->prfntSysEUDC->hsemCache))
{
GreReleaseSemaphore(rfo.prfnt->prfntSysEUDC->hsemCache);
if (bUMPDOBJ)
pumpdobj->vSetFlags(RELEASE_SYSEUDCFONT);
else
*pfl |= RELEASE_SYSEUDCFONT;
}
if (rfo.prfnt->prfntDefEUDC && rfo.prfnt->prfntDefEUDC->hsemCache &&
GreIsSemaphoreOwnedByCurrentThread(rfo.prfnt->prfntDefEUDC->hsemCache))
{
GreReleaseSemaphore(rfo.prfnt->prfntDefEUDC->hsemCache);
if(bUMPDOBJ)
pumpdobj->vSetFlags(RELEASE_DEFEUDCFONT);
else
*pfl |= RELEASE_DEFEUDCFONT;
}
if (numLinks = rfo.uiNumFaceNameLinks())
{
BOOL bContinue = FALSE;
if (bUMPDOBJ)
{
bContinue = pumpdobj->bAllocFontLinks(numLinks);
}
else
{
pFaceLink = numLinks > UMPD_MAX_FONTFACELINK ?
(BOOL*)PALLOCNOZ(sizeof(BOOL) * numLinks, UMPD_MEMORY_TAG) :
*ppFaceLink;
*ppFaceLink = pFaceLink;
if (pFaceLink)
{
bContinue = TRUE;
*pnumLinks = numLinks;
RtlZeroMemory(pFaceLink, sizeof(BOOL) * numLinks);
}
}
if (bContinue)
{
for(ULONG ii = 0; ii < numLinks; ii++)
{
if(rfo.prfnt->paprfntFaceName[ii] &&
rfo.prfnt->paprfntFaceName[ii]->hsemCache &&
GreIsSemaphoreOwnedByCurrentThread(rfo.prfnt->paprfntFaceName[ii]->hsemCache))
{
GreReleaseSemaphore(rfo.prfnt->paprfntFaceName[ii]->hsemCache);
if (bUMPDOBJ)
pumpdobj->vSetFontLink(ii);
else
pFaceLink[ii] = TRUE;
}
}
}
}
GreReleaseSemaphore(rfo.prfnt->hsemEUDC);
}
if (rfo.prfnt->hsemCache != NULL &&
GreIsSemaphoreOwnedByCurrentThread(rfo.prfnt->hsemCache))
{
GreReleaseSemaphore(rfo.prfnt->hsemCache);
if (bUMPDOBJ)
pumpdobj->vSetFlags(RELEASE_BASEFONT);
else
*pfl |= RELEASE_BASEFONT;
}
return TRUE;
}
/*
VOID UMPDAcquireRFONTSem()
Used by umpd printing, acquire all the RFONT caching semaphores.
*/
VOID UMPDAcquireRFONTSem(
RFONTOBJ& rfo,
PUMPDOBJ pumpdobj,
ULONG fl,
ULONG numLinks,
BOOL* pFaceLink
)
{
BOOL bUMPDOBJ = FALSE;
if (!rfo.bValid())
return;
if (pumpdobj)
{
bUMPDOBJ = TRUE;
fl = pumpdobj->GetFlags();
numLinks = pumpdobj->bLinkedFonts() ? pumpdobj->numLinkedFonts() : 0;
}
if ((fl & RELEASE_BASEFONT) && rfo.prfnt->hsemCache != NULL)
{
GreAcquireSemaphore(rfo.prfnt->hsemCache);
if (bUMPDOBJ)
pumpdobj->vClearFlags(RELEASE_BASEFONT);
}
if (rfo.prfnt->hsemEUDC)
{
GreAcquireSemaphore(rfo.prfnt->hsemEUDC);
if ((fl & RELEASE_SYSTTFONT) && rfo.prfnt->prfntSystemTT)
{
GreAcquireSemaphore(rfo.prfnt->prfntSystemTT->hsemCache);
if (bUMPDOBJ)
pumpdobj->vClearFlags(RELEASE_SYSTTFONT);
}
if ((fl & RELEASE_SYSEUDCFONT) && rfo.prfnt->prfntSysEUDC)
{
GreAcquireSemaphore(rfo.prfnt->prfntSysEUDC->hsemCache);
if (bUMPDOBJ)
pumpdobj->vClearFlags(RELEASE_SYSEUDCFONT);
}
if ((fl & RELEASE_DEFEUDCFONT) && rfo.prfnt->prfntDefEUDC)
{
GreAcquireSemaphore(rfo.prfnt->prfntDefEUDC->hsemCache);
if (bUMPDOBJ)
pumpdobj->vClearFlags(RELEASE_DEFEUDCFONT);
}
if (numLinks)
{
BOOL bAcquire;
numLinks =(numLinks > rfo.uiNumFaceNameLinks()) ? rfo.uiNumFaceNameLinks() : numLinks;
for (ULONG ii = 0; ii < numLinks; ii++)
{
bAcquire = rfo.prfnt->paprfntFaceName[ii] &&
(bUMPDOBJ ? pumpdobj->bLinkedFont(ii) : pFaceLink[ii]);
if (bAcquire)
{
GreAcquireSemaphore(rfo.prfnt->paprfntFaceName[ii]->hsemCache);
if (bUMPDOBJ)
pumpdobj->vClearFontLink(ii);
}
}
}
GreReleaseSemaphore(rfo.prfnt->hsemEUDC);
}
}
VOID TextOutBitBlt(
SURFACE *pSurf,
RFONTOBJ& rfo,
SURFOBJ *psoSrc,
SURFOBJ *psoMask,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
RECTL *prclTrg,
POINTL *pptlSrc,
POINTL *pptlMask,
BRUSHOBJ *pbo,
POINTL *pptlBrush,
ROP4 rop4
)
{
BOOL bSem = FALSE;
ULONG fl = 0, numLinks = 0;
BOOL aFaceLink[UMPD_MAX_FONTFACELINK], *pFaceLink = aFaceLink;
//
// Release rfont semaphores, otherwise holding rfont semaphores can
// disable APC queue while calling to the user mode.
//
//
// WINBUG #214225 tessiew 10-27-2000 Blackcomb: re-visit the RFONT.hsemCache acquiring/releasing issue
// Need to revisit the font semaphore problem in Blackcomb
// It seems that a thread doesn't need to hold the font caching semaphore
// during the whole GreExtTextOutWLocked call.
//
PDEVOBJ po(pSurf->hdev());
if (po.bPrinter() && po.bUMPD() && rfo.bValid())
{
bSem = UMPDReleaseRFONTSem(rfo, NULL, &fl, &numLinks, &pFaceLink);
}
// call driver BitBlt
(*(pSurf->pfnBitBlt())) (pSurf->pSurfobj(),
psoSrc,
psoMask,
pco,
pxlo,
prclTrg,
pptlSrc,
pptlMask,
pbo,
pptlBrush,
rop4);
// acquire the font semaphore(s)
if (bSem)
{
UMPDAcquireRFONTSem(rfo, NULL, fl, numLinks, pFaceLink);
if (pFaceLink && pFaceLink != aFaceLink)
{
VFREEMEM(pFaceLink);
}
}
}
BOOL GetETMFontManagement(
RFONTOBJ& rfo,
PDEVOBJ pdo,
SURFOBJ *pso,
FONTOBJ *pfo,
ULONG iEsc,
ULONG cjIn,
PVOID pvIn,
ULONG cjOut,
PVOID pvOut
)
{
BOOL bRet;
BOOL bSem = FALSE;
ULONG fl = 0, numLinks = 0;
BOOL aFaceLink[UMPD_MAX_FONTFACELINK], *pFaceLink = aFaceLink;
//
// Release rfont semaphores, otherwise holding rfont semaphores can
// disable APC queue while calling to the user mode.
//
//
// WINBUG #214225 tessiew 10-27-2000 Blackcomb: re-visit the RFONT.hsemCache acquiring/releasing issue
// Need to revisit the font semaphore problem in Blackcomb
// It seems that a thread doesn't need to hold the font caching semaphore
// during the whole GreExtTextOutWLocked call.
if (pdo.bPrinter() && pdo.bUMPD() && rfo.bValid())
{
bSem = UMPDReleaseRFONTSem(rfo, NULL, &fl, &numLinks, &pFaceLink);
}
bRet = pdo.FontManagement(pso,
pfo,
iEsc,
cjIn,
pvIn,
cjOut,
pvOut);
// acquire the font semaphore(s)
if (bSem)
{
UMPDAcquireRFONTSem(rfo, NULL, fl, numLinks, pFaceLink);
if (pFaceLink && pFaceLink != aFaceLink)
{
VFREEMEM(pFaceLink);
}
}
return bRet;
}
#else // _GDIPLUS_
extern "C" PUMPD UMPDDrvEnableDriver(PWSTR, ULONG);
PLDEV
UMPD_ldevLoadDriver(
PWSTR pwszDriver,
LDEVTYPE ldt
)
{
PLDEV pldev = NULL;
PUMPD pUMPD;
if ((pUMPD = UMPDDrvEnableDriver(pwszDriver, DDI_DRIVER_VERSION_NT5_01_SP1)) &&
(pldev = (PLDEV) PALLOCMEM(sizeof(LDEV), UMPD_MEMORY_TAG)))
{
pldev->pldevNext = (PLDEV)pUMPD;
pldev->pldevPrev = NULL;
pldev->ldevType = ldt;
pldev->cldevRefs = 1;
pldev->pGdiDriverInfo = NULL;
RtlCopyMemory(pldev->apfn, pUMPD->apfn, sizeof(pldev->apfn));
return pldev;
}
else
{
if (pldev)
VFREEMEM(pldev);
return NULL;
}
}
#endif // _GDIPLUS_
VOID UMPD_ldevUnloadImage(PLDEV pldev)
{
if (pldev)
EngFreeMem(pldev);
return;
}