2918 lines
79 KiB
C++
2918 lines
79 KiB
C++
/******************************Module*Header*******************************\
|
||
* Module Name: spool.cxx
|
||
*
|
||
* Created: 21-Feb-1995 10:13:18
|
||
* Author: Eric Kutter [erick]
|
||
*
|
||
* Copyright (c) 1993-1999 Microsoft Corporation
|
||
*
|
||
\**************************************************************************/
|
||
|
||
#include "precomp.hxx"
|
||
|
||
|
||
|
||
DWORD DriverInfo1Offsets[]={offsetof(DRIVER_INFO_1W, pName),
|
||
0xFFFFFFFF};
|
||
|
||
DWORD DriverInfo2Offsets[]={offsetof(DRIVER_INFO_2W, pName),
|
||
offsetof(DRIVER_INFO_2W, pEnvironment),
|
||
offsetof(DRIVER_INFO_2W, pDriverPath),
|
||
offsetof(DRIVER_INFO_2W, pDataFile),
|
||
offsetof(DRIVER_INFO_2W, pConfigFile),
|
||
0xFFFFFFFF};
|
||
DWORD DriverInfo3Offsets[]={offsetof(DRIVER_INFO_3W, pName),
|
||
offsetof(DRIVER_INFO_3W, pEnvironment),
|
||
offsetof(DRIVER_INFO_3W, pDriverPath),
|
||
offsetof(DRIVER_INFO_3W, pDataFile),
|
||
offsetof(DRIVER_INFO_3W, pConfigFile),
|
||
offsetof(DRIVER_INFO_3W, pHelpFile),
|
||
offsetof(DRIVER_INFO_3W, pDependentFiles),
|
||
offsetof(DRIVER_INFO_3W, pMonitorName),
|
||
offsetof(DRIVER_INFO_3W, pDefaultDataType),
|
||
0xFFFFFFFF};
|
||
|
||
DWORD DriverInfo1Strings[]={offsetof(DRIVER_INFO_1W, pName),
|
||
0xFFFFFFFF};
|
||
|
||
DWORD DriverInfo2Strings[]={offsetof(DRIVER_INFO_2W, pName),
|
||
offsetof(DRIVER_INFO_2W, pEnvironment),
|
||
offsetof(DRIVER_INFO_2W, pDriverPath),
|
||
offsetof(DRIVER_INFO_2W, pDataFile),
|
||
offsetof(DRIVER_INFO_2W, pConfigFile),
|
||
0xFFFFFFFF};
|
||
DWORD DriverInfo3Strings[]={offsetof(DRIVER_INFO_3W, pName),
|
||
offsetof(DRIVER_INFO_3W, pEnvironment),
|
||
offsetof(DRIVER_INFO_3W, pDriverPath),
|
||
offsetof(DRIVER_INFO_3W, pDataFile),
|
||
offsetof(DRIVER_INFO_3W, pConfigFile),
|
||
offsetof(DRIVER_INFO_3W, pHelpFile),
|
||
offsetof(DRIVER_INFO_3W, pMonitorName),
|
||
offsetof(DRIVER_INFO_3W, pDefaultDataType),
|
||
0xFFFFFFFF};
|
||
|
||
|
||
DWORD FormInfo1Offsets[] = { offsetof(FORM_INFO_1W, pName),
|
||
0xFFFFFFFF};
|
||
|
||
|
||
DWORD PrinterInfo1Offsets[]={offsetof(PRINTER_INFO_1W, pDescription),
|
||
offsetof(PRINTER_INFO_1W, pName),
|
||
offsetof(PRINTER_INFO_1W, pComment),
|
||
0xFFFFFFFF};
|
||
|
||
DWORD PrinterInfo2Offsets[]={offsetof(PRINTER_INFO_2W, pServerName),
|
||
offsetof(PRINTER_INFO_2W, pPrinterName),
|
||
offsetof(PRINTER_INFO_2W, pShareName),
|
||
offsetof(PRINTER_INFO_2W, pPortName),
|
||
offsetof(PRINTER_INFO_2W, pDriverName),
|
||
offsetof(PRINTER_INFO_2W, pComment),
|
||
offsetof(PRINTER_INFO_2W, pLocation),
|
||
offsetof(PRINTER_INFO_2W, pDevMode),
|
||
offsetof(PRINTER_INFO_2W, pSepFile),
|
||
offsetof(PRINTER_INFO_2W, pPrintProcessor),
|
||
offsetof(PRINTER_INFO_2W, pDatatype),
|
||
offsetof(PRINTER_INFO_2W, pParameters),
|
||
offsetof(PRINTER_INFO_2W, pSecurityDescriptor),
|
||
0xFFFFFFFF};
|
||
|
||
DWORD PrinterInfo3Offsets[]={offsetof(PRINTER_INFO_3, pSecurityDescriptor),
|
||
0xFFFFFFFF};
|
||
|
||
DWORD PrinterInfo4Offsets[]={offsetof(PRINTER_INFO_4W, pPrinterName),
|
||
offsetof(PRINTER_INFO_4W, pServerName),
|
||
0xFFFFFFFF};
|
||
|
||
DWORD PrinterInfo5Offsets[]={offsetof(PRINTER_INFO_5W, pPrinterName),
|
||
offsetof(PRINTER_INFO_5W, pPortName),
|
||
0xFFFFFFFF};
|
||
|
||
|
||
|
||
|
||
|
||
|
||
/*********************************Class************************************\
|
||
* SPOOLMSG
|
||
*
|
||
* structure containg a message waiting to be grabbed by a spooler thread.
|
||
* This is a private structure to communicate between the applications thread
|
||
* and the spoolers thread
|
||
*
|
||
* History:
|
||
* 27-Mar-1995 -by- Eric Kutter [erick]
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
#define SPOOLMSG_DELETE_INBUF 0x00000002
|
||
#define SPOOLMSG_MAXINPUT_BUF 4
|
||
#define NO_CLIENT 1
|
||
#define NON_SPOOL_INSTANCE ((DWORD) -1)
|
||
#define MIN_DEVMODE_SIZE 72 // Win 3.1 DevMode size. Also hard-coded in yspool
|
||
|
||
typedef struct _SPOOLMSG
|
||
{
|
||
ULONG cj;
|
||
ULONG iMsg;
|
||
ULONG fl;
|
||
|
||
HSPOOLOBJ hso;
|
||
PETHREAD pthreadClient;
|
||
SECURITY_CLIENT_CONTEXT sccSecurity;
|
||
|
||
// in order to avoid extra copying into a single buffer, there are multiple
|
||
// input buffers. For example, WritePrinter uses a header buffer on the
|
||
// stack with a second buffer containing the output data.
|
||
|
||
ULONG cjIn; // combined size of input buffers
|
||
ULONG cBuf; // number of input buffers
|
||
PULONG apulIn[SPOOLMSG_MAXINPUT_BUF];// input buffers
|
||
ULONG acjIn[SPOOLMSG_MAXINPUT_BUF];
|
||
|
||
PULONG pulOut; // location to put output data
|
||
ULONG cjOut; // size of output
|
||
|
||
ULONG ulRet; // return value
|
||
ULONG ulErr; // transfer last error from spooler thread to client
|
||
|
||
struct _SPOOLMSG *pNext;
|
||
|
||
} SPOOLMSG, *PSPOOLMSG;
|
||
|
||
|
||
/*********************************Class************************************\
|
||
* SPOOLOBJ : public OBJECT
|
||
*
|
||
* a SPOOLOBJ is GDI's internal spooler object containing data need to access
|
||
* the spooler for a particular print job.
|
||
*
|
||
* Public Interface:
|
||
*
|
||
* History:
|
||
* 21-Jun-1995 -by- Eric Kutter [erick]
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
class SPOOLOBJ : public OBJECT
|
||
{
|
||
public:
|
||
|
||
KEVENT *pkevent;
|
||
HANDLE hSpool;
|
||
PVOID pvMsg;
|
||
SPOOLMSG sm;
|
||
DWORD dwFlags;
|
||
DWORD dwSpoolInstance;
|
||
GREWRITEPRINTER WritePrinter;
|
||
DWORD dwWritePrinterReturn;
|
||
};
|
||
typedef SPOOLOBJ *PSPOOLOBJ;
|
||
|
||
|
||
/**************************************************************************\
|
||
*
|
||
\**************************************************************************/
|
||
|
||
BOOL gbInitSpool = FALSE; // set/cleared as the spooler comes and goes
|
||
PW32PROCESS gpidSpool = 0; // process ID of the spooler
|
||
PEPROCESS gpeSpool = 0; // process pointer of the spooler
|
||
|
||
PKEVENT gpeventGdiSpool; // spooler lock
|
||
PKEVENT gpeventSpoolerTermination; // signals spooler termination so client threads in spooler process can exit
|
||
|
||
DWORD gdwSpoolInstance = 0; // Keeps track of the spooler instance
|
||
|
||
LONG gpInfiniteWait = TRUE; // LONG used to ensure we have one spooler thread waiting with INFINITE timeoue
|
||
|
||
// there is a queue of spool messages. Elements are removed from the head
|
||
// and added to the tail
|
||
|
||
PSPOOLMSG gpsmSpoolHead = NULL;
|
||
PSPOOLMSG gpsmSpoolTail = NULL;
|
||
|
||
int gcSpoolMsg = 0;
|
||
int gcSpoolMsgCurrent = 0;
|
||
int gcSpoolMsgMax = 0;
|
||
|
||
|
||
#define LOCKSPOOLER GreAcquireSemaphore(ghsemGdiSpool)
|
||
#define UNLOCKSPOOLER GreReleaseSemaphore(ghsemGdiSpool)
|
||
|
||
#define POFFSET(pBase,pCur) ((PBYTE)(pCur) - (PBYTE)(pBase))
|
||
|
||
|
||
/*********************************Class************************************\
|
||
* class SPOOLREF
|
||
*
|
||
* Public Interface:
|
||
*
|
||
* History:
|
||
* 22-May-1995 -by- Eric Kutter [erick]
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
class SPOOLREF
|
||
{
|
||
public:
|
||
|
||
PSPOOLOBJ pso;
|
||
|
||
SPOOLREF() {}
|
||
SPOOLREF(HANDLE hspool)
|
||
{
|
||
pso = (PSPOOLOBJ)HmgLock((HOBJ)hspool,SPOOL_TYPE);
|
||
}
|
||
|
||
|
||
~SPOOLREF()
|
||
{
|
||
if (bValid())
|
||
{
|
||
DEC_EXCLUSIVE_REF_CNT(pso);
|
||
pso = NULL;
|
||
}
|
||
}
|
||
|
||
BOOL bDelete();
|
||
BOOL GreEscapeSpool();
|
||
|
||
BOOL bValid() {return(pso != NULL); }
|
||
HSPOOLOBJ hGet() {return((HSPOOLOBJ)pso->hGet());}
|
||
PSPOOLMSG psm() {return(&pso->sm); }
|
||
|
||
// we need to know the lock count for cleanup so we don't free up a message
|
||
// when it still may be accessed.
|
||
|
||
ULONG cAltLock()
|
||
{
|
||
return(((POBJ) (pso))->ulShareCount);
|
||
}
|
||
};
|
||
|
||
|
||
class SPOOLALTREF : public SPOOLREF
|
||
{
|
||
public:
|
||
|
||
SPOOLALTREF(HANDLE hspool)
|
||
{
|
||
pso = (PSPOOLOBJ)HmgShareLock((HOBJ)hspool,SPOOL_TYPE);
|
||
}
|
||
|
||
~SPOOLALTREF()
|
||
{
|
||
if (bValid())
|
||
{
|
||
DEC_SHARE_REF_CNT(pso);
|
||
pso = NULL;
|
||
}
|
||
}
|
||
};
|
||
|
||
typedef SPOOLALTREF *PSPOOLALTREF;
|
||
|
||
|
||
|
||
class SPOOLMEMOBJ : public SPOOLREF
|
||
{
|
||
public:
|
||
|
||
SPOOLMEMOBJ();
|
||
~SPOOLMEMOBJ() {}
|
||
};
|
||
|
||
|
||
ULONG
|
||
ulFinishMessage(
|
||
PSPOOLMSG psm,
|
||
PSPOOLESC psesc,
|
||
PSPOOLALTREF sr,
|
||
PBYTE pjEscData,
|
||
ULONG cjEscData
|
||
);
|
||
|
||
BOOL AddMessage2Q(
|
||
PSPOOLMSG psm,
|
||
DWORD dwSpoolInstance
|
||
);
|
||
|
||
VOID SubtractMessageFromQ(PSPOOLMSG psmIn);
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
*
|
||
*
|
||
* History:
|
||
* 22-May-1995 -by- Eric Kutter [erick]
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
SPOOLMEMOBJ::SPOOLMEMOBJ()
|
||
{
|
||
KEVENT *pkevent = (PKEVENT) GdiAllocPoolNonPagedNS(
|
||
sizeof(KEVENT), 'lpsG');
|
||
|
||
if (pkevent == NULL)
|
||
{
|
||
pso = NULL;
|
||
}
|
||
else
|
||
{
|
||
pso = (PSPOOLOBJ)HmgAlloc(sizeof(SPOOLOBJ),SPOOL_TYPE, HMGR_ALLOC_LOCK);
|
||
|
||
if (bValid())
|
||
{
|
||
|
||
LOCKSPOOLER;
|
||
pso->dwSpoolInstance = gdwSpoolInstance;
|
||
UNLOCKSPOOLER;
|
||
|
||
pso->pkevent = pkevent;
|
||
|
||
KeInitializeEvent(
|
||
pso->pkevent,
|
||
SynchronizationEvent,
|
||
FALSE);
|
||
}
|
||
else
|
||
{
|
||
VFREEMEM(pkevent);
|
||
}
|
||
}
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
*
|
||
*
|
||
* History:
|
||
* 22-May-1995 -by- Eric Kutter [erick]
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
BOOL SPOOLREF::bDelete()
|
||
{
|
||
if (bValid())
|
||
{
|
||
VFREEMEM(pso->pkevent);
|
||
|
||
HmgFree((HOBJ)hGet());
|
||
|
||
pso = NULL;
|
||
}
|
||
return(TRUE);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* bIsProcessLocalSystem()
|
||
*
|
||
* History:
|
||
* 19-Jun-2001 -by- Barton House [bhouse]
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
static BOOL bIsProcessLocalSystem(void)
|
||
{
|
||
BOOL bResult = FALSE;
|
||
PEPROCESS peprocess;
|
||
PACCESS_TOKEN paccessToken;
|
||
NTSTATUS status;
|
||
PTOKEN_USER ptu;
|
||
|
||
peprocess = PsGetCurrentProcess();
|
||
|
||
paccessToken = PsReferencePrimaryToken(peprocess);
|
||
|
||
status = SeQueryInformationToken(paccessToken, TokenUser, (PVOID *) &ptu);
|
||
|
||
PsDereferencePrimaryToken(paccessToken);
|
||
|
||
if (NT_SUCCESS(status) == TRUE)
|
||
{
|
||
bResult = RtlEqualSid(SeExports->SeLocalSystemSid, ptu->User.Sid);
|
||
ExFreePool(ptu);
|
||
}
|
||
|
||
return bResult;
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* GreInitSpool()
|
||
*
|
||
* History:
|
||
* 21-Feb-1995 -by- Eric Kutter [erick]
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
BOOL NtGdiInitSpool()
|
||
{
|
||
BOOL bRet = FALSE;
|
||
|
||
LOCKSPOOLER;
|
||
|
||
if (gbInitSpool)
|
||
{
|
||
EngSetLastError(ERROR_INVALID_ACCESS);
|
||
WARNING("GreInitSpool - already called\n");
|
||
}
|
||
else if(!bIsProcessLocalSystem())
|
||
{
|
||
EngSetLastError(ERROR_INVALID_ACCESS);
|
||
WARNING("GreInitSpool - caller is not system\n");
|
||
}
|
||
else
|
||
{
|
||
NTSTATUS status;
|
||
|
||
// intialize the spooler events
|
||
|
||
gpeventGdiSpool = (PKEVENT) GdiAllocPoolNonPagedNS(
|
||
sizeof(KEVENT), 'gdis');
|
||
|
||
gpeventSpoolerTermination = (PKEVENT) GdiAllocPoolNonPagedNS(
|
||
sizeof(KEVENT), 'gdis');
|
||
|
||
if (gpeventGdiSpool && gpeventSpoolerTermination)
|
||
{
|
||
KeInitializeEvent(
|
||
gpeventGdiSpool,
|
||
SynchronizationEvent,
|
||
FALSE);
|
||
|
||
KeInitializeEvent(
|
||
gpeventSpoolerTermination,
|
||
NotificationEvent,
|
||
FALSE);
|
||
|
||
gbInitSpool = TRUE;
|
||
bRet = TRUE;
|
||
gpeSpool = PsGetCurrentProcess();
|
||
|
||
}
|
||
else
|
||
{
|
||
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||
|
||
if (gpeventGdiSpool)
|
||
{
|
||
VFREEMEM(gpeventGdiSpool);
|
||
gpeventGdiSpool = NULL;
|
||
}
|
||
|
||
if (gpeventSpoolerTermination)
|
||
{
|
||
VFREEMEM(gpeventSpoolerTermination);
|
||
gpeventSpoolerTermination = NULL;
|
||
}
|
||
}
|
||
|
||
gpidSpool = W32GetCurrentProcess();
|
||
|
||
if (++gdwSpoolInstance == NON_SPOOL_INSTANCE)
|
||
++gdwSpoolInstance;
|
||
}
|
||
|
||
UNLOCKSPOOLER;
|
||
|
||
return(bRet);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
*
|
||
*
|
||
* History:
|
||
* 01-Jun-1995 -by- Eric Kutter [erick]
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
VOID vCleanupSpool()
|
||
{
|
||
if (gpidSpool == W32GetCurrentProcess())
|
||
{
|
||
//DbgPrint("vCleanupSpool() - cleaning up the spooler process\n");
|
||
|
||
LOCKSPOOLER;
|
||
|
||
if (gbInitSpool == TRUE)
|
||
{
|
||
|
||
while (gpsmSpoolHead != NULL)
|
||
{
|
||
//DbgPrint("vCleanupSpool() - got another\n");
|
||
|
||
PSPOOLMSG psm = gpsmSpoolHead;
|
||
|
||
gpsmSpoolHead = psm->pNext;
|
||
|
||
// and some stats
|
||
|
||
ASSERTGDI(gcSpoolMsgCurrent > 0, "GreGetSpoolMsg - invalid count\n");
|
||
gcSpoolMsgCurrent--;
|
||
|
||
SPOOLALTREF sr(psm->hso);
|
||
|
||
if (sr.bValid())
|
||
{
|
||
KeSetEvent(sr.pso->pkevent,0,FALSE);
|
||
}
|
||
}
|
||
|
||
gpsmSpoolTail = NULL;
|
||
|
||
|
||
VFREEMEM(gpeventGdiSpool);
|
||
VFREEMEM(gpeventSpoolerTermination);
|
||
|
||
gpeventGdiSpool = NULL;
|
||
gpeventSpoolerTermination = NULL;
|
||
gbInitSpool = FALSE;
|
||
gpeSpool = NULL;
|
||
|
||
gcSpoolMsg = 0;
|
||
gcSpoolMsgCurrent = 0;
|
||
gcSpoolMsgMax = 0;
|
||
|
||
gpidSpool = NULL;
|
||
|
||
//DbgPrint("Done cleaning up spooler for this thread\n");
|
||
}
|
||
|
||
UNLOCKSPOOLER;
|
||
}
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* GreGetSpoolMessage()
|
||
*
|
||
* This is intended to be called from the spooler process (GdiGetSpoolMessage)
|
||
* to get the next spooler message out of the kernel.
|
||
*
|
||
*
|
||
* if (output buffer exists)
|
||
* copy out output buffer
|
||
*
|
||
* wait for next message
|
||
*
|
||
* copy in input buffer
|
||
*
|
||
* input:
|
||
*
|
||
* psesc - buffer to place message
|
||
* cjmsg - size of message buffer
|
||
* pulOut - buffer containing data to be copied to output buffer
|
||
* cjOut - size of output buffer
|
||
*
|
||
*
|
||
* returns:
|
||
*
|
||
* size of data placed in psesc.
|
||
*
|
||
*
|
||
* Note: the output buffer is filled by the calling routine before calling
|
||
* this function again.
|
||
*
|
||
* History:
|
||
* 21-Feb-1995 -by- Eric Kutter [erick]
|
||
*
|
||
* 6-Aug-1995 - Added Input buffer growing (Steve Wilson [swilson])
|
||
*
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
SECURITY_QUALITY_OF_SERVICE Sqos =
|
||
{
|
||
sizeof(SECURITY_QUALITY_OF_SERVICE),
|
||
SecurityImpersonation,
|
||
SECURITY_DYNAMIC_TRACKING,
|
||
FALSE
|
||
};
|
||
|
||
ULONG GreGetSpoolMessage(
|
||
PSPOOLESC psesc,
|
||
PBYTE pjEscData, // this must only be accessed under a try/except
|
||
ULONG cjEscData,
|
||
PULONG pulOut,
|
||
ULONG cjOut
|
||
)
|
||
{
|
||
ULONG ulRet = 0;
|
||
NTSTATUS status;
|
||
LONG lState;
|
||
|
||
//DbgPrint("Entered GreGetSpoolMessage\n");
|
||
|
||
if (!gbInitSpool)
|
||
{
|
||
WARNING("GreGetSpoolMessage - not initialized\n");
|
||
}
|
||
else if (gpidSpool != W32GetCurrentProcess())
|
||
{
|
||
WARNING("GreGetSpoolMessage - called from non-spooler process\n");
|
||
}
|
||
else
|
||
{
|
||
KEVENT *pkevent = NULL;
|
||
|
||
// see if we need to copy any data out
|
||
|
||
if (psesc->hso)
|
||
{
|
||
SPOOLALTREF sr(psesc->hso);
|
||
|
||
if (sr.bValid())
|
||
{
|
||
|
||
// we have found the spool obj. Now see if we really have
|
||
// an output buffer and need to copy anything.
|
||
|
||
PSPOOLMSG psm = (PSPOOLMSG)sr.pso->pvMsg;
|
||
|
||
// if we asked the spooler to grow the buffer and it succeeded
|
||
// finish copying the message and return. If it failed, we still
|
||
// need to cleanup this message and release the thread.
|
||
|
||
if (psesc->iMsg == GDISPOOL_INPUT2SMALL)
|
||
{
|
||
if (psesc->ulRet && psm)
|
||
{
|
||
return(ulFinishMessage(psm, psesc, &sr, pjEscData, cjEscData));
|
||
}
|
||
|
||
pulOut = NULL;
|
||
psesc->ulRet = 0;
|
||
}
|
||
|
||
// if we actualy have a message, we need to copy out the data
|
||
// if there is any and remember the event in order to let the
|
||
// client continue.
|
||
|
||
if (psm)
|
||
{
|
||
// if we are still impersonating the client, undo it
|
||
|
||
if (psm->pthreadClient)
|
||
{
|
||
SeStopImpersonatingClient();
|
||
SeDeleteClientSecurity(&psm->sccSecurity);
|
||
psm->pthreadClient = NULL;
|
||
}
|
||
|
||
// see if we have anything to copy out
|
||
|
||
if (pulOut && psm->pulOut)
|
||
{
|
||
if (cjOut > psm->cjOut)
|
||
cjOut = psm->cjOut;
|
||
|
||
__try
|
||
{
|
||
// this is the only place that pulOut is validated
|
||
|
||
ProbeForRead(pulOut,cjOut,sizeof(ULONG));
|
||
|
||
RtlCopyMemory(psm->pulOut,pulOut,cjOut);
|
||
|
||
psm->cjOut = cjOut;
|
||
}
|
||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
psm->cjOut = 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
psm->cjOut = 0;
|
||
}
|
||
|
||
psm->ulRet = psesc->ulRet;
|
||
psm->ulErr = EngGetLastError();
|
||
|
||
// Since to have output the message must have been synchronous,
|
||
// we need to let the other thread go now.
|
||
|
||
pkevent = sr.pso->pkevent;
|
||
}
|
||
|
||
|
||
// the spool obj is now done with this message
|
||
|
||
sr.pso->pvMsg = NULL;
|
||
}
|
||
else
|
||
{
|
||
WARNING("GreGetSpoolMessage - hso but no pso\n");
|
||
}
|
||
}
|
||
|
||
// the release of the other thread needs to be done once the SPOOLOBJ has
|
||
// been unlocked.
|
||
|
||
if (pkevent)
|
||
{
|
||
lState = KeSetEvent(pkevent,0,FALSE);
|
||
|
||
ASSERTGDI(lState == 0,"GreGetSpoolMessage - lState not 0, a\n");
|
||
}
|
||
|
||
// done with the last message. Wait for the next message.
|
||
|
||
PSPOOLMSG psm = NULL;
|
||
BOOL bDone;
|
||
LARGE_INTEGER Timeout;
|
||
|
||
// 600/(100*10(-9)) : negative value is interval, positive is absolute
|
||
Timeout.QuadPart = (LONGLONG) -6000000000; // Timeout is in 100 nsec, so 6,000,000,000 == 10 min
|
||
|
||
do
|
||
{
|
||
BOOL bGrabIt = TRUE;
|
||
bDone = TRUE;
|
||
|
||
if (gpsmSpoolHead == NULL)
|
||
{
|
||
LONG bInfiniteWait = InterlockedExchange(&gpInfiniteWait, FALSE);
|
||
|
||
//DbgPrint("\nGDISPOOL(%lx): waiting for message\n",psesc);
|
||
status = KeWaitForSingleObject(
|
||
gpeventGdiSpool,
|
||
(KWAIT_REASON)WrExecutive,
|
||
UserMode,
|
||
FALSE,
|
||
(bInfiniteWait ? NULL : &Timeout));
|
||
|
||
if(bInfiniteWait)
|
||
InterlockedExchange(&gpInfiniteWait, TRUE);
|
||
|
||
if (status == STATUS_TIMEOUT)
|
||
{
|
||
SendSimpleMessage(0, GDISPOOL_TERMINATETHREAD, NON_SPOOL_INSTANCE);
|
||
}
|
||
else if (status == STATUS_USER_APC) // Upon this return, User mode spooler does not execute
|
||
{
|
||
KeSetEvent(gpeventSpoolerTermination,0,FALSE);
|
||
return (ULONG) -1;
|
||
}
|
||
else if (!NT_SUCCESS(status))
|
||
{
|
||
WARNING("GDISPOOL: wait error\n");
|
||
bGrabIt = FALSE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//DbgPrint("\nGDISPOOL(%lx): message already there\n",psesc);
|
||
}
|
||
|
||
if (bGrabIt)
|
||
{
|
||
// now find the message and the spoolobj
|
||
|
||
LOCKSPOOLER;
|
||
|
||
if (gpsmSpoolHead == NULL)
|
||
{
|
||
bDone = FALSE;
|
||
}
|
||
else
|
||
{
|
||
psm = gpsmSpoolHead;
|
||
gpsmSpoolHead = psm->pNext;
|
||
|
||
if (gpsmSpoolHead == NULL)
|
||
gpsmSpoolTail = NULL;
|
||
|
||
// and some stats
|
||
|
||
ASSERTGDI(gcSpoolMsgCurrent > 0, "GreGetSpoolMsg - invalid count\n");
|
||
gcSpoolMsgCurrent--;
|
||
//DbgPrint(" got a message(%lx), hso = %lx - count = %ld\n",psesc,psm->hso,gcSpoolMsgCurrent);
|
||
}
|
||
|
||
UNLOCKSPOOLER;
|
||
}
|
||
|
||
} while ((psm == NULL) && !bDone);
|
||
|
||
// did we get a message?
|
||
|
||
if (psm != NULL)
|
||
{
|
||
if (psm->iMsg == GDISPOOL_TERMINATETHREAD || psm->iMsg == GDISPOOL_CLOSEPRINTER)
|
||
{
|
||
// going to terminate the thread so just get out.
|
||
|
||
ulRet = sizeof(SPOOLESC);
|
||
psesc->cj = sizeof(SPOOLESC);
|
||
psesc->iMsg = psm->iMsg;
|
||
psesc->hso = psm->hso;
|
||
|
||
if (psm->iMsg & GDISPOOL_API) // Let API messages have a spool handle
|
||
{
|
||
psesc->hSpool = psm->hso;
|
||
|
||
if (psm->iMsg & GDISPOOL_CLOSEPRINTER)
|
||
{
|
||
psesc->hso = NULL;
|
||
}
|
||
}
|
||
|
||
psesc->cjOut = 0;
|
||
VFREEMEM(psm);
|
||
}
|
||
else // Got a non-null, non-TERMINATETHREAD message to send to spooler
|
||
{
|
||
SPOOLALTREF sr(psm->hso);
|
||
|
||
if (sr.bValid())
|
||
{
|
||
if (cjEscData < psm->cjIn)
|
||
{
|
||
// set up the header
|
||
|
||
ulRet = offsetof(SPOOLESC, ajData);
|
||
|
||
psesc->cj = sizeof(SPOOLESC);
|
||
psesc->iMsg = GDISPOOL_INPUT2SMALL;
|
||
psesc->hSpool = sr.pso->hSpool;
|
||
psesc->hso = psm->hso;
|
||
sr.pso->pvMsg = (PVOID)psm;
|
||
|
||
// required message buffer size
|
||
|
||
psesc->cjOut = psm->cjIn + offsetof(SPOOLESC,ajData);
|
||
}
|
||
else
|
||
{
|
||
ulRet = ulFinishMessage(psm, psesc, &sr, pjEscData, cjEscData);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return(ulRet);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* ulFinishMessage()
|
||
*
|
||
* Fills in psesc structure and impersonates client
|
||
*
|
||
*
|
||
* History:
|
||
* 8-Aug-95 -by- Steve Wilson [swilson]
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
ULONG
|
||
ulFinishMessage(
|
||
PSPOOLMSG psm,
|
||
PSPOOLESC psesc, // this must only be accessed under a try/except
|
||
PSPOOLALTREF psr,
|
||
PBYTE pjEscData,
|
||
ULONG cjEscDAta
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
ULONG ulRet;
|
||
|
||
// impersonate the client
|
||
|
||
status = SeCreateClientSecurity(
|
||
psm->pthreadClient,
|
||
&Sqos,
|
||
FALSE,
|
||
&psm->sccSecurity);
|
||
|
||
if (NT_SUCCESS(status))
|
||
{
|
||
status = SeImpersonateClientEx(&psm->sccSecurity,NULL);
|
||
}
|
||
|
||
if (!NT_SUCCESS(status))
|
||
{
|
||
WARNING("FinishMessage - CreateClientSecurity failed\n");
|
||
psm->pthreadClient = NULL;
|
||
}
|
||
|
||
// copy the data
|
||
|
||
ulRet = 0;
|
||
|
||
if (psm->cjIn)
|
||
{
|
||
__try
|
||
{
|
||
// copy all the buffers into the input buffer
|
||
|
||
ulRet = 0;
|
||
|
||
for (DWORD i = 0; i < psm->cBuf; ++i)
|
||
{
|
||
RtlCopyMemory(pjEscData+ulRet,psm->apulIn[i],psm->acjIn[i]);
|
||
ulRet += psm->acjIn[i];
|
||
}
|
||
|
||
ASSERTGDI(ulRet == psm->cjIn,"ulFinishMessage - invalid size\n");
|
||
}
|
||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
ulRet = 0;
|
||
}
|
||
}
|
||
|
||
// if the input buffer was only temporary, delete it.
|
||
|
||
if (psm->fl & SPOOLMSG_DELETE_INBUF)
|
||
{
|
||
ASSERTGDI(psm->cBuf == 1,"ulFinishMessage - delete more than 1\n");
|
||
|
||
VFREEMEM(psm->apulIn[0]);
|
||
psm->apulIn[0] = NULL;
|
||
}
|
||
|
||
// set up the header
|
||
|
||
ulRet += offsetof(SPOOLESC,ajData);
|
||
|
||
psesc->iMsg = psm->iMsg;
|
||
psesc->cj = ulRet;
|
||
psesc->hSpool = psr->pso->hSpool;
|
||
psesc->cjOut = psm->cjOut;
|
||
|
||
psesc->hso = psm->hso;
|
||
psr->pso->pvMsg = (PVOID)psm;
|
||
|
||
return(ulRet);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* GreEscapeSpool()
|
||
*
|
||
* given a spool message, add it to the queue and notify the spooler thread
|
||
*
|
||
*
|
||
* History:
|
||
* 21-Feb-1995 -by- Eric Kutter [erick]
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
BOOL SPOOLREF::GreEscapeSpool()
|
||
{
|
||
BOOL bRet = FALSE;
|
||
NTSTATUS status;
|
||
|
||
ASSERTGDI(psm()->iMsg != GDISPOOL_TERMINATETHREAD,"GreEscapeSpool - GDISPOOL_TERMINATETHREAD\n");
|
||
ASSERTGDI(psm()->iMsg != GDISPOOL_CLOSEPRINTER,"GreEscapeSpool - GDISPOOL_CLOSEPRINTER\n");
|
||
ASSERTGDI(psm() != NULL,"GreEscapeSpool - null\n");
|
||
|
||
//DbgPrint("Entered GreEscapeSpool\n");
|
||
|
||
if (!gbInitSpool)
|
||
{
|
||
EngSetLastError(ERROR_NOT_READY);
|
||
WARNING("GreEscapeSpool - not initialized\n");
|
||
}
|
||
else if (pso->dwFlags & NO_CLIENT)
|
||
{
|
||
//DbgPrint(" GreEscapeSpool: NO_CLIENT, message received: %x\n",psm()->iMsg);
|
||
EngSetLastError(ERROR_PROCESS_ABORTED);
|
||
}
|
||
else
|
||
{ // add the message to the queue
|
||
|
||
//NOTE: we may want to reference count this in the future
|
||
psm()->pthreadClient = PsGetCurrentThread();
|
||
if (AddMessage2Q(psm(), pso->dwSpoolInstance))
|
||
{
|
||
|
||
PVOID pEvent[3];
|
||
|
||
pEvent[0] = gpeSpool;
|
||
pEvent[1] = pso->pkevent;
|
||
pEvent[2] = gpeventSpoolerTermination;
|
||
|
||
status = KeWaitForMultipleObjects( 3,
|
||
pEvent,
|
||
WaitAny,
|
||
(KWAIT_REASON)0,
|
||
UserMode,
|
||
FALSE,
|
||
0,
|
||
NULL);
|
||
|
||
switch (status)
|
||
{
|
||
case 0: // Spooler terminated
|
||
SubtractMessageFromQ(psm());
|
||
EngSetLastError(ERROR_PROCESS_ABORTED);
|
||
|
||
ASSERTGDI(cAltLock() == 0,"GreEscapeSpool - invalid lock 0\n");
|
||
bRet = FALSE;
|
||
break;
|
||
|
||
case 1: // Spooler returned
|
||
bRet = TRUE;
|
||
EngSetLastError(psm()->ulErr);
|
||
|
||
ASSERTGDI(cAltLock() == 0,"GreEscapeSpool - invalid lock 1\n");
|
||
|
||
break;
|
||
|
||
case STATUS_USER_APC: // Client terminated
|
||
case 2: // Spooler terminated, this client may be the spooler
|
||
|
||
// Stress Failure Note:
|
||
// AddMessage2Q is called above here to add a message to the message queue.
|
||
// After the message is in the queue, we leave the spooler lock and set
|
||
// gpeventGdiSpool, which wakes up the spooler thread. The spooler thread
|
||
// then grabs the message and removes it from the message queue inside the spooler
|
||
// lock. It then returns to user mode and creates a new message thread. All this
|
||
// typically works fine.
|
||
//
|
||
// Now suppose just after AddMessage2Q adds a new message and before gpeventGdiSpool
|
||
// is set, the spooler shuts down. When the spooler shuts down, STATUS_USER_APC is
|
||
// returned from the gpeventGdiSpool Wait and all spooler messaging threads will set
|
||
// gpeventSpoolerTermination, which is case 2 in this switch statement. This wakes
|
||
// up the client thread, which proceeds to terminate and frees the psm before exiting.
|
||
// Meanwhile, the spooler is down to its very last thread and calls vCleanupSpool, which
|
||
// traverses and frees the psm queue. vCleanupSpool will AV when it hits one of the freed
|
||
// messages in the queue.
|
||
//
|
||
// The problem was rarely encountered because it would only occur if the spooler shut down
|
||
// after a message was entered in the queue and before the gpeventGdiSpool event was seen.
|
||
//
|
||
// Removing the message from the queue when the spooler or client terminates should solve
|
||
// the problem. Note that this was always done for the STATUS_USER_APC case, and has now
|
||
// been added to case 0 and case 2.
|
||
//
|
||
// Steve Wilson (NT)
|
||
//
|
||
SubtractMessageFromQ(psm());
|
||
|
||
WARNING("Win32K spool: Client is dying!\n");
|
||
|
||
pso->dwFlags |= NO_CLIENT;
|
||
EngSetLastError(ERROR_PROCESS_ABORTED);
|
||
bRet = FALSE;
|
||
|
||
// we need to make sure there is no alt lock
|
||
|
||
pso->pvMsg = NULL;
|
||
|
||
while (cAltLock())
|
||
KeDelayExecutionThread(KernelMode,FALSE,gpLockShortDelay);
|
||
|
||
break;
|
||
|
||
default:
|
||
#if 1
|
||
DbgPrint("GreEscapeSpool - WaitForSingleObject failed w/ status 0x%lx\n", status);
|
||
DbgBreakPoint();
|
||
#else
|
||
WARNING("GreEscapeSpool - WaitForSingleObject failed\n");
|
||
#endif
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
return bRet;
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* SendSimpleMessage()
|
||
*
|
||
* allow a client app to send a spool message
|
||
*
|
||
*
|
||
* History:
|
||
* 21-Feb-1995 -by- Eric Kutter [erick]
|
||
* 7-Jun-1996 - Steve Wilson [SWilson] - Changed from NtGdiSpoolEsc to SendSimpleMessage
|
||
*
|
||
\**************************************************************************/
|
||
|
||
ULONG SendSimpleMessage(
|
||
HANDLE hSpool,
|
||
ULONG iMsg,
|
||
DWORD dwSpoolInstance)
|
||
{
|
||
ULONG ulRet = 0;
|
||
|
||
if (!gbInitSpool)
|
||
{
|
||
WARNING("GreEscapeSpool - not initialized\n");
|
||
}
|
||
else if (iMsg == GDISPOOL_TERMINATETHREAD || iMsg == GDISPOOL_CLOSEPRINTER)
|
||
{
|
||
PSPOOLMSG psm = (PSPOOLMSG) PALLOCMEM(sizeof(SPOOLMSG),'lpsG');
|
||
|
||
if (psm)
|
||
{
|
||
psm->cj = sizeof(SPOOLMSG);
|
||
psm->iMsg = iMsg;
|
||
psm->hso = (HSPOOLOBJ) hSpool; // This is Spooler's handle, not kernel handle
|
||
|
||
ulRet = AddMessage2Q(psm, dwSpoolInstance);
|
||
if (ulRet == FALSE)
|
||
VFREEMEM(psm);
|
||
}
|
||
}
|
||
|
||
return ulRet;
|
||
}
|
||
|
||
|
||
/*****************************
|
||
SubtractMessageFromQ()
|
||
*****************************/
|
||
|
||
VOID SubtractMessageFromQ(PSPOOLMSG psmIn)
|
||
{
|
||
PSPOOLMSG psm;
|
||
PSPOOLMSG psmPrev = NULL;
|
||
|
||
//DbgPrint("Enter SubtractMessageFromQ\n");
|
||
|
||
LOCKSPOOLER;
|
||
|
||
for (psm = gpsmSpoolHead ; psm ; psmPrev = psm , psm = psm->pNext)
|
||
{
|
||
if (psm == psmIn)
|
||
{
|
||
if (psmPrev)
|
||
{
|
||
psmPrev->pNext = psm->pNext;
|
||
|
||
if (!psmPrev->pNext)
|
||
{
|
||
ASSERTGDI(psm == gpsmSpoolTail,"SubtractMessageFromQ: Bad gpsmSpoolTail!\n");
|
||
gpsmSpoolTail = psmPrev;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
gpsmSpoolHead = psm->pNext;
|
||
|
||
if (!gpsmSpoolHead)
|
||
{
|
||
ASSERTGDI(psm == gpsmSpoolTail,"SubtractMessageFromQ: Bad gpsmSpoolTail!\n");
|
||
gpsmSpoolTail = gpsmSpoolHead;
|
||
}
|
||
}
|
||
|
||
// gcSpool stuff is for debug purposes only
|
||
gcSpoolMsgCurrent--;
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
UNLOCKSPOOLER;
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* BOOL AddMessage2Q (PSPOOLMSG psm)
|
||
*
|
||
* History:
|
||
* 6-Aug-1995 -by- Steve Wilson [swilson]
|
||
*
|
||
\**************************************************************************/
|
||
|
||
BOOL AddMessage2Q(PSPOOLMSG psm, DWORD dwSpoolInstance)
|
||
{
|
||
BOOL bRet = FALSE;
|
||
|
||
// add the message to the queue
|
||
|
||
LOCKSPOOLER;
|
||
|
||
if (psm == NULL)
|
||
{
|
||
bRet = FALSE;
|
||
}
|
||
else if ((dwSpoolInstance != gdwSpoolInstance) && (dwSpoolInstance != NON_SPOOL_INSTANCE))
|
||
{
|
||
EngSetLastError(ERROR_INVALID_HANDLE);
|
||
bRet = FALSE;
|
||
}
|
||
else
|
||
{
|
||
if (gpsmSpoolTail)
|
||
{
|
||
// list isn't empty, so add it to the list
|
||
|
||
ASSERTGDI(gpsmSpoolHead != NULL,"GreEscapeSpool - head is null\n");
|
||
|
||
gpsmSpoolTail->pNext = psm;
|
||
}
|
||
else
|
||
{
|
||
ASSERTGDI(gpsmSpoolHead == NULL,"GreEscapeSpool - head not null\n");
|
||
gpsmSpoolHead = psm;
|
||
}
|
||
|
||
// the tail now always points to the new element
|
||
|
||
gpsmSpoolTail = psm;
|
||
psm->pNext = NULL;
|
||
|
||
// and some stats
|
||
|
||
gcSpoolMsg++;
|
||
gcSpoolMsgCurrent++;
|
||
if (gcSpoolMsgCurrent > gcSpoolMsgMax)
|
||
gcSpoolMsgMax = gcSpoolMsgCurrent;
|
||
|
||
bRet = TRUE;
|
||
}
|
||
|
||
UNLOCKSPOOLER;
|
||
|
||
// notify the spooler that there is a message ready
|
||
if (bRet == TRUE)
|
||
{
|
||
KeSetEvent(gpeventGdiSpool,0,FALSE);
|
||
}
|
||
|
||
return bRet;
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* GreOpenPrinterW()
|
||
*
|
||
* History:
|
||
* 28-Mar-1995 -by- Eric Kutter [erick]
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
BOOL
|
||
WINAPI
|
||
GreOpenPrinterW(
|
||
GREOPENPRINTER *pOpenPrinter,
|
||
LPHANDLE phPrinter)
|
||
{
|
||
ULONG bRet;
|
||
ULONG ul;
|
||
|
||
SPOOLMEMOBJ spmo; // Creates (PSPOOLOBJ) spmo.pso, containing pkevent, hSpool, pvMsg
|
||
|
||
//DbgPrint("Enter GreOpenPrinterW\n");
|
||
|
||
if (spmo.bValid())
|
||
{
|
||
// setup the message
|
||
|
||
PSPOOLMSG psm = spmo.psm();
|
||
|
||
psm->cj = sizeof(SPOOLMSG);
|
||
psm->iMsg = GDISPOOL_OPENPRINTER;
|
||
psm->fl = 0;
|
||
psm->cBuf = 1;
|
||
psm->cjIn = pOpenPrinter->cj;
|
||
psm->acjIn[0] = pOpenPrinter->cj;
|
||
psm->apulIn[0]= (PULONG)pOpenPrinter;
|
||
psm->pulOut = (PULONG)&spmo.pso->hSpool;
|
||
|
||
psm->cjOut = sizeof(*phPrinter);
|
||
|
||
psm->hso = spmo.hGet(); // returns ((HSPOOLOBJ) pso)
|
||
|
||
if (spmo.GreEscapeSpool() && psm->ulRet)
|
||
{
|
||
*phPrinter = (HANDLE)spmo.hGet();
|
||
|
||
bRet = TRUE;
|
||
}
|
||
else
|
||
{
|
||
spmo.bDelete();
|
||
bRet = FALSE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
bRet = FALSE;
|
||
}
|
||
|
||
return(bRet);
|
||
}
|
||
|
||
|
||
/*****************************************************************************
|
||
* GreEnumFormsW
|
||
*
|
||
* History:
|
||
* 25/7/95 by Steve Wilson [swilson]
|
||
* Wrote it.
|
||
*******************************************************************************/
|
||
|
||
BOOL
|
||
WINAPI
|
||
GreEnumFormsW(
|
||
HANDLE hSpool,
|
||
GREENUMFORMS *pEnumForms,
|
||
GREENUMFORMS *pEnumFormsReturn,
|
||
LONG cjOut )
|
||
{
|
||
ULONG bRet = FALSE;
|
||
SPOOLREF sr(hSpool);
|
||
|
||
if (sr.bValid())
|
||
{
|
||
PSPOOLMSG psm = sr.psm();
|
||
|
||
//DbgPrint("Enter GreEnumFormsW\n");
|
||
|
||
// setup the message
|
||
|
||
psm->cj = sizeof(SPOOLMSG);
|
||
psm->iMsg = GDISPOOL_ENUMFORMS;
|
||
psm->fl = 0;
|
||
psm->cBuf = 1;
|
||
psm->cjIn = pEnumForms->cj;
|
||
psm->acjIn[0] = pEnumForms->cj;
|
||
psm->apulIn[0]= (PULONG) pEnumForms;
|
||
psm->pulOut = (PULONG) pEnumFormsReturn;
|
||
psm->cjOut = cjOut;
|
||
psm->hso = (HSPOOLOBJ) hSpool;
|
||
|
||
bRet = sr.GreEscapeSpool() ? psm->ulRet : FALSE;
|
||
}
|
||
|
||
return bRet;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* GreGenericW
|
||
*
|
||
* History:
|
||
* 25-Jul-95 by Steve Wilson [swilson]
|
||
* Wrote it.
|
||
*******************************************************************************/
|
||
|
||
BOOL
|
||
GreGenericW(
|
||
HANDLE hSpool,
|
||
PULONG pX,
|
||
PULONG pXReturn,
|
||
LONG cjOut,
|
||
LONG MessageID,
|
||
ULONG ulFlag )
|
||
{
|
||
ULONG bRet = FALSE;
|
||
SPOOLREF sr(hSpool);
|
||
|
||
if (sr.bValid())
|
||
{
|
||
PSPOOLMSG psm = sr.psm();
|
||
|
||
//DbgPrint("Enter GreGenericW\n");
|
||
|
||
// setup the message
|
||
|
||
psm->cj = sizeof(SPOOLMSG);
|
||
psm->iMsg = MessageID;
|
||
psm->fl = ulFlag;
|
||
psm->cBuf = 1;
|
||
psm->cjIn = pX ? *(PULONG) pX : 0; // Must be sure first element of pX is LONG cj: (pX->cj)
|
||
psm->acjIn[0] = pX ? *(PULONG) pX : 0; // Must be sure first element of pX is LONG cj: (pX->cj)
|
||
psm->apulIn[0]= (PULONG) pX;
|
||
psm->pulOut = (PULONG) pXReturn;
|
||
psm->cjOut = cjOut;
|
||
psm->hso = (HSPOOLOBJ) hSpool;
|
||
|
||
bRet = sr.GreEscapeSpool() ? psm->ulRet : FALSE;
|
||
}
|
||
|
||
return bRet;
|
||
}
|
||
|
||
/*****************************************************************************\
|
||
* GrePrinterDriverUnloadW
|
||
*
|
||
* This function is used to a send a message to the spooler when a printer
|
||
* driver is unloaded (i.e the DC count on the driver goes to zero)
|
||
* On receipt of this message, the spooler attempts to upgrade the driver if
|
||
* neccesary.
|
||
*
|
||
* History:
|
||
* 11/17/97 by Ramanathan N Venkatapathy
|
||
* Wrote it.
|
||
\*****************************************************************************/
|
||
|
||
BOOL GrePrinterDriverUnloadW(
|
||
LPWSTR pDriverName
|
||
)
|
||
{
|
||
BOOL bRet = FALSE;
|
||
ULONG cbDriverName;
|
||
LPWSTR pDriverFile = NULL;
|
||
|
||
SPOOLMEMOBJ spmo;
|
||
|
||
// Check for invalid printer driver names.
|
||
if (!pDriverName || !*pDriverName)
|
||
{
|
||
return bRet;
|
||
}
|
||
|
||
// Copy the driver name into another buffer.
|
||
cbDriverName = (wcslen(pDriverName) + 1) * sizeof(WCHAR);
|
||
pDriverFile = (LPWSTR) PALLOCMEM(cbDriverName, 'lpsG');
|
||
|
||
if (spmo.bValid() && pDriverFile)
|
||
{
|
||
PSPOOLMSG psm = spmo.psm();
|
||
|
||
memcpy(pDriverFile, pDriverName, cbDriverName);
|
||
|
||
psm->cj = sizeof(SPOOLMSG);
|
||
psm->iMsg = GDISPOOL_UNLOADDRIVER_COMPLETE;
|
||
psm->fl = 0;
|
||
|
||
psm->cBuf = 1;
|
||
psm->cjIn = cbDriverName;
|
||
psm->apulIn[0] = (PULONG) pDriverFile;
|
||
psm->acjIn[0] = cbDriverName;
|
||
|
||
psm->pulOut = NULL;
|
||
psm->cjOut = 0;
|
||
|
||
psm->hso = spmo.hGet();
|
||
|
||
bRet = spmo.GreEscapeSpool() && psm->ulRet;
|
||
|
||
spmo.bDelete();
|
||
}
|
||
|
||
if (pDriverFile) {
|
||
VFREEMEM(pDriverFile);
|
||
}
|
||
|
||
return bRet;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* GreGetPrinterDriverW
|
||
*
|
||
* History:
|
||
* 4/14/1995 by Gerrit van Wingerden [gerritv]
|
||
* Wrote it.
|
||
*******************************************************************************/
|
||
|
||
BOOL WINAPI GreGetPrinterDriverW(
|
||
HANDLE hSpool,
|
||
GREGETPRINTERDRIVER *pGetPrinterDriver,
|
||
GREGETPRINTERDRIVER *pGetPrinterDriverReturn,
|
||
LONG cjOut
|
||
)
|
||
{
|
||
ULONG bRet = FALSE;
|
||
SPOOLREF sr(hSpool);
|
||
|
||
if (sr.bValid())
|
||
{
|
||
PSPOOLMSG psm = sr.psm();
|
||
|
||
//DbgPrint("Enter GreGetPrinterDriverW\n");
|
||
|
||
// setup the message
|
||
|
||
psm->cj = sizeof(SPOOLMSG);
|
||
psm->iMsg = GDISPOOL_GETPRINTERDRIVER;
|
||
psm->fl = 0;
|
||
psm->cBuf = 1;
|
||
psm->cjIn = pGetPrinterDriver->cj;
|
||
psm->acjIn[0] = pGetPrinterDriver->cj;
|
||
psm->apulIn[0]= (PULONG) pGetPrinterDriver;
|
||
psm->pulOut = (PULONG)pGetPrinterDriverReturn;
|
||
psm->cjOut = cjOut;
|
||
psm->hso = (HSPOOLOBJ)hSpool;
|
||
|
||
if( sr.GreEscapeSpool() )
|
||
{
|
||
bRet = psm->ulRet;
|
||
}
|
||
else
|
||
{
|
||
bRet = FALSE;
|
||
}
|
||
}
|
||
|
||
return(bRet);
|
||
}
|
||
|
||
/****************************************************************************
|
||
* BOOL StartPagePrinter( HANDLE hPrinter )
|
||
*
|
||
* History:
|
||
* 4/28/1995 by Gerrit van Wingerden [gerritv]
|
||
* Wrote it.
|
||
*****************************************************************************/
|
||
|
||
BOOL
|
||
WINAPI
|
||
StartPagePrinter(
|
||
HANDLE hSpool
|
||
)
|
||
{
|
||
BOOL bRet = FALSE;
|
||
SPOOLREF sr(hSpool);
|
||
|
||
if (sr.bValid())
|
||
{
|
||
PSPOOLMSG psm = sr.psm();
|
||
|
||
//DbgPrint("Enter StartPagePrinter\n");
|
||
|
||
psm->cj = sizeof(SPOOLMSG);
|
||
psm->iMsg = GDISPOOL_STARTPAGEPRINTER;
|
||
psm->fl = 0;
|
||
psm->cBuf = 0;
|
||
psm->cjIn = 0;
|
||
psm->pulOut = NULL;
|
||
psm->cjOut = 0;
|
||
psm->hso = (HSPOOLOBJ)hSpool;
|
||
|
||
if( sr.GreEscapeSpool() )
|
||
{
|
||
bRet = psm->ulRet;
|
||
}
|
||
}
|
||
|
||
return(bRet);
|
||
}
|
||
|
||
|
||
/****************************************************************************
|
||
* BOOL EndPagePrinter( HANDLE hPrinter )
|
||
*
|
||
* History:
|
||
* 4/28/1995 by Gerrit van Wingerden [gerritv]
|
||
* Wrote it.
|
||
*****************************************************************************/
|
||
|
||
BOOL
|
||
WINAPI
|
||
EndPagePrinter(
|
||
HANDLE hSpool
|
||
)
|
||
{
|
||
BOOL bRet = FALSE;
|
||
SPOOLREF sr(hSpool);
|
||
|
||
if (sr.bValid())
|
||
{
|
||
PSPOOLMSG psm = sr.psm();
|
||
|
||
//DbgPrint("Enter EndPagePrinter\n");
|
||
|
||
psm->cj = sizeof(SPOOLMSG);
|
||
psm->iMsg = GDISPOOL_ENDPAGEPRINTER;
|
||
psm->fl = 0;
|
||
psm->cBuf = 0;
|
||
psm->cjIn = 0;
|
||
psm->pulOut = NULL;
|
||
psm->cjOut = 0;
|
||
psm->hso = (HSPOOLOBJ)hSpool;
|
||
|
||
if(sr.GreEscapeSpool())
|
||
{
|
||
bRet = psm->ulRet;
|
||
}
|
||
}
|
||
|
||
return(bRet);
|
||
|
||
}
|
||
|
||
|
||
/****************************************************************************
|
||
* BOOL EndDocPrinter( HANDLE hPrinter )
|
||
*
|
||
* History:
|
||
* 4/28/1995 by Gerrit van Wingerden [gerritv]
|
||
* Wrote it.
|
||
*****************************************************************************/
|
||
|
||
BOOL
|
||
WINAPI
|
||
EndDocPrinter(
|
||
HANDLE hSpool
|
||
)
|
||
{
|
||
BOOL bRet = FALSE;
|
||
SPOOLREF sr(hSpool);
|
||
|
||
if (sr.bValid())
|
||
{
|
||
PSPOOLMSG psm = sr.psm();
|
||
|
||
|
||
//DbgPrint("Enter EndDocPrinter\n");
|
||
|
||
psm->cj = sizeof(SPOOLMSG);
|
||
psm->iMsg = GDISPOOL_ENDDOCPRINTER;
|
||
psm->fl = 0;
|
||
psm->cBuf = 0;
|
||
psm->cjIn = 0;
|
||
psm->pulOut = NULL;
|
||
psm->cjOut = 0;
|
||
psm->hso = (HSPOOLOBJ)hSpool;
|
||
|
||
if( sr.GreEscapeSpool() )
|
||
{
|
||
bRet = (DWORD) psm->ulRet;
|
||
}
|
||
}
|
||
|
||
return(bRet);
|
||
|
||
}
|
||
|
||
|
||
/****************************************************************************
|
||
* ClosePrinter( HANDLE hPrinter )
|
||
*
|
||
* History:
|
||
* 12-Feb-1996 -by- Steve Wilson (swilson)
|
||
* Wrote it.
|
||
*****************************************************************************/
|
||
|
||
BOOL
|
||
WINAPI
|
||
ClosePrinter(
|
||
HANDLE hSpool
|
||
)
|
||
{
|
||
SPOOLREF sr(hSpool);
|
||
|
||
if (sr.bValid())
|
||
{
|
||
//DbgPrint("Enter ClosePrinter: %d\n", sr.pso->hSpool);
|
||
|
||
SendSimpleMessage(sr.pso->hSpool, GDISPOOL_CLOSEPRINTER, sr.pso->dwSpoolInstance);
|
||
|
||
sr.bDelete();
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* AbortPrinter()
|
||
*
|
||
* History:
|
||
* 18-Jul-1995 -by- Steve Wilson (swilson)
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
BOOL
|
||
WINAPI
|
||
AbortPrinter(
|
||
HANDLE hPrinter)
|
||
{
|
||
BOOL bRet = FALSE;
|
||
SPOOLREF sr(hPrinter);
|
||
|
||
if (sr.bValid())
|
||
{
|
||
PSPOOLMSG psm = sr.psm();
|
||
|
||
|
||
//DbgPrint("Enter AbortPrinter\n");
|
||
|
||
psm->cj = sizeof(SPOOLMSG);
|
||
psm->iMsg = GDISPOOL_ABORTPRINTER;
|
||
psm->fl = 0;
|
||
psm->cBuf = 0;
|
||
psm->cjIn = 0;
|
||
psm->pulOut = NULL;
|
||
psm->cjOut = 0;
|
||
psm->hso = (HSPOOLOBJ)hPrinter;
|
||
|
||
if( sr.GreEscapeSpool() )
|
||
{
|
||
bRet = (DWORD) psm->ulRet;
|
||
}
|
||
}
|
||
|
||
return(bRet);
|
||
}
|
||
|
||
|
||
|
||
/****************************************************************************
|
||
* StartDocPrinter()
|
||
*
|
||
* History:
|
||
* 4/28/1995 by Gerrit van Wingerden [gerritv]
|
||
* Wrote it.
|
||
*****************************************************************************/
|
||
|
||
DWORD
|
||
WINAPI
|
||
StartDocPrinterW(
|
||
HANDLE hPrinter,
|
||
DWORD dwLevel,
|
||
LPBYTE lpbDocInfo
|
||
)
|
||
{
|
||
LONG cj = offsetof(GRESTARTDOCPRINTER,alData);
|
||
LONG cjDocName = 0;
|
||
LONG cjOutputFile = 0;
|
||
LONG cjDatatype = 0;
|
||
DOC_INFO_1W* pDocInfo = (DOC_INFO_1W*) lpbDocInfo;
|
||
DWORD ret = 0;
|
||
|
||
//DbgPrint("Enter StartDocPrinterW\n");
|
||
|
||
ASSERTGDI( dwLevel == 1, "StartDocPrinter: dwLevel != 1\n" );
|
||
ASSERTGDI( lpbDocInfo != NULL, "StarDocPrinter lpbDocInfo is NULL\n");
|
||
|
||
// first we need to compute the sizes.
|
||
|
||
if (pDocInfo->pDocName)
|
||
{
|
||
cjDocName = (wcslen(pDocInfo->pDocName) + 1) * sizeof(WCHAR);
|
||
|
||
cj += cjDocName;
|
||
cj = (cj + 3) & ~3;
|
||
}
|
||
|
||
if (pDocInfo->pOutputFile)
|
||
{
|
||
cjOutputFile = (wcslen(pDocInfo->pOutputFile) + 1) * sizeof(WCHAR);
|
||
|
||
cj += cjOutputFile;
|
||
cj = (cj + 3) & ~3;
|
||
}
|
||
|
||
if (pDocInfo->pDatatype)
|
||
{
|
||
cjDatatype = (wcslen(pDocInfo->pDatatype) + 1) * sizeof(WCHAR);
|
||
|
||
cj += cjDatatype;
|
||
cj = (cj + 3) & ~3;
|
||
}
|
||
|
||
|
||
SPOOLREF sr(hPrinter);
|
||
|
||
if (sr.bValid())
|
||
{
|
||
PLONG plData;
|
||
|
||
GRESTARTDOCPRINTER *pStartDocPrinter;
|
||
pStartDocPrinter = (GRESTARTDOCPRINTER*)PALLOCNOZ(cj,'lpsG');
|
||
|
||
if (pStartDocPrinter)
|
||
{
|
||
PSPOOLMSG psm = sr.psm();
|
||
|
||
// we got memory, now copy the stuff in
|
||
|
||
pStartDocPrinter->cj = cj;
|
||
plData = pStartDocPrinter->alData;
|
||
|
||
pStartDocPrinter->cjDocName = (cjDocName + 3) & ~3;
|
||
pStartDocPrinter->cjOutputFile = (cjOutputFile + 3) & ~3;
|
||
pStartDocPrinter->cjDatatype = (cjDatatype + 3) & ~3;
|
||
|
||
if (pDocInfo->pDocName)
|
||
{
|
||
memcpy(plData,pDocInfo->pDocName,cjDocName);
|
||
plData += (cjDocName+3)/4;
|
||
}
|
||
|
||
if (pDocInfo->pOutputFile)
|
||
{
|
||
memcpy(plData,pDocInfo->pOutputFile,cjOutputFile);
|
||
plData += (cjOutputFile+3)/4;
|
||
}
|
||
|
||
if (pDocInfo->pDatatype)
|
||
{
|
||
memcpy(plData,pDocInfo->pDatatype,cjDatatype);
|
||
plData += (cjDatatype+3)/4;
|
||
}
|
||
|
||
ASSERTGDI(POFFSET(pStartDocPrinter,plData) == cj,
|
||
"EngStartDocPrinter - sizes are wrong\n");
|
||
|
||
// pStartDocPrinter now contains all needed data, call out
|
||
// setup the message
|
||
|
||
psm->cj = sizeof(SPOOLMSG);
|
||
psm->iMsg = GDISPOOL_STARTDOCPRINTER;
|
||
psm->fl = 0;
|
||
psm->cBuf = 1;
|
||
psm->cjIn = pStartDocPrinter->cj;
|
||
psm->acjIn[0] = pStartDocPrinter->cj;
|
||
psm->apulIn[0]= (PULONG)pStartDocPrinter;
|
||
psm->pulOut = NULL;
|
||
psm->cjOut = 0;
|
||
psm->hso = (HSPOOLOBJ)hPrinter;
|
||
|
||
if( sr.GreEscapeSpool() )
|
||
{
|
||
ret = (DWORD) psm->ulRet;
|
||
}
|
||
|
||
VFREEMEM(pStartDocPrinter);
|
||
}
|
||
}
|
||
|
||
return(ret);
|
||
|
||
}
|
||
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* OpenPrinterW()
|
||
*
|
||
* History:
|
||
* 05-Apr-1995 -by- Eric Kutter [erick]
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
BOOL
|
||
WINAPI
|
||
OpenPrinterW(
|
||
LPWSTR pPrinterName,
|
||
LPHANDLE phPrinter,
|
||
LPPRINTER_DEFAULTSW pDefault)
|
||
{
|
||
LONG cjName = 0;
|
||
LONG cjDatatype = 0;
|
||
LONG cjDevMode = 0;
|
||
LONG cj = offsetof(GREOPENPRINTER,alData);
|
||
BOOL bRet = FALSE;
|
||
|
||
PLONG plData;
|
||
|
||
GREOPENPRINTER *pOpenPrinter;
|
||
|
||
//DbgPrint("Enter OpenPrinterW\n");
|
||
|
||
// first we need to compute the sizes.
|
||
|
||
if (pPrinterName)
|
||
{
|
||
cjName = (wcslen(pPrinterName) + 1) * sizeof(WCHAR);
|
||
|
||
cj += cjName;
|
||
cj = (cj + 3) & ~3;
|
||
}
|
||
|
||
if (pDefault)
|
||
{
|
||
if (pDefault->pDatatype)
|
||
{
|
||
cjDatatype = (wcslen(pDefault->pDatatype) + 1) * sizeof(WCHAR);
|
||
|
||
cj += cjDatatype;
|
||
cj = (cj + 3) & ~3;
|
||
}
|
||
|
||
if (pDefault->pDevMode)
|
||
{
|
||
|
||
//DbgPrint("cjMinDevmode = %d, dmSize = %d, dmDriverExtra = %d\n", MIN_DEVMODE_SIZE, pDefault->pDevMode->dmSize, pDefault->pDevMode->dmDriverExtra);
|
||
|
||
cjDevMode = pDefault->pDevMode->dmSize + pDefault->pDevMode->dmDriverExtra;
|
||
|
||
if (cjDevMode < MIN_DEVMODE_SIZE)
|
||
{
|
||
EngSetLastError(ERROR_INVALID_PARAMETER);
|
||
return bRet;
|
||
}
|
||
|
||
cj += cjDevMode;
|
||
cj = (cj + 3) & ~3;
|
||
}
|
||
|
||
}
|
||
|
||
// allocate the memory
|
||
|
||
pOpenPrinter = (GREOPENPRINTER*)PALLOCNOZ(cj,'lpsG');
|
||
|
||
if (pOpenPrinter)
|
||
{
|
||
// we got memory, now copy the stuff in
|
||
|
||
pOpenPrinter->cj = cj;
|
||
pOpenPrinter->pd = *pDefault;
|
||
plData = pOpenPrinter->alData;
|
||
|
||
pOpenPrinter->cjName = (cjName + 3) & ~3;
|
||
pOpenPrinter->cjDatatype = (cjDatatype + 3) & ~3;
|
||
pOpenPrinter->cjDevMode = (cjDevMode + 3) & ~3;
|
||
|
||
if (pPrinterName)
|
||
{
|
||
memcpy(plData,pPrinterName,cjName);
|
||
plData += (cjName+3)/4;
|
||
}
|
||
|
||
if (pDefault)
|
||
{
|
||
if (pDefault->pDatatype)
|
||
{
|
||
pOpenPrinter->pd.pDatatype = (WCHAR*)POFFSET(pOpenPrinter,plData);
|
||
memcpy(plData,pDefault->pDatatype,cjDatatype);
|
||
plData += (cjDatatype+3)/4;
|
||
}
|
||
|
||
if (pDefault->pDevMode)
|
||
{
|
||
pOpenPrinter->pd.pDevMode = (PDEVMODEW)POFFSET(pOpenPrinter,plData);
|
||
memcpy(plData,pDefault->pDevMode,cjDevMode);
|
||
plData += (cjDevMode+3)/4;
|
||
}
|
||
}
|
||
|
||
ASSERTGDI(POFFSET(pOpenPrinter,plData) == cj,
|
||
"EngOpenPrinter - sizes are wrong\n");
|
||
|
||
// pOpenPrinter now contains all needed data, call out
|
||
|
||
bRet = GreOpenPrinterW(pOpenPrinter,phPrinter);
|
||
|
||
|
||
VFREEMEM(pOpenPrinter);
|
||
}
|
||
|
||
return(bRet);
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* void MarshallUpStructure( LPBYTE lpStructure, LPDWORD lpOffsets )
|
||
*
|
||
* This routine does pointer adjustment to offsets within the buffer
|
||
*
|
||
* History:
|
||
* 6/30/1995 by Muhunthan Sivapragasam (MuhuntS)
|
||
* Got from spoolss code
|
||
*******************************************************************************/
|
||
|
||
void
|
||
MarshallUpStructure(
|
||
LPBYTE lpStructure,
|
||
LPDWORD lpOffsets
|
||
)
|
||
{
|
||
register DWORD i=0;
|
||
|
||
while (lpOffsets[i] != -1) {
|
||
|
||
if ((*(LPBYTE *)(lpStructure+lpOffsets[i]))) {
|
||
(*(LPBYTE *)(lpStructure+lpOffsets[i]))+=(ULONG_PTR)lpStructure;
|
||
}
|
||
|
||
i++;
|
||
}
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* BOOL ValidateString( LPWSTR pString, PBYTE pBuffer, LONG cjLength )
|
||
*
|
||
* This routine validates a LPWSTR to make sure that it really lies inside of a buffer.
|
||
*
|
||
* History:
|
||
* 4/19/1995 by Gerrit van Wingerden [gerritv]
|
||
* Wrote it.
|
||
*******************************************************************************/
|
||
|
||
BOOL
|
||
ValidateString(
|
||
LPWSTR pString,
|
||
PBYTE pBuffer,
|
||
LONG cjLength )
|
||
{
|
||
LPWSTR pEnd = (LPWSTR) ( pBuffer + cjLength );
|
||
|
||
if( pString > pEnd || pString < (LPWSTR) pBuffer )
|
||
{
|
||
return(FALSE);
|
||
}
|
||
|
||
while( *pString && pString < pEnd )
|
||
{
|
||
pString++;
|
||
}
|
||
|
||
return( pString < pEnd );
|
||
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* BOOL ValidateStrings( LPBYTE lpStructure, LPDWORD lpOffsets, LONG cjLength )
|
||
*
|
||
* This routine validates all the strings in the structure to make sure they really lie inside of a buffer.
|
||
*
|
||
* History:
|
||
* 6/30/1995 by Muhunthan Sivapragasam (MuhuntS)
|
||
* Wrote it.
|
||
*******************************************************************************/
|
||
BOOL
|
||
ValidateStrings(
|
||
LPBYTE lpStructure,
|
||
LPDWORD lpOffsets,
|
||
LONG cjLength
|
||
)
|
||
{
|
||
register DWORD i=0;
|
||
|
||
while (lpOffsets[i] != -1)
|
||
{
|
||
|
||
if ( (*(LPWSTR *) (lpStructure+lpOffsets[i])) &&
|
||
!ValidateString(*(LPWSTR *) (lpStructure+lpOffsets[i]),
|
||
lpStructure,
|
||
cjLength) )
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
i++;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* BOOL ValidateDependentFiles( LPWSTR pString, PBYTE pBuffer, LONG cjLength )
|
||
*
|
||
* This routine validates DependentFiles field (which is a list of strings
|
||
* up to \0\0) to make sure that it really lies inside of a buffer.
|
||
*
|
||
* History:
|
||
* 6/30/1995 by Muhunthan Sivapragasam
|
||
* Wrote it.
|
||
*******************************************************************************/
|
||
|
||
BOOL
|
||
ValidateDependentFiles(
|
||
LPWSTR pString,
|
||
PBYTE pBuffer,
|
||
LONG cjLength )
|
||
{
|
||
LPWSTR pEnd = (LPWSTR) ( pBuffer + cjLength );
|
||
|
||
if( pString > pEnd || pString < (LPWSTR) pBuffer )
|
||
{
|
||
return(FALSE);
|
||
}
|
||
|
||
while( ( *pString || *(pString+1) ) && pString < pEnd )
|
||
{
|
||
pString++;
|
||
}
|
||
|
||
return( pString < pEnd );
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* EngEnumForms()
|
||
*
|
||
* History:
|
||
* 7/24/1995 by Steve Wilson [swilson]
|
||
* Wrote it.
|
||
*******************************************************************************/
|
||
|
||
BOOL
|
||
WINAPI
|
||
EngEnumForms(
|
||
HANDLE hPrinter,
|
||
DWORD dwLevel,
|
||
LPBYTE lpbForms,
|
||
DWORD cbBuf,
|
||
LPDWORD pcbNeeded,
|
||
LPDWORD pcbReturned
|
||
)
|
||
{
|
||
LONG cj;
|
||
DWORD cjReturn;
|
||
BOOL bRet = FALSE;
|
||
GREENUMFORMS *pEnumForms, *pEnumFormsReturn;
|
||
|
||
//DbgPrint("Enter EngEnumFormsW\n");
|
||
|
||
if(!pcbNeeded || !pcbReturned)
|
||
{
|
||
EngSetLastError(ERROR_INVALID_PARAMETER);
|
||
return FALSE;
|
||
}
|
||
|
||
cj = sizeof(GREENUMFORMS);
|
||
|
||
// Allocate TO buffer
|
||
pEnumForms = (GREENUMFORMS *) PALLOCMEM(cj, 'lpsG');
|
||
|
||
// Marshall TO buffer
|
||
if (pEnumForms) {
|
||
|
||
pEnumForms->cj = cj;
|
||
pEnumForms->cjData = cbBuf;
|
||
pEnumForms->dwLevel = dwLevel;
|
||
|
||
// Allocate RETURN buffer
|
||
pEnumFormsReturn = (GREENUMFORMS *) PALLOCNOZ(cjReturn = sizeof(GREENUMFORMS) + cbBuf, 'lpsG');
|
||
|
||
// SEND MESSAGE
|
||
if (pEnumFormsReturn) {
|
||
bRet = GreEnumFormsW(hPrinter, pEnumForms, pEnumFormsReturn, cjReturn);
|
||
|
||
// Fill in return sizes
|
||
*pcbNeeded = pEnumFormsReturn->cjData; // # return data bytes
|
||
*pcbReturned = pEnumFormsReturn->nForms; // # forms in return data
|
||
|
||
// UnMarshall Message
|
||
if (bRet) {
|
||
|
||
ASSERTGDI(*pcbNeeded <= cbBuf,"EnumFormsW - error\n");
|
||
|
||
if (lpbForms && *pcbNeeded <= cbBuf) {
|
||
// Copy returned data into supplied FORM_INFO_1 structure
|
||
memcpy(lpbForms, pEnumFormsReturn->alData, pEnumFormsReturn->cjData);
|
||
|
||
DWORD i;
|
||
|
||
for (i = 0 ; i < *pcbReturned ; ++i, lpbForms += sizeof(FORM_INFO_1W)) {
|
||
MarshallUpStructure(lpbForms, FormInfo1Offsets);
|
||
}
|
||
}
|
||
}
|
||
VFREEMEM(pEnumFormsReturn);
|
||
}
|
||
VFREEMEM(pEnumForms);
|
||
}
|
||
return bRet;
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* EngGetPrinter()
|
||
*
|
||
* History:
|
||
* 9/30/1995 by Steve Wilson [swilson]
|
||
* Wrote it.
|
||
*******************************************************************************/
|
||
BOOL
|
||
WINAPI
|
||
EngGetPrinter(
|
||
HANDLE hPrinter,
|
||
DWORD dwLevel,
|
||
LPBYTE pPrinter,
|
||
DWORD cbBuf,
|
||
LPDWORD pcbNeeded
|
||
)
|
||
{
|
||
LONG cj;
|
||
DWORD cjReturn;
|
||
BOOL bRet = FALSE;
|
||
GREGETPRINTER *pGetPrinter, *pGetPrinterReturn;
|
||
|
||
DWORD *pOffsets;
|
||
|
||
|
||
//DbgPrint("Enter EngGetPrinter\n");
|
||
|
||
if (!pcbNeeded)
|
||
{
|
||
EngSetLastError(ERROR_INVALID_PARAMETER);
|
||
return FALSE;
|
||
}
|
||
|
||
switch (dwLevel)
|
||
{
|
||
case 1:
|
||
pOffsets = PrinterInfo1Offsets;
|
||
break;
|
||
|
||
case 2:
|
||
pOffsets = PrinterInfo2Offsets;
|
||
break;
|
||
|
||
case 3:
|
||
pOffsets = PrinterInfo3Offsets;
|
||
break;
|
||
|
||
case 4:
|
||
pOffsets = PrinterInfo4Offsets;
|
||
break;
|
||
|
||
case 5:
|
||
pOffsets = PrinterInfo5Offsets;
|
||
break;
|
||
|
||
default:
|
||
EngSetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
cj = sizeof(GREGETPRINTER);
|
||
|
||
// Allocate TO buffer
|
||
pGetPrinter = (GREGETPRINTER *) PALLOCMEM(cj, 'lpsG');
|
||
|
||
// Marshall TO buffer
|
||
if (pGetPrinter)
|
||
{
|
||
|
||
pGetPrinter->cj = cj;
|
||
pGetPrinter->cjData = cbBuf;
|
||
pGetPrinter->dwLevel = dwLevel;
|
||
|
||
// Allocate RETURN buffer
|
||
pGetPrinterReturn = (GREGETPRINTER *) PALLOCNOZ(cjReturn = sizeof(GREGETPRINTER) + cbBuf, 'lpsG');
|
||
|
||
// SEND MESSAGE
|
||
if (pGetPrinterReturn)
|
||
{
|
||
bRet = GreGenericW(hPrinter, (PULONG) pGetPrinter, (PULONG) pGetPrinterReturn, cjReturn, GDISPOOL_GETPRINTER, 0);
|
||
|
||
// Fill in return size
|
||
*pcbNeeded = pGetPrinterReturn->cjData;
|
||
|
||
// UnMarshall Message
|
||
if (bRet)
|
||
{
|
||
ASSERTGDI(*pcbNeeded <= cbBuf,"EngGetPrinter - error\n");
|
||
|
||
if (pPrinter && *pcbNeeded <= cbBuf)
|
||
{
|
||
memcpy(pPrinter, pGetPrinterReturn->alData, pGetPrinterReturn->cjData);
|
||
MarshallUpStructure(pPrinter, pOffsets);
|
||
}
|
||
}
|
||
VFREEMEM(pGetPrinterReturn);
|
||
}
|
||
VFREEMEM(pGetPrinter);
|
||
}
|
||
return bRet;
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* EngGetForm()
|
||
*
|
||
* History:
|
||
* 7/24/1995 by Steve Wilson [swilson]
|
||
* Wrote it.
|
||
*******************************************************************************/
|
||
|
||
BOOL
|
||
WINAPI
|
||
EngGetForm(
|
||
HANDLE hPrinter,
|
||
LPWSTR pFormName,
|
||
DWORD dwLevel,
|
||
LPBYTE lpbForm,
|
||
DWORD cbBuf,
|
||
LPDWORD pcbNeeded
|
||
)
|
||
{
|
||
LONG cj, cjFormName;
|
||
DWORD cjReturn;
|
||
BOOL bRet = FALSE;
|
||
GREGETFORM *pGetForm, *pGetFormReturn;
|
||
|
||
//DbgPrint("Enter EngGetForm\n");
|
||
|
||
if (!pcbNeeded)
|
||
{
|
||
EngSetLastError(ERROR_INVALID_PARAMETER);
|
||
return FALSE;
|
||
}
|
||
|
||
// Accumulate sizes of base struct plus strings
|
||
cj = sizeof(GREGETFORM);
|
||
cj += (cjFormName = pFormName ? (wcslen(pFormName) + 1)*sizeof *pFormName : 0);
|
||
|
||
// Allocate TO buffer
|
||
pGetForm = (GREGETFORM *) PALLOCMEM(cj, 'lpsG');
|
||
|
||
// Marshall TO buffer
|
||
if (pGetForm)
|
||
{
|
||
pGetForm->cj = cj;
|
||
pGetForm->cjData = cbBuf;
|
||
pGetForm->dwLevel = dwLevel;
|
||
|
||
if (pFormName)
|
||
{
|
||
memcpy(pGetForm->alData,pFormName,cjFormName);
|
||
}
|
||
|
||
// Allocate RETURN buffer
|
||
pGetFormReturn = (GREGETFORM *) PALLOCNOZ(cjReturn = sizeof(GREGETFORM) + cbBuf, 'lpsG');
|
||
|
||
// SEND MESSAGE
|
||
if (pGetFormReturn)
|
||
{
|
||
bRet = GreGenericW(hPrinter, (PULONG) pGetForm, (PULONG) pGetFormReturn, cjReturn, GDISPOOL_GETFORM, 0);
|
||
|
||
if (bRet)
|
||
{
|
||
|
||
// Fill in return sizes
|
||
*pcbNeeded = pGetFormReturn->cjData; // # return data bytes
|
||
|
||
// UnMarshall Message
|
||
if (lpbForm && bRet)
|
||
{
|
||
|
||
if (*pcbNeeded <= cbBuf)
|
||
memcpy(lpbForm, pGetFormReturn->alData, pGetFormReturn->cjData);
|
||
else
|
||
ASSERTGDI(*pcbNeeded <= cbBuf,"GetFormW - error\n");
|
||
|
||
MarshallUpStructure(lpbForm, FormInfo1Offsets);
|
||
|
||
}
|
||
}
|
||
VFREEMEM(pGetFormReturn);
|
||
}
|
||
VFREEMEM(pGetForm);
|
||
}
|
||
return bRet;
|
||
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* GetPrinterDriverW()
|
||
*
|
||
* History:
|
||
* 4/19/1995 by Gerrit van Wingerden [gerritv]
|
||
* Wrote it.
|
||
*******************************************************************************/
|
||
|
||
BOOL WINAPI GetPrinterDriverW(
|
||
HANDLE hPrinter,
|
||
LPWSTR pEnvironment,
|
||
DWORD dwLevel,
|
||
LPBYTE lpbDrvInfo,
|
||
DWORD cbBuf,
|
||
LPDWORD pcbNeeded
|
||
)
|
||
{
|
||
BOOL bRet = FALSE;
|
||
LONG cj, cjEnvironment;
|
||
DWORD *pOffsets, *pStrings;
|
||
|
||
//DbgPrint("Enter GetPrinterDriverW\n");
|
||
|
||
if (!pcbNeeded)
|
||
{
|
||
EngSetLastError(ERROR_INVALID_PARAMETER);
|
||
return FALSE;
|
||
}
|
||
|
||
cj = sizeof(GREGETPRINTERDRIVER);
|
||
cjEnvironment = 0;
|
||
|
||
*pcbNeeded = 0;
|
||
|
||
if( pEnvironment )
|
||
{
|
||
cjEnvironment += (wcslen(pEnvironment) + 1) * sizeof(WCHAR);
|
||
}
|
||
|
||
cj += cjEnvironment;
|
||
|
||
GREGETPRINTERDRIVER *pGetPrinterDriver;
|
||
|
||
pGetPrinterDriver = (GREGETPRINTERDRIVER*)PALLOCMEM(cj, 'lpsG');
|
||
|
||
if( pGetPrinterDriver )
|
||
{
|
||
pGetPrinterDriver->cj = cj;
|
||
pGetPrinterDriver->cjData = cbBuf;
|
||
pGetPrinterDriver->dwLevel = dwLevel;
|
||
|
||
if( pEnvironment )
|
||
{
|
||
memcpy(pGetPrinterDriver->alData,pEnvironment,cjEnvironment);
|
||
}
|
||
|
||
GREGETPRINTERDRIVER *pGetPrinterDriverReturn = NULL;
|
||
UINT cjSize = cbBuf + sizeof(GREGETPRINTERDRIVER);
|
||
|
||
pGetPrinterDriverReturn = (GREGETPRINTERDRIVER*) PALLOCNOZ(cjSize, 'lpsG');
|
||
|
||
if( pGetPrinterDriverReturn )
|
||
{
|
||
bRet = GreGetPrinterDriverW(hPrinter,pGetPrinterDriver, pGetPrinterDriverReturn, cjSize );
|
||
|
||
DWORD cjData = pGetPrinterDriverReturn->cjData;
|
||
|
||
if (bRet == FALSE)
|
||
{
|
||
if (cjData > cbBuf)
|
||
{
|
||
// need to return the size needed.
|
||
|
||
*pcbNeeded = pGetPrinterDriverReturn->cjData;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ASSERTGDI(cjData <= cbBuf,"GetPrinterDriverW - error\n");
|
||
|
||
// return the size needed whether everything fits or not
|
||
|
||
*pcbNeeded = cjData;
|
||
|
||
// only copy data and return success if everything fits
|
||
switch (dwLevel) {
|
||
case 1:
|
||
pOffsets = DriverInfo1Offsets;
|
||
pStrings = DriverInfo1Strings;
|
||
break;
|
||
|
||
case 2:
|
||
pOffsets = DriverInfo2Offsets;
|
||
pStrings = DriverInfo2Strings;
|
||
break;
|
||
|
||
case 3:
|
||
pOffsets = DriverInfo3Offsets;
|
||
pStrings = DriverInfo3Strings;
|
||
break;
|
||
|
||
default:
|
||
// We should not get here
|
||
ASSERTGDI(0, "GetPrinterDriverW invalid level\n");
|
||
}
|
||
|
||
if (lpbDrvInfo)
|
||
{
|
||
memcpy( lpbDrvInfo, pGetPrinterDriverReturn->alData, cjData );
|
||
MarshallUpStructure((LPBYTE)lpbDrvInfo, pOffsets);
|
||
if ( !ValidateStrings((LPBYTE)lpbDrvInfo, pStrings, cjData) ||
|
||
(dwLevel == 3 &&
|
||
((PDRIVER_INFO_3W) lpbDrvInfo)->pDependentFiles &&
|
||
!ValidateDependentFiles(((PDRIVER_INFO_3W) lpbDrvInfo)->pDependentFiles,
|
||
(LPBYTE)lpbDrvInfo, cjData) ) ) {
|
||
WARNING("GetPrinterDriverW: String does not fit in buffer\n");
|
||
bRet = FALSE;
|
||
}
|
||
}
|
||
}
|
||
|
||
VFREEMEM(pGetPrinterDriverReturn);
|
||
}
|
||
|
||
VFREEMEM(pGetPrinterDriver);
|
||
}
|
||
return(bRet);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
*
|
||
* Routine Name:
|
||
*
|
||
* EngGetPrinterDriver
|
||
*
|
||
* Routine Description:
|
||
*
|
||
* Arguments:
|
||
*
|
||
* Called by:
|
||
*
|
||
* Return Value:
|
||
*
|
||
\**************************************************************************/
|
||
|
||
extern "C" BOOL APIENTRY EngGetPrinterDriver(
|
||
HANDLE hPrinter
|
||
, LPWSTR pEnvironment
|
||
, DWORD dwLevel
|
||
, BYTE *lpbDrvInfo
|
||
, DWORD cbBuf
|
||
, DWORD *pcbNeeded
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
ReturnValue = GetPrinterDriverW(
|
||
hPrinter
|
||
, pEnvironment
|
||
, dwLevel
|
||
, lpbDrvInfo
|
||
, cbBuf
|
||
, pcbNeeded
|
||
);
|
||
return( ReturnValue );
|
||
}
|
||
|
||
|
||
/*******************************************************************************
|
||
* EngGetPrinterDataW()
|
||
*
|
||
* History:
|
||
* 25-Jul-95 by Steve Wilson [swilson]
|
||
* Wrote it.
|
||
*******************************************************************************/
|
||
|
||
DWORD
|
||
WINAPI
|
||
EngGetPrinterData(
|
||
HANDLE hPrinter, // IN
|
||
LPWSTR pValueName, // IN
|
||
LPDWORD pType, // OUT -- may be NULL
|
||
LPBYTE lpbData, // OUT
|
||
DWORD cbBuf, // IN
|
||
LPDWORD pcbNeeded // OUT
|
||
)
|
||
{
|
||
LONG cj, cjValueName;
|
||
DWORD cjReturn;
|
||
DWORD dwLastError = ERROR_NOT_ENOUGH_MEMORY;
|
||
GREGETPRINTERDATA *pX, *pXReturn;
|
||
|
||
//DbgPrint("Enter EngGetPrinterData\n");
|
||
|
||
if (!pcbNeeded)
|
||
{
|
||
EngSetLastError(ERROR_INVALID_PARAMETER);
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
// Accumulate sizes of base struct plus strings
|
||
cj = sizeof *pX;
|
||
cj += (cjValueName = pValueName ? (wcslen(pValueName) + 1)*sizeof *pValueName : 0);
|
||
|
||
// Allocate TO buffer
|
||
pX = (GREGETPRINTERDATA *) PALLOCMEM(cj, 'lpsG');
|
||
|
||
// Marshall TO buffer
|
||
if (pX)
|
||
{
|
||
|
||
pX->cj = cj;
|
||
pX->cjData = cbBuf; // Client's buffer size
|
||
|
||
// Write strings at end of GRE struct
|
||
if (pValueName) {
|
||
memcpy(pX->alData,pValueName,cjValueName);
|
||
pX->cjValueName = cjValueName;
|
||
}
|
||
|
||
// Allocate RETURN buffer
|
||
pXReturn = (GREGETPRINTERDATA *) PALLOCNOZ(cjReturn = sizeof *pX + cbBuf, 'lpsG');
|
||
|
||
// SEND MESSAGE
|
||
if (pXReturn)
|
||
{
|
||
// GreGenericW return value indicates success or failure of GreEscapeSpool() and KMGetPrinterData()
|
||
GreGenericW( hPrinter,
|
||
(PULONG) pX,
|
||
(PULONG) pXReturn,
|
||
cjReturn,
|
||
(LONG) GDISPOOL_GETPRINTERDATA, 0);
|
||
|
||
dwLastError = EngGetLastError();
|
||
|
||
// return from GreGenericW may be 0, meaning any number of things, including ERROR_MORE_DATA
|
||
if (dwLastError != ERROR_PROCESS_ABORTED)
|
||
{
|
||
// Fill in return sizes
|
||
if (pcbNeeded)
|
||
{
|
||
*pcbNeeded = pXReturn->dwNeeded; // # return data bytes
|
||
|
||
//DbgPrint("EngGetPrinterData *pcbNeeded = %d\n", *pcbNeeded);
|
||
}
|
||
|
||
if (pType)
|
||
*pType = pXReturn->dwType;
|
||
|
||
if (dwLastError == ERROR_SUCCESS)
|
||
{
|
||
// Copy returned data into supplied structure
|
||
if (lpbData)
|
||
{
|
||
if ((DWORD) pXReturn->cjData <= cbBuf)
|
||
memcpy(lpbData, pXReturn->alData, pXReturn->cjData);
|
||
else
|
||
ASSERTGDI((DWORD) pXReturn->cjData <= cbBuf, "GetPrinterDataW - Bad spooler buffer size\n");
|
||
}
|
||
}
|
||
}
|
||
|
||
VFREEMEM(pXReturn);
|
||
}
|
||
VFREEMEM(pX);
|
||
}
|
||
|
||
//DbgPrint("GetPrinterData return: %d\n", dwLastError);
|
||
|
||
return dwLastError;
|
||
}
|
||
|
||
|
||
|
||
/*******************************************************************************
|
||
* EngSetPrinterData()
|
||
*
|
||
* History:
|
||
* 25-Oct-95 by Steve Wilson [swilson]
|
||
* Wrote it.
|
||
*******************************************************************************/
|
||
|
||
DWORD
|
||
WINAPI
|
||
EngSetPrinterData(
|
||
HANDLE hPrinter, // IN
|
||
LPWSTR pType, // IN
|
||
DWORD dwType, // IN
|
||
LPBYTE lpbPrinterData, // IN
|
||
DWORD cjPrinterData // IN
|
||
)
|
||
{
|
||
LONG cj, cjType;
|
||
DWORD cjReturn;
|
||
DWORD dwLastError = ERROR_NOT_ENOUGH_MEMORY;
|
||
GRESETPRINTERDATA *pTo, *pFrom;
|
||
|
||
//DbgPrint("Enter EngSetPrinterData\n");
|
||
|
||
// Accumulate sizes of base struct plus strings
|
||
cj = sizeof *pTo;
|
||
cj += (cjType = pType ? (wcslen(pType) + 1)*sizeof *pType : 0);
|
||
cj += lpbPrinterData ? cjPrinterData : 0;
|
||
|
||
// Allocate TO buffer
|
||
pTo = (GRESETPRINTERDATA *) PALLOCMEM(cj, 'lpsG');
|
||
|
||
// Marshall TO buffer
|
||
if (pTo)
|
||
{
|
||
|
||
pTo->cj = cj;
|
||
|
||
// Write incoming data at end of GRE struct
|
||
if (pType) {
|
||
memcpy(pTo->alData,pType,cjType);
|
||
pTo->cjType = cjType;
|
||
}
|
||
|
||
if (lpbPrinterData) {
|
||
memcpy((BYTE *)pTo->alData + cjType,lpbPrinterData,cjPrinterData);
|
||
pTo->cjPrinterData = cjPrinterData;
|
||
}
|
||
|
||
|
||
// Allocate RETURN buffer
|
||
pFrom = (GRESETPRINTERDATA *) PALLOCNOZ(cjReturn = sizeof *pTo, 'lpsG');
|
||
|
||
// SEND MESSAGE
|
||
if (pFrom)
|
||
{
|
||
pTo->dwType = dwType;
|
||
|
||
// GreGenericW return value indicates success or failure of GreEscapeSpool() and KMGetPrinterData()
|
||
GreGenericW( hPrinter,
|
||
(PULONG) pTo,
|
||
(PULONG) pFrom,
|
||
cjReturn,
|
||
(LONG) GDISPOOL_SETPRINTERDATA, 0);
|
||
|
||
dwLastError = EngGetLastError();
|
||
|
||
VFREEMEM(pFrom);
|
||
}
|
||
VFREEMEM(pTo);
|
||
}
|
||
|
||
//DbgPrint("GetPrinterData return: %d\n", dwLastError);
|
||
|
||
return dwLastError;
|
||
}
|
||
|
||
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
*
|
||
*
|
||
* History:
|
||
* 27-Feb-1995 -by- Eric Kutter [erick]
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
BOOL
|
||
WINAPI
|
||
EngWritePrinter(
|
||
HANDLE hPrinter,
|
||
LPVOID pBuf,
|
||
DWORD cbBuf,
|
||
LPDWORD pcWritten
|
||
)
|
||
{
|
||
DWORD ulRet = 0;
|
||
SPOOLREF sr(hPrinter);
|
||
|
||
if (sr.bValid())
|
||
{
|
||
PSPOOLMSG psm = sr.psm();
|
||
LPVOID pKmBuf = NULL;
|
||
|
||
GREWRITEPRINTER *wp = &sr.pso->WritePrinter;
|
||
|
||
//DbgPrint("Enter EngWritePrinter\n");
|
||
|
||
wp->cj = offsetof(GREWRITEPRINTER,alData) + cbBuf;
|
||
wp->cjData = cbBuf;
|
||
|
||
if (gpeSpool == PsGetCurrentProcess() &&
|
||
pBuf <= MM_HIGHEST_USER_ADDRESS &&
|
||
pBuf >= MM_LOWEST_USER_ADDRESS)
|
||
{
|
||
wp->pUserModeData = (PULONG) pBuf;
|
||
wp->cjUserModeData = cbBuf;
|
||
psm->cBuf = 1;
|
||
psm->cjIn = offsetof(GREWRITEPRINTER, alData);
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// if we recevie a user mode buffer, make a kernel copy.
|
||
// This is to patch PSCRIPT 4 driver running on NT5.
|
||
//
|
||
|
||
if (pBuf <= MM_HIGHEST_USER_ADDRESS &&
|
||
pBuf >= MM_LOWEST_USER_ADDRESS)
|
||
{
|
||
if (pKmBuf = PALLOCNOZ(cbBuf,'lpsG'))
|
||
{
|
||
__try
|
||
{
|
||
ProbeAndReadBuffer(pKmBuf,pBuf,cbBuf);
|
||
}
|
||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
VFREEMEM(pKmBuf);
|
||
return (FALSE);
|
||
}
|
||
|
||
pBuf = pKmBuf;
|
||
}
|
||
else
|
||
{
|
||
WARNING ("failed to allocate memory in EngWritePrinter\n");
|
||
return (FALSE);
|
||
}
|
||
}
|
||
|
||
wp->pUserModeData = NULL;
|
||
wp->cjUserModeData = 0;
|
||
psm->cBuf = 2;
|
||
psm->apulIn[1]= (PULONG)pBuf;
|
||
psm->acjIn[1] = cbBuf;
|
||
psm->cjIn = wp->cj;
|
||
}
|
||
|
||
|
||
// setup the message
|
||
|
||
psm->cj = sizeof(SPOOLMSG);
|
||
psm->iMsg = GDISPOOL_WRITE;
|
||
psm->fl = 0;
|
||
|
||
// there are two buffers, one for the GREWRITEPRINTER header and one
|
||
// for the data.
|
||
|
||
psm->apulIn[0]= (PULONG)wp;
|
||
psm->acjIn[0] = offsetof(GREWRITEPRINTER,alData);
|
||
|
||
// place the return value in ulRet
|
||
|
||
psm->pulOut = &sr.pso->dwWritePrinterReturn;
|
||
psm->cjOut = sizeof(sr.pso->dwWritePrinterReturn);
|
||
psm->hso = (HSPOOLOBJ)hPrinter;
|
||
|
||
if (!sr.GreEscapeSpool())
|
||
{
|
||
ulRet = 0;
|
||
}
|
||
else
|
||
{
|
||
ulRet = sr.pso->dwWritePrinterReturn;
|
||
}
|
||
|
||
if (pcWritten)
|
||
*pcWritten = ulRet;
|
||
|
||
if (pKmBuf)
|
||
{
|
||
VFREEMEM(pKmBuf);
|
||
}
|
||
}
|
||
|
||
// return TRUE or FALSE
|
||
|
||
return(!!ulRet);
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* BOOL GetFontPathName( WCHAR *pFullPath, WCHAR *pFileName )
|
||
*
|
||
* Goes to the spooler and does a search path in the font path to find the
|
||
* full path given a font file name. We expect pFullName and pFileName to
|
||
* point to the same piece of memory although we don't require this to be the case.
|
||
*
|
||
* History
|
||
* 7-31-95 Gerrit van Wingerden [gerritv]
|
||
* Wrote it.
|
||
*
|
||
*******************************************************************************/
|
||
|
||
BOOL GetFontPathName( WCHAR *pFullPath, WCHAR *pFileName )
|
||
{
|
||
BOOL bRet = FALSE;
|
||
SPOOLMEMOBJ spmo;
|
||
|
||
if (spmo.bValid())
|
||
{
|
||
PSPOOLMSG psm = spmo.psm();
|
||
|
||
psm->cj = sizeof(SPOOLMSG);
|
||
psm->iMsg = GDISPOOL_GETPATHNAME;
|
||
psm->fl = 0;
|
||
|
||
psm->cBuf = 1;
|
||
psm->cjIn = (wcslen(pFileName) + 1) * sizeof(WCHAR);
|
||
psm->apulIn[0] = (PULONG) pFileName;
|
||
psm->acjIn[0] = psm->cjIn;
|
||
|
||
psm->pulOut = (PULONG) pFullPath;
|
||
psm->cjOut = sizeof(WCHAR) * (MAX_PATH+1);
|
||
|
||
psm->hso = spmo.hGet();
|
||
|
||
bRet = spmo.GreEscapeSpool() && psm->ulRet;
|
||
|
||
spmo.bDelete();
|
||
}
|
||
|
||
return(bRet);
|
||
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* EngEscape()
|
||
*
|
||
* History:
|
||
* 18-Sep-1995 -by- Eric Kutter [erick]
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
ULONG APIENTRY EngEscape(
|
||
HANDLE hPrinter,
|
||
ULONG iEsc,
|
||
ULONG cjIn,
|
||
PVOID pvIn,
|
||
ULONG cjOut,
|
||
PVOID pvOut)
|
||
{
|
||
BOOL ulRet = FALSE;
|
||
SPOOLREF sr(hPrinter);
|
||
|
||
if (sr.bValid())
|
||
{
|
||
PSPOOLMSG psm = sr.psm();
|
||
|
||
psm->cj = sizeof(SPOOLMSG);
|
||
psm->iMsg = GDISPOOL_ENDDOCPRINTER;
|
||
psm->fl = 0;
|
||
|
||
psm->cBuf = 2;
|
||
psm->cjIn = sizeof(ULONG)+cjIn;
|
||
|
||
psm->apulIn[0]= &iEsc;
|
||
psm->acjIn[0] = sizeof(ULONG);
|
||
|
||
psm->apulIn[1]= (PULONG)pvIn;
|
||
psm->acjIn[1] = cjIn;
|
||
|
||
psm->pulOut = (PULONG)pvOut;
|
||
psm->cjOut = cjOut;
|
||
|
||
psm->hso = (HSPOOLOBJ)hPrinter;
|
||
|
||
if( sr.GreEscapeSpool() )
|
||
{
|
||
ulRet = (DWORD) psm->ulRet;
|
||
}
|
||
}
|
||
|
||
return(ulRet);
|
||
}
|
||
|