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

1264 lines
26 KiB

/*++
Copyright (c) 1990-1996 Microsoft Corporation
All rights reserved
Module Name:
kmspool.c
Abstract:
Spooler API entry points for Kernel Clients.
Author:
Steve Wilson (NT) (swilson) 1-Jun-95 (Ported from client\winspool.c)
Environment:
User Mode -Win32
Revision History:
Matthew Felton (mattfe) May-96 Driver Hooks
--*/
#include "precomp.h"
#include "server.h"
#include "client.h"
#include "yspool.h"
#include "kmspool.h"
//
// Globals
//
#define ENTER_WAIT_LIST() EnterCriticalSection(&ThreadCriticalSection)
#define EXIT_WAIT_LIST() LeaveCriticalSection(&ThreadCriticalSection)
LPWSTR szEnvironment = LOCAL_ENVIRONMENT;
//
// Printer Attributes
//
#define SPLPRINTER_USER_MODE_PRINTER_DRIVER TEXT("SPLUserModePrinterDriver")
BOOL
ValidatePrinterHandle(
HANDLE hPrinter
);
BOOL
DriverEndPageHook(
PSPOOL pSpool
);
BOOL
DriverStartPageHook(
PSPOOL pSpool
);
BOOL
DriverWritePrinterHook(
PSPOOL pSpool,
LPVOID pBuf,
DWORD cbBuf,
LPDWORD pcWritten
);
VOID
DriverEndDocHook(
PSPOOL pSpool
);
DWORD
DriverStartDocHook(
PSPOOL pSpool,
DWORD JobId
);
VOID
DriverClosePrinterHook(
PSPOOL pSpool
);
VOID
DriverAbortPrinterHook(
PSPOOL pSpool
);
// Simple for Now !!!
DWORD
TranslateExceptionCode(
DWORD ExceptionCode
)
{
switch (ExceptionCode) {
case EXCEPTION_ACCESS_VIOLATION:
case EXCEPTION_DATATYPE_MISALIGNMENT:
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
case EXCEPTION_FLT_DENORMAL_OPERAND:
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
case EXCEPTION_FLT_INEXACT_RESULT:
case EXCEPTION_FLT_INVALID_OPERATION:
case EXCEPTION_FLT_OVERFLOW:
case EXCEPTION_FLT_STACK_CHECK:
case EXCEPTION_FLT_UNDERFLOW:
case EXCEPTION_INT_DIVIDE_BY_ZERO:
case EXCEPTION_INT_OVERFLOW:
case EXCEPTION_PRIV_INSTRUCTION:
case ERROR_NOACCESS:
case RPC_S_INVALID_BOUND:
return ERROR_INVALID_PARAMETER;
break;
default:
return ExceptionCode;
}
}
BOOL
KMOpenPrinterW(
LPWSTR pPrinterName,
LPHANDLE phPrinter,
LPPRINTER_DEFAULTS pDefault
)
{
BOOL ReturnValue;
DEVMODE_CONTAINER DevModeContainer;
HANDLE hPrinter;
PSPOOL pSpool;
DWORD dwSize = 0;
if (pDefault && pDefault->pDevMode)
{
dwSize = pDefault->pDevMode->dmSize + pDefault->pDevMode->dmDriverExtra;
if (dwSize) {
DevModeContainer.cbBuf = pDefault->pDevMode->dmSize +
pDefault->pDevMode->dmDriverExtra;
DevModeContainer.pDevMode = (LPBYTE)pDefault->pDevMode;
} else {
DevModeContainer.cbBuf = 0;
DevModeContainer.pDevMode = NULL;
}
}
else
{
DevModeContainer.cbBuf = 0;
DevModeContainer.pDevMode = NULL;
}
try {
if (ReturnValue = YOpenPrinter(pPrinterName, &hPrinter,
pDefault ? pDefault->pDatatype : NULL,
&DevModeContainer,
pDefault ? pDefault->DesiredAccess : 0,
NATIVE_CALL )) {
SetLastError(ReturnValue);
ReturnValue = FALSE;
} else
ReturnValue = TRUE;
} except(1) {
SetLastError(TranslateExceptionCode(GetExceptionCode()));
ReturnValue = FALSE;
}
if (ReturnValue) {
pSpool = AllocSplMem(sizeof(SPOOL));
if (pSpool) {
memset(pSpool, 0, sizeof(SPOOL));
pSpool->signature = SP_SIGNATURE;
pSpool->hPrinter = hPrinter;
pSpool->cThreads = -1;
//
// This is to fix passing a bad pHandle to OpenPrinter!!
//
try {
*phPrinter = pSpool;
} except(1) {
YClosePrinter(&hPrinter, NATIVE_CALL);
FreeSplMem(pSpool);
SetLastError(TranslateExceptionCode(GetExceptionCode()));
return FALSE;
}
} else {
YClosePrinter(&hPrinter, NATIVE_CALL);
ReturnValue = FALSE;
}
}
return ReturnValue;
}
BOOL
KMGetFormW(
HANDLE hPrinter,
LPWSTR pFormName,
DWORD Level,
LPBYTE pForm,
DWORD cbBuf,
LPDWORD pcbNeeded
)
{
BOOL ReturnValue;
DWORD *pOffsets;
PSPOOL pSpool = (PSPOOL)hPrinter;
if (!ValidatePrinterHandle(hPrinter)) {
return(FALSE);
}
switch (Level) {
case 1:
pOffsets = FormInfo1Offsets;
break;
default:
SetLastError(ERROR_INVALID_LEVEL);
return FALSE;
}
try {
if (pForm)
memset(pForm, 0, cbBuf);
if (ReturnValue = YGetForm(pSpool->hPrinter, pFormName, Level, pForm,
cbBuf, pcbNeeded, NATIVE_CALL)) {
SetLastError(ReturnValue);
ReturnValue = FALSE;
} else {
ReturnValue = TRUE;
}
} except(1) {
SetLastError(TranslateExceptionCode(GetExceptionCode()));
ReturnValue = FALSE;
}
return ReturnValue;
}
BOOL
KMEnumFormsW(
HANDLE hPrinter,
DWORD Level,
LPBYTE pForm,
DWORD cbBuf,
LPDWORD pcbNeeded,
LPDWORD pcReturned
)
{
BOOL ReturnValue;
DWORD cbStruct;
DWORD *pOffsets;
PSPOOL pSpool = (PSPOOL)hPrinter;
if (!ValidatePrinterHandle(hPrinter)) {
return(FALSE);
}
switch (Level) {
case 1:
pOffsets = FormInfo1Offsets;
cbStruct = sizeof(FORM_INFO_1);
break;
default:
SetLastError(ERROR_INVALID_LEVEL);
return FALSE;
}
try {
if (pForm)
memset(pForm, 0, cbBuf);
if (ReturnValue = YEnumForms(pSpool->hPrinter, Level, pForm, cbBuf,
pcbNeeded, pcReturned, NATIVE_CALL)) {
SetLastError(ReturnValue);
ReturnValue = FALSE;
} else {
ReturnValue = TRUE;
}
} except(1) {
SetLastError(TranslateExceptionCode(GetExceptionCode()));
ReturnValue = FALSE;
}
return ReturnValue;
}
BOOL
KMGetPrinterW(
HANDLE hPrinter,
DWORD Level,
LPBYTE pPrinter,
DWORD cbBuf,
LPDWORD pcbNeeded
)
{
BOOL ReturnValue;
DWORD *pOffsets;
PSPOOL pSpool = (PSPOOL)hPrinter;
if (!ValidatePrinterHandle(hPrinter)) {
return(FALSE);
}
switch (Level) {
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:
SetLastError(ERROR_INVALID_LEVEL);
return FALSE;
}
try {
if (pPrinter)
memset(pPrinter, 0, cbBuf);
if (ReturnValue = YGetPrinter(pSpool->hPrinter, Level, pPrinter, cbBuf, pcbNeeded, NATIVE_CALL)) {
SetLastError(ReturnValue);
ReturnValue = FALSE;
} else {
ReturnValue = TRUE;
}
} except(1) {
SetLastError(TranslateExceptionCode(GetExceptionCode()));
ReturnValue = FALSE;
}
return ReturnValue;
}
BOOL
KMGetPrinterDriverW(
HANDLE hPrinter,
LPWSTR pEnvironment,
DWORD Level,
LPBYTE pDriverInfo,
DWORD cbBuf,
LPDWORD pcbNeeded
)
{
BOOL ReturnValue;
PSPOOL pSpool = (PSPOOL)hPrinter;
DWORD dwServerMajorVersion;
DWORD dwServerMinorVersion;
if (!ValidatePrinterHandle(hPrinter)) {
return(FALSE);
}
if (Level < 1 || Level > 3) {
SetLastError(ERROR_INVALID_LEVEL);
return FALSE;
}
try {
if (pDriverInfo)
memset(pDriverInfo, 0, cbBuf);
if (!pEnvironment || !*pEnvironment)
pEnvironment = szEnvironment;
if (ReturnValue = YGetPrinterDriver2(pSpool->hPrinter, pEnvironment,
Level, pDriverInfo, cbBuf,
pcbNeeded,
(DWORD)-1, (DWORD)-1,
&dwServerMajorVersion,
&dwServerMinorVersion,
NATIVE_CALL
)) {
SetLastError(ReturnValue);
ReturnValue = FALSE;
} else {
ReturnValue = TRUE;
}
} except(1) {
SetLastError(TranslateExceptionCode(GetExceptionCode()));
ReturnValue = FALSE;
}
return ReturnValue;
}
DWORD
KMGetPrinterDataW(
HANDLE hPrinter,
LPWSTR pValueName,
LPDWORD pType,
LPBYTE pData,
DWORD nSize,
LPDWORD pcbNeeded
)
{
DWORD ReturnValue = 0;
PSPOOL pSpool = (PSPOOL)hPrinter;
if (!ValidatePrinterHandle(hPrinter)) {
return ERROR_INVALID_HANDLE;
}
//
// The user should be able to pass in NULL for buffer, and
// 0 for size. However, the RPC interface specifies a ref pointer,
// so we must pass in a valid pointer. Pass in a pointer to
// ReturnValue (this is just a dummy pointer).
//
if( !pData && !nSize ){
pData = (PBYTE)&ReturnValue;
}
try {
ReturnValue = YGetPrinterData(pSpool->hPrinter, pValueName, pType,
pData, nSize, pcbNeeded, NATIVE_CALL);
} except(1) {
ReturnValue = TranslateExceptionCode(GetExceptionCode());
}
return ReturnValue;
}
DWORD
KMSetPrinterDataW(
HANDLE hPrinter,
LPWSTR pValueName,
DWORD Type,
LPBYTE pData,
DWORD cbData
)
{
DWORD ReturnValue = 0;
PSPOOL pSpool = (PSPOOL)hPrinter;
if (!ValidatePrinterHandle(hPrinter)) {
return ERROR_INVALID_HANDLE;
}
try {
ReturnValue = YSetPrinterData(pSpool->hPrinter, pValueName, Type,
pData, cbData, NATIVE_CALL);
} except(1) {
ReturnValue = TranslateExceptionCode(GetExceptionCode());
}
return ReturnValue;
}
DWORD
KMStartDocPrinterW(
HANDLE hPrinter,
DWORD Level,
LPBYTE pDocInfo
)
{
BOOL ReturnValue;
DWORD JobId;
GENERIC_CONTAINER DocInfoContainer;
PSPOOL pSpool = (PSPOOL)hPrinter;
try {
if (!ValidatePrinterHandle(hPrinter)) {
return(FALSE);
}
DBGMSG(DBG_TRACE,("Entered KMStartDocPrinterW side hPrinter = %x\n", hPrinter));
if (Level != 1) {
SetLastError(ERROR_INVALID_LEVEL);
return FALSE;
}
DocInfoContainer.Level = Level;
DocInfoContainer.pData = pDocInfo;
try {
if (ReturnValue = YStartDocPrinter(pSpool->hPrinter,
(LPDOC_INFO_CONTAINER)&DocInfoContainer,
&JobId, NATIVE_CALL)) {
SetLastError(ReturnValue);
ReturnValue = FALSE;
} else
ReturnValue = JobId;
} except(1) {
SetLastError(TranslateExceptionCode(GetExceptionCode()));
ReturnValue = FALSE;
}
if (ReturnValue) {
ReturnValue = DriverStartDocHook( pSpool, JobId );
if ( ReturnValue )
pSpool->Status |= SPOOL_STATUS_STARTDOC;
}
return ReturnValue;
} except (1) {
SetLastError(TranslateExceptionCode(GetExceptionCode()));
return(FALSE);
}
}
BOOL
KMEndDocPrinter(
HANDLE hPrinter
)
{
BOOL ReturnValue;
PSPOOL pSpool = (PSPOOL)hPrinter;
try {
if (!ValidatePrinterHandle(hPrinter)) {
return(FALSE);
}
pSpool->Status &= ~SPOOL_STATUS_STARTDOC;
DriverEndDocHook( pSpool );
try {
if (ReturnValue = YEndDocPrinter(pSpool->hPrinter, NATIVE_CALL)) {
SetLastError(ReturnValue);
ReturnValue = FALSE;
} else
ReturnValue = TRUE;
} except(1) {
SetLastError(TranslateExceptionCode(GetExceptionCode()));
ReturnValue = FALSE;
}
DBGMSG(DBG_TRACE, ("Exit EndDocPrinter - client side hPrinter %x\n", hPrinter));
return ReturnValue;
} except (1) {
SetLastError(ERROR_INVALID_HANDLE);
return(FALSE);
}
}
BOOL
KMWritePrinter(
HANDLE hPrinter,
LPVOID pBuf,
DWORD cbBuf,
LPDWORD pcWritten
)
{
BOOL ReturnValue = TRUE;
PSPOOL pSpool = (PSPOOL)hPrinter;
DBGMSG(DBG_TRACE, ("WritePrinter - hPrinter %x pBuf %x cbBuf %d pcWritten %x\n",
hPrinter, pBuf, cbBuf, pcWritten));
if (!ValidatePrinterHandle(hPrinter)) {
return(FALSE);
}
*pcWritten = 0;
if ( !(pSpool->Status & SPOOL_STATUS_STARTDOC) ) {
SetLastError(ERROR_SPL_NO_STARTDOC);
return FALSE;
}
//
// Call Printer Drivers User Mode WritePrinter Hook
//
if ( pSpool->hDriver ) {
return DriverWritePrinterHook( pSpool, pBuf, cbBuf, pcWritten );
}
try {
if (ReturnValue = YWritePrinter(pSpool->hPrinter, (LPBYTE) pBuf, cbBuf, pcWritten, NATIVE_CALL)) {
SetLastError(ReturnValue);
ReturnValue = FALSE;
DBGMSG(DBG_WARNING, ("KMWritePrinter - YWritePrinter Failed Error %d\n",GetLastError() ));
} else {
ReturnValue = TRUE;
DBGMSG(DBG_TRACE, ("KMWritePrinter - YWritePrinter Success hPrinter %x pBuffer %x cbBuffer %x cbWritten %x\n",
pSpool->hPrinter, (LPBYTE) pBuf, cbBuf, *pcWritten));
}
} except(1) {
SetLastError(TranslateExceptionCode(GetExceptionCode()));
ReturnValue = FALSE;
DBGMSG(DBG_WARNING, ("YWritePrinter Exception Error %d\n",GetLastError()));
}
// Return the number of bytes written.
DBGMSG(DBG_TRACE, ("KMWritePrinter cbWritten %d ReturnValue %d\n",*pcWritten, ReturnValue));
return ReturnValue;
}
BOOL
KMStartPagePrinter(
HANDLE hPrinter
)
{
BOOL ReturnValue;
PSPOOL pSpool = (PSPOOL)hPrinter;
if (!ValidatePrinterHandle(hPrinter)) {
return(FALSE);
}
try {
ReturnValue = DriverStartPageHook( pSpool );
if ( ReturnValue ) {
if (ReturnValue = YStartPagePrinter(pSpool->hPrinter, NATIVE_CALL)) {
SetLastError(ReturnValue);
ReturnValue = FALSE;
} else
ReturnValue = TRUE;
}
} except(1) {
SetLastError(TranslateExceptionCode(GetExceptionCode()));
ReturnValue = FALSE;
}
return ReturnValue;
}
BOOL
KMEndPagePrinter(
HANDLE hPrinter
)
{
BOOL ReturnValue;
PSPOOL pSpool = (PSPOOL)hPrinter;
if (!ValidatePrinterHandle(hPrinter)) {
return(FALSE);
}
try {
ReturnValue = DriverEndPageHook( pSpool );
if ( ReturnValue ) {
if (ReturnValue = YEndPagePrinter(pSpool->hPrinter, NATIVE_CALL)) {
SetLastError(ReturnValue);
ReturnValue = FALSE;
} else
ReturnValue = TRUE;
}
} except(1) {
SetLastError(TranslateExceptionCode(GetExceptionCode()));
ReturnValue = FALSE;
}
return ReturnValue;
}
BOOL
KMAbortPrinter(
HANDLE hPrinter
)
{
BOOL ReturnValue;
PSPOOL pSpool = (PSPOOL)hPrinter;
DWORD dwNumWritten = 0;
DWORD dwPointer = 0;
if (!ValidatePrinterHandle(hPrinter)){
return(FALSE);
}
pSpool->Status &= ~SPOOL_STATUS_STARTDOC;
try {
DriverAbortPrinterHook( pSpool );
if (ReturnValue = YAbortPrinter(pSpool->hPrinter, NATIVE_CALL)) {
SetLastError(ReturnValue);
ReturnValue = FALSE;
} else
ReturnValue = TRUE;
} except(1) {
SetLastError(TranslateExceptionCode(GetExceptionCode()));
ReturnValue = FALSE;
}
return ReturnValue;
}
BOOL
KMClosePrinter(
HANDLE hPrinter)
{
BOOL ReturnValue;
PSPOOL pSpool = (PSPOOL)hPrinter;
HANDLE hPrinterKM;
if (!ValidatePrinterHandle(hPrinter)) {
return(FALSE);
}
try {
DriverClosePrinterHook( pSpool );
} except(1) {
DBGMSG(DBG_WARNING, ("DrvClosePrinter Exception Error %d\n",TranslateExceptionCode(GetExceptionCode())));
}
ENTER_WAIT_LIST();
hPrinterKM = pSpool->hPrinter;
FreeSplMem(pSpool);
EXIT_WAIT_LIST();
try {
if (ReturnValue = YClosePrinter(&hPrinterKM, NATIVE_CALL)) {
SetLastError(ReturnValue);
ReturnValue = FALSE;
} else
ReturnValue = TRUE;
} except(1) {
SetLastError(TranslateExceptionCode(GetExceptionCode()));
ReturnValue = FALSE;
}
return ReturnValue;
}
BOOL
ValidatePrinterHandle(
HANDLE hPrinter
)
{
PSPOOL pSpool = hPrinter;
BOOL bReturnValue = FALSE;
try {
if ( pSpool && (pSpool->signature == SP_SIGNATURE)) {
bReturnValue = TRUE;
}
} except (1) {
}
if ( !bReturnValue ) {
SetLastError( ERROR_INVALID_HANDLE );
}
return bReturnValue;
}
BOOL
DriverWritePrinterHook(
PSPOOL pSpool,
LPVOID pBuf,
DWORD cbBuf,
LPDWORD pcWritten
)
{
BOOL ReturnValue;
// Some Printer Drivers want to push functionality out of kernel mode
// to achieve that we allow them to hook the calls to writeprinter from
// their Kernel Mode DLL to their User Mode Dll
SPLASSERT( pSpool->hModule &&
pSpool->pfnWrite &&
pSpool->hDriver &&
pSpool->hPrinter );
try {
ReturnValue = (*pSpool->pfnWrite)( pSpool->hDriver,
pBuf,
cbBuf,
pcWritten );
} except(1) {
SetLastError(TranslateExceptionCode(GetExceptionCode()));
ReturnValue = FALSE;
DBGMSG(DBG_ERROR, ("DrvWritePrinter Exception Error %d pSpool %x\n",GetLastError(), pSpool));
}
if ( !ReturnValue ) {
SPLASSERT( GetLastError() );
}
return ReturnValue;
}
HANDLE
LoadPrinterDriver(
PSPOOL pSpool,
PWCHAR pUserModeDriverName
)
{
PDRIVER_INFO_2 pDriverInfo;
DWORD cbNeeded;
HANDLE hModule = NULL;
PWCHAR pFileName;
fnWinSpoolDrv fnList;
if (!GetPrinterDriver(pSpool->hPrinter, NULL, 2, NULL, 0, &cbNeeded)) {
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
// Allow for the size of the string passed in.
cbNeeded += ( wcslen( pUserModeDriverName ) + 1 )* sizeof(WCHAR);
if (pDriverInfo = (PDRIVER_INFO_2)AllocSplMem( cbNeeded )) {
if (GetPrinterDriver(pSpool->hPrinter, NULL, 2, (LPBYTE)pDriverInfo, cbNeeded, &cbNeeded)) {
HRESULT hRes;
//
// Driver Info 2 doesn't have the fully Qualified Path
// to the UserModePrinterDriver.
// So form it by taking replacing the UI DLL name with the
// UseModePrinterDriverName
pFileName = wcsrchr( pDriverInfo->pConfigFile, L'\\');
pFileName++;
//
// the line cbNeeded += ( wcslen( pUserModeDriverName ) + 1 )* sizeof(WCHAR);
// makes sure that we have enough buffer to copy pUserModeDriverName
//
hRes = StringCchCopyW(pFileName, 1 + wcslen(pUserModeDriverName), pUserModeDriverName);
if (SUCCEEDED(hRes)) {
pFileName = pDriverInfo->pConfigFile;
DBGMSG( DBG_WARNING, ("UserModeDriverPath %ws\n", pFileName ));
if (SplInitializeWinSpoolDrv(&fnList)) {
hModule = (* (fnList.pfnRefCntLoadDriver))(pFileName,
LOAD_WITH_ALTERED_SEARCH_PATH,
0, FALSE);
}
if ( !hModule ) {
DBGMSG( DBG_WARNING, ("Failed to load %ws error %d\n", pFileName, GetLastError() ));
}
}
else {
SetLastError(SCODE_CODE(hRes));
}
}
FreeSplMem(pDriverInfo);
}
}
}
return hModule;
}
VOID
UnloadPrinterDriver(
PSPOOL pSpool
)
{
fnWinSpoolDrv fnList;
if ( pSpool->hModule ) {
SPLASSERT( pSpool->hDriver == NULL );
if (SplInitializeWinSpoolDrv(&fnList)) {
(* (fnList.pfnRefCntUnloadDriver))(pSpool->hModule, TRUE);
}
pSpool->hModule = NULL;
pSpool->pfnWrite = NULL;
pSpool->pfnStartDoc = NULL;
pSpool->pfnEndDoc = NULL;
pSpool->pfnClose = NULL;
pSpool->pfnStartPage = NULL;
pSpool->pfnEndPage = NULL;
}
}
DWORD
DriverStartDocHook(
PSPOOL pSpool,
DWORD JobId
)
{
DWORD dwReturn;
WCHAR UserModeDriverName[MAX_PATH];
DWORD dwNeeded;
INT cDriverName;
BOOL ReturnValue = FALSE;
DWORD Type = 0;
//
// Determine if there is a UserMode Printer Driver
//
dwReturn = GetPrinterDataW( pSpool->hPrinter,
SPLPRINTER_USER_MODE_PRINTER_DRIVER,
&Type,
(LPBYTE)&UserModeDriverName,
MAX_PATH,
&dwNeeded );
if ( dwReturn != ERROR_SUCCESS ) {
SPLASSERT( dwReturn != ERROR_INSUFFICIENT_BUFFER );
ReturnValue = TRUE;
goto Complete;
}
if ( Type != REG_SZ ) {
SPLASSERT( Type == REG_SZ );
goto Complete;
}
// No String treat as success
cDriverName = wcslen( UserModeDriverName );
if ( !cDriverName ) {
ReturnValue = TRUE;
goto Complete;
}
//
// Load the UM Driver DLL
//
if ( pSpool->hModule == NULL ) {
pSpool->hModule = LoadPrinterDriver( pSpool, UserModeDriverName );
if ( pSpool->hModule == NULL ) goto Complete;
}
//
// Get Function Pointers
//
// Required
//
pSpool->pfnWrite = (DWORD (*)()) GetProcAddress( pSpool->hModule, "DrvSplWritePrinter" );
pSpool->pfnStartDoc = (HANDLE (*)()) GetProcAddress( pSpool->hModule, "DrvSplStartDoc" );
pSpool->pfnClose = (VOID (*)()) GetProcAddress( pSpool->hModule, "DrvSplClose" );
pSpool->pfnEndDoc = (VOID (*)()) GetProcAddress( pSpool->hModule, "DrvSplEndDoc" );
// Optional
//
pSpool->pfnEndPage = (BOOL (*)()) GetProcAddress( pSpool->hModule, "DrvSplEndPage" );
pSpool->pfnStartPage = (BOOL (*)()) GetProcAddress( pSpool->hModule, "DrvSplStartPage" );
pSpool->pfnAbort = (VOID (*)()) GetProcAddress( pSpool->hModule, "DrvSplAbort" );
if (!( pSpool->pfnWrite) ||
!( pSpool->pfnStartDoc) ||
!( pSpool->pfnClose) ||
!( pSpool->pfnEndDoc)) {
goto Complete;
}
//
// Ask the Driver for a Handle for this print job
//
SPLASSERT( pSpool->hDriver == NULL );
SPLASSERT( pSpool->hPrinter );
SPLASSERT( JobId );
pSpool->hDriver = (HANDLE)(*pSpool->pfnStartDoc)( pSpool->hPrinter, JobId );
if ( pSpool->hDriver != NULL ) {
ReturnValue = TRUE;
}
Complete:
if (!ReturnValue) {
UnloadPrinterDriver( pSpool );
// Cancel the outstanding job
//
// In the direct case
// AbortPrinter doesn't work
// SetJob _CANCEL doesn't work
// EndDocPrinter does work
EndDocPrinter( pSpool->hPrinter );
JobId = 0;
}
pSpool->JobId = JobId;
return JobId;
}
VOID
DriverEndDocHook(
PSPOOL pSpool
)
{
if ( pSpool->hDriver ) {
(*pSpool->pfnEndDoc)( pSpool->hDriver );
(*pSpool->pfnClose)(pSpool->hDriver );
pSpool->hDriver = NULL;
}
}
BOOL
DriverStartPageHook(
PSPOOL pSpool
)
{
if ( pSpool->hDriver && pSpool->pfnStartPage ){
return (*pSpool->pfnStartPage)( pSpool->hDriver );
} else {
return TRUE;
}
}
BOOL
DriverEndPageHook(
PSPOOL pSpool
)
{
if ( pSpool->hDriver && pSpool->pfnEndPage ){
return (*pSpool->pfnEndPage)( pSpool->hDriver );
} else {
return TRUE;
}
}
VOID
DriverAbortPrinterHook(
PSPOOL pSpool
)
{
if ( pSpool->hDriver && pSpool->pfnAbort )
(*pSpool->pfnAbort)( pSpool->hDriver );
}
VOID
DriverClosePrinterHook(
PSPOOL pSpool
)
{
if ( pSpool->hDriver ) {
SPLASSERT( pSpool->pfnClose );
(*pSpool->pfnClose)(pSpool->hDriver);
pSpool->hDriver = NULL;
}
UnloadPrinterDriver( pSpool );
}