|
|
/*++
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; }
|