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.
2918 lines
79 KiB
2918 lines
79 KiB
/******************************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 < pEnd && *pString)
|
|
{
|
|
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) - 1;
|
|
|
|
if (pString < (LPWSTR) pBuffer)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
while (pString < pEnd)
|
|
{
|
|
if (*pString==0 && *(pString+1)==0) return TRUE;
|
|
pString++;
|
|
}
|
|
|
|
return (FALSE);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* 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
|
|
cjReturn = sizeof *pTo;
|
|
pFrom = (GRESETPRINTERDATA *) PALLOCNOZ(cjReturn, '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);
|
|
}
|