|
|
/*****************************************************************************\
* MODULE: ppprn.c * * This module contains the routines which control the printer during the * course of a single job. * * * Copyright (C) 1996-1997 Microsoft Corporation * Copyright (C) 1996-1997 Hewlett Packard * * History: * 09-Jun-1993 JonMarb Created * 07-Oct-1996 HWP-Guys Initiated port from win95 to winNT * \*****************************************************************************/
#include "precomp.h"
#include "priv.h"
/*****************************************************************************\
* _ppprn_free_hprinter (Local Routine) * * Free up the hPrinter handle. * \*****************************************************************************/ _inline VOID _ppprn_free_hprinter( HANDLE hPrinter) { LPINET_HPRINTER pPrt;
if (pPrt = (LPINET_HPRINTER)hPrinter) {
#ifdef WINNT32
DeleteHandleFromList (pPrt); #endif
if (pPrt->lpszName) memFreeStr(pPrt->lpszName);
#ifdef WINNT32
if (pPrt->hUser) delete ( pPrt->hUser );
#endif
memFree(pPrt, sizeof(INET_HPRINTER));
} }
/*****************************************************************************\
* _ppprn_inc_user_refcount (Local Routine) * * Increment the reference count for the Port on the current printer * \*****************************************************************************/ #ifdef WINNT32
_inline DWORD __ppprn_inc_user_refcout( HANDLE hPrinter ) {
LPINET_HPRINTER pPrt; DWORD dwRet = MAXDWORD;
if (pPrt = (LPINET_HPRINTER)hPrinter) { dwRet = (PCINETMONPORT (pPrt->hPort))->IncUserRefCount(pPrt->hUser );
} else SetLastError( ERROR_INVALID_PARAMETER );
return dwRet; }
#endif
/*****************************************************************************\
* _ppprn_make_hprinter (Local Routine) * * Returns a printer handle. * \*****************************************************************************/ HANDLE _ppprn_make_hprinter( HANDLE hPort, LPCTSTR lpszPrnName) { LPINET_HPRINTER pPrt;
if (pPrt = (LPINET_HPRINTER)memAlloc(sizeof(INET_HPRINTER))) {
pPrt->dwSignature = IPO_SIGNATURE; pPrt->lpszName = memAllocStr(lpszPrnName); pPrt->hPort = hPort; pPrt->dwStatus = 0; pPrt->pjmJob = NULL; #ifdef WINNT32
pPrt->hUser = new CLogonUserData;
#endif
if ( pPrt->lpszName #ifdef WINNT32
&& pPrt->hUser && pPrt->hUser->bValid () && AddHandleToList (pPrt) #endif
) {
return (HANDLE)pPrt;
} else {
if (pPrt->lpszName) memFreeStr (pPrt->lpszName);
#ifdef WINNT32
if (pPrt->hUser) { delete ( pPrt->hUser ); } #endif
memFree (pPrt, sizeof(INET_HPRINTER)); } }
return NULL; }
#ifdef WINNT32
/*****************************************************************************\
* _ppprn_free_xcv_hprinter (Local Routine) * * Free a xcv printer handle. * \*****************************************************************************/ _inline VOID _ppprn_free_xcv_hprinter( HANDLE hPrinter) { LPINET_XCV_HPRINTER pPrt;
if (pPrt = (LPINET_XCV_HPRINTER)hPrinter) {
memFreeStr (pPrt->lpszName); memFree(pPrt, sizeof(INET_XCV_HPRINTER));
} }
/*****************************************************************************\
* _ppprn_make_xcv_hprinter (Local Routine) * * Returns a xcv printer handle. * \*****************************************************************************/ HANDLE _ppprn_make_xcv_hprinter( PCINETMONPORT pIniPort) { LPINET_XCV_HPRINTER pPrt;
if (pPrt = (LPINET_XCV_HPRINTER)memAlloc(sizeof(INET_XCV_HPRINTER))) {
pPrt->dwSignature = IPO_XCV_SIGNATURE; pPrt->lpszName = memAllocStr(pIniPort->GetPortName()); }
return pPrt; }
#endif
/*****************************************************************************\
* ppprn_IppSetRsp (Local Callback Routine) * * Retrieves a SetPrinter response from the IPP server * \*****************************************************************************/ BOOL CALLBACK ppprn_IppSetRsp( CAnyConnection *pConnection, HINTERNET hReq, PCINETMONPORT pIniPort, LPARAM lParam) { HANDLE hIpp; DWORD dwRet; DWORD cbRd; LPBYTE lpDta; DWORD cbDta; LPIPPRET_PRN lpRsp; DWORD cbRsp; BYTE bBuf[MAX_IPP_BUFFER]; BOOL bRet = FALSE;
if (hIpp = WebIppRcvOpen((WORD)(LPARAM)lParam)) {
while (TRUE) {
cbRd = 0; if (pIniPort->ReadFile (pConnection, hReq, (LPVOID)bBuf, sizeof(bBuf), &cbRd) && cbRd) {
dwRet = WebIppRcvData(hIpp, bBuf, cbRd, (LPBYTE*)&lpRsp, &cbRsp, &lpDta, &cbDta);
switch (dwRet) {
case WEBIPP_OK:
if ((bRet = lpRsp->bRet) == FALSE) SetLastError(lpRsp->dwLastError);
WebIppFreeMem(lpRsp);
goto EndSetRsp;
case WEBIPP_MOREDATA:
// Need to do another read to fullfill our header-response.
//
break;
default:
DBG_MSG(DBG_LEV_ERROR, (TEXT("ppprn_IppSetRsp - Err : Receive Data Error (dwRet=%d, LE=%d)"), dwRet, WebIppGetError(hIpp)));
SetLastError(ERROR_INVALID_DATA);
goto EndSetRsp; }
} else {
goto EndSetRsp; } }
EndSetRsp:
WebIppRcvClose(hIpp);
} else {
SetLastError(ERROR_OUTOFMEMORY); }
return bRet; }
/*****************************************************************************\
* ppprn_Set (Local Routine) * * Sets a printer command. * \*****************************************************************************/ BOOL ppprn_Set( PCINETMONPORT pIniPort, DWORD dwCmd) { PIPPREQ_SETPRN psp; REQINFO ri; DWORD dwRet; LPBYTE lpIpp; DWORD cbIpp; WORD wReq; LPTSTR lpszUsrName; BOOL bRet = FALSE;
// Create our ipp-reqest-structure.
//
if (lpszUsrName = GetUserName()) {
psp = WebIppCreateSetPrnReq(dwCmd, lpszUsrName, pIniPort->GetPortName());
memFreeStr(lpszUsrName);
if (psp) {
switch (dwCmd) { case PRINTER_CONTROL_PAUSE: wReq = IPP_REQ_PAUSEPRN; break;
case PRINTER_CONTROL_RESUME: wReq = IPP_REQ_RESUMEPRN; break;
case PRINTER_CONTROL_PURGE: wReq = IPP_REQ_CANCELPRN; break;
default: wReq = 0; break; }
// Convert the reqest to IPP, and perform the
// post.
//
ZeroMemory(&ri, sizeof(REQINFO)); ri.cpReq = CP_UTF8; ri.idReq = wReq;
ri.fReq[0] = IPP_REQALL; ri.fReq[1] = IPP_REQALL;
dwRet = WebIppSndData(wReq, &ri, (LPBYTE)psp, psp->cbSize, &lpIpp, &cbIpp);
// The request-structure has been converted to IPP format,
// so it is ready to go to the server.
//
if (dwRet == WEBIPP_OK) {
bRet = pIniPort->SendReq(lpIpp, cbIpp, ppprn_IppSetRsp, (LPARAM)(wReq | IPP_RESPONSE), TRUE);
WebIppFreeMem(lpIpp);
} else {
SetLastError(ERROR_OUTOFMEMORY); }
WebIppFreeMem(psp);
} else {
SetLastError(ERROR_OUTOFMEMORY); } }
return bRet; }
#ifdef WINNT32
void _ppprn_working_thread ( PENDDOCTHREADCONTEXT pThreadData) { BOOL bRet = FALSE; PJOBMAP pjm = pThreadData->pjmJob; PCINETMONPORT pIniPort = pThreadData->pIniPort; static DWORD cdwWaitTime = 15000;
DBGMSGT (DBG_LEV_CALLTREE, ("Enter _ppprn_working_thread (%p)\n", pThreadData));
pThreadData->pSidToken->SetCurrentSid (); delete pThreadData->pSidToken; pThreadData->pSidToken = NULL;
semEnterCrit();
pjmUpdateLocalJobStatus (pjm, JOB_STATUS_PRINTING);
//
// The document is cancelled
//
if (pjmChkState(pThreadData->pjmJob, PJM_CANCEL)) {
bRet = TRUE; } else {
// Refresh the notification handle
//
RefreshNotificationPort (pIniPort);
bRet = pIniPort->EndDocPort(pjm);
#if 0
bRet = FALSE; //
// This is for testing
//
semLeaveCrit(); Sleep (3000); semEnterCrit(); #endif
}
//
// Check this flags again, since we left CriticalSection during file transfer
//
if (pjmChkState(pThreadData->pjmJob, PJM_CANCEL)) {
bRet = TRUE; }
if (bRet) { //
// Clear our spooling-state. This will free up any spool-job-resources.
//
pjmClrState(pjm, PJM_SPOOLING);
//
// Invalidate both job and printer caches
//
pIniPort->InvalidateGetPrinterCache (); pIniPort->InvalidateEnumJobsCache (); } else { pjmUpdateLocalJobStatus (pjm, JOB_STATUS_ERROR);
}
// Refresh the notification handle
//
RefreshNotificationPort (pIniPort);
//
// Clean the async thread flag
//
pjmClrState(pjm, PJM_ASYNCON);
pIniPort->DecRef();
semLeaveCrit();
delete pThreadData;
DBGMSGT (DBG_LEV_CALLTREE, ("Leave _ppprn_working_thread (ret = %d)\n", bRet)); }
BOOL _ppprn_end_docprinter_async ( PCINETMONPORT pIniPort, PJOBMAP pjmJob)
{ BOOL bRet = FALSE;
PENDDOCTHREADCONTEXT pThreadData = new ENDDOCTHREADCONTEXT;
if (pThreadData) { pThreadData->pIniPort = pIniPort; pThreadData->pjmJob = pjmJob; pThreadData->pSidToken = new CSid;
if (pThreadData->pSidToken && pThreadData->pSidToken->bValid ()) { HANDLE hThread;
pjmSetState(pjmJob, PJM_ASYNCON);
//
// Increase the ref count of the port to make sure it is not deleted
//
pIniPort->IncRef();
if (pIniPort->CreateTerminateEvent() && (hThread = CreateThread (NULL, COMMITTED_STACK_SIZE, (LPTHREAD_START_ROUTINE)_ppprn_working_thread, (PVOID) pThreadData, 0, NULL))) { CloseHandle (hThread); bRet = TRUE; } else {
//
// Fail to create the thread
//
pIniPort->DecRef ();
pjmClrState(pjmJob, PJM_ASYNCON); } }
if (!bRet) { if (pThreadData->pSidToken) { delete (pThreadData->pSidToken); pThreadData->pSidToken = NULL; }
delete (pThreadData); } }
return bRet; }
#endif
/*****************************************************************************\
* PP_OpenJobInfo * * Opens a job-information. This is called at StartDoc timeframe when we * need to start a spool-job. * \*****************************************************************************/ PJOBMAP PP_OpenJobInfo( HANDLE hPrinter, PCINETMONPORT pIniPort, LPTSTR pDocName) { PJOBMAP* pjmList; LPINET_HPRINTER lpPrt = (LPINET_HPRINTER)hPrinter; LPTSTR pUserName = GetUserName();
pjmList = pIniPort->GetPJMList();
if (lpPrt->pjmJob = pjmAdd(pjmList, pIniPort, pUserName, pDocName)) {
// Set the state to spooling for our job-entry. This wil
// create the spool-file object.
//
pjmSetState(lpPrt->pjmJob, PJM_SPOOLING);
}
memFreeStr (pUserName);
return lpPrt->pjmJob; }
/*****************************************************************************\
* PP_CloseJobInfo * * Close our spool-job and clear out the information regarding a printjob from * the printer. * \*****************************************************************************/ VOID PP_CloseJobInfo( HANDLE hPrinter) { PJOBMAP* pjmList; LPINET_HPRINTER lpPrt = (LPINET_HPRINTER)hPrinter;
// Clear our spooling-state. This will free up any spool-job-resources.
//
pjmClrState(lpPrt->pjmJob, PJM_SPOOLING);
// If we had cancelled our print-job, then we can remove the
// entry.
//
if (pjmChkState(lpPrt->pjmJob, PJM_CANCEL)) {
pjmList = ((PCINETMONPORT)(lpPrt->hPort))->GetPJMList();
pjmDel(pjmList, lpPrt->pjmJob); }
// Clear out or spool-status.
//
lpPrt->pjmJob = NULL; }
VOID PP_CloseJobInfo2( HANDLE hPrinter) { PJOBMAP* pjmList; LPINET_HPRINTER lpPrt = (LPINET_HPRINTER)hPrinter;
// Clear out or spool-status.
//
lpPrt->pjmJob = NULL; }
/*****************************************************************************\
* PPAbortPrinter * * Deletes a printer's spool file if the printer is configured for spooling. * Returns TRUE if successful, FALSE if an error occurs. * \*****************************************************************************/ BOOL PPAbortPrinter( HANDLE hPrinter) { PCINETMONPORT pIniPort; BOOL bRet = FALSE;
DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPAbortPrinter(%08lX)"), hPrinter));
semEnterCrit();
if (pIniPort = utlValidatePrinterHandle(hPrinter)) {
if ( PP_ChkStatus(hPrinter, PP_STARTDOC) && !PP_ChkStatus(hPrinter, PP_ENDDOC)) {
if (bRet = pIniPort->AbortPort(PP_GetJobInfo(hPrinter))) {
// If this call was successful, the job-info
// will have been freed. Therefore, it is OK
// to set the printer-jobreq to NULL.
//
PP_SetStatus(hPrinter, PP_CANCELLED); PP_ClrStatus(hPrinter, PP_STARTDOC); PP_CloseJobInfo(hPrinter); }
} else {
if (PP_ChkStatus(hPrinter, PP_CANCELLED)) SetLastError(ERROR_PRINT_CANCELLED); else SetLastError(ERROR_SPL_NO_STARTDOC);
bRet = TRUE; } }
semLeaveCrit();
return bRet; }
/*****************************************************************************\
* PPClosePrinter * * Closes a printer that was previously opened with PPOpenPrinter. Returns * TRUE if successful, FALSE if an error occurs. * \*****************************************************************************/ BOOL PPClosePrinter( HANDLE hPrinter) { PCINETMONPORT pIniPort; BOOL bRet = FALSE; BOOL bDeletePending = FALSE;
DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPClosePrinter: Printer(%08lX)"), hPrinter));
semEnterCrit();
if (pIniPort = utlValidatePrinterHandleForClose(hPrinter, &bDeletePending) ) {
if (bDeletePending) {
bRet = gpInetMon->InetmonReleasePort(pIniPort); _ppprn_free_hprinter(hPrinter);
} else {
if ( PP_ChkStatus(hPrinter, PP_STARTDOC) && !PP_ChkStatus(hPrinter, PP_ENDDOC)) {
PP_SetStatus(hPrinter, PP_ENDDOC);
pIniPort->EndDocPort(PP_GetJobInfo(hPrinter));
PP_ClrStatus(hPrinter, (PP_STARTDOC | PP_ENDDOC)); PP_CloseJobInfo(hPrinter); }
// Our write-port does leave the crit-sect. If this
// routine is called while we're still in an end-doc, then
// we will set a zombie-flag and let the End-Doc clean up
// the handle for us.
//
if (PP_ChkStatus(hPrinter, PP_ENDDOC)) {
bRet = TRUE;
PP_SetStatus(hPrinter, PP_ZOMBIE);
} else {
bRet = gpInetMon->InetmonClosePort(pIniPort, hPrinter ); _ppprn_free_hprinter(hPrinter); } } } #ifdef WINNT32
else if (utlValidateXcvPrinterHandle(hPrinter) ) {
//
// We don't need to dec-ref on the http port for XCV handle
//
//
// Free memory
//
_ppprn_free_xcv_hprinter(hPrinter); } #endif
semLeaveCrit();
return bRet; }
/*****************************************************************************\
* PPEndDocPrinter * * Ends a print job on the specified printer. Returns TRUE if successful, * FALSE otherwise. * \*****************************************************************************/
BOOL PPEndDocPrinter( HANDLE hPrinter) { PCINETMONPORT pIniPort; PJOBMAP pjmJob; DWORD dwLE; BOOL bRet = FALSE;
DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPEndDocPrinter: Printer(%08lX)"), hPrinter));
semEnterCrit();
if (pIniPort = utlValidatePrinterHandle(hPrinter)) {
// Verify that we are in a StartDoc.
//
if ( PP_ChkStatus(hPrinter, PP_STARTDOC) && !PP_ChkStatus(hPrinter, PP_ENDDOC)) {
PP_SetStatus(hPrinter, PP_ENDDOC);
// Get the job we're dealing with.
//
pjmJob = PP_GetJobInfo(hPrinter);
// End the job. This closes our spooling
// and submits it to the server. If our job was
// cancelled at anytime prior to EndDoc(), then we should
// only remove the local-spool-job and not hit the server.
//
if (pjmChkState(pjmJob, PJM_CANCEL)) {
bRet = TRUE;
} else {
#ifdef WINNT32
if ((bRet = _ppprn_end_docprinter_async(pIniPort, pjmJob)) == FALSE) dwLE = ERROR_CAN_NOT_COMPLETE; #else
if ((bRet = pIniPort->EndDocPort(pjmJob)) == FALSE) dwLE = ERROR_CAN_NOT_COMPLETE; #endif
}
// Clear our flags so others can use the
// printer.
//
PP_ClrStatus(hPrinter, (PP_STARTDOC | PP_ENDDOC));
#ifdef WINNT32
PP_CloseJobInfo2(hPrinter); #else
PP_CloseJobInfo(hPrinter);
// Invalidate both job and printer caches
//
pIniPort->InvalidateGetPrinterCache (); pIniPort->InvalidateEnumJobsCache (); #endif
// Since the end-doc-port leaves the crit-sect, there's
// the possibility that the printer-handle has been
// closed. If so, check for zombie-status and delete
// the printer-handle accordingly.
//
if (PP_ChkStatus(hPrinter, PP_ZOMBIE)) {
gpInetMon->InetmonClosePort(pIniPort, hPrinter);
_ppprn_free_hprinter(hPrinter); }
} else {
if (PP_ChkStatus(hPrinter, PP_CANCELLED)) dwLE = ERROR_PRINT_CANCELLED; else dwLE = ERROR_SPL_NO_STARTDOC; }
} else {
dwLE = ERROR_INVALID_HANDLE; }
semLeaveCrit();
if (bRet == FALSE) SetLastError(dwLE);
return bRet; }
/*****************************************************************************\
* PPEndPagePrinter * * Informs the printer that the data sent with WritePrinter since the last * BeginPage functions, constitutes a page. Returns TRUE if successful. * Otherwise, it returns FALSE. * \*****************************************************************************/ BOOL PPEndPagePrinter( HANDLE hPrinter) { BOOL bRet = FALSE;
DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPEndPagePrinter: hPrinter(%08lX)"), hPrinter));
semEnterCrit();
if (utlValidatePrinterHandle(hPrinter) != NULL) {
if (PP_ChkStatus(hPrinter, PP_CANCELLED)) SetLastError(ERROR_PRINT_CANCELLED); else bRet = TRUE; }
semLeaveCrit();
return bRet; }
/*****************************************************************************\
* PPOpenPrinter * * Obtains a handle for the specified printer (queue). * * NOTE: We're going to delay the validation of the printer-port-name until * later (StartDoc), as to handle cases where the server is down. If * this is not done, we appear to hang at the UI as we attempt to * send a request to the server. * * Return Value: * * We have to return the correct router code to the spooler * * ROUTER_* status code: * * ROUTER_SUCCESS, phPrinter holds return handle, name cached * ROUTER_UNKNOWN, printer not recognized, error updated * ROUTER_STOP_ROUTING, printer recognized, but failure, error updated * * \*****************************************************************************/ #ifdef WINNT32
BOOL PPOpenPrinter( LPTSTR lpszPrnName, LPHANDLE phPrinter, LPPRINTER_DEFAULTS pDefaults) { PCINETMONPORT pIniPort; BOOL bRet = FALSE; DWORD dwRet = ROUTER_UNKNOWN; DWORD dwLE; BOOL bXcv = FALSE;
DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPOpenPrinter: Name(%s)"), lpszPrnName));
semEnterCrit();
// Open the port for the printer, and create the true
// printer handle.
//
if (pIniPort = gpInetMon->InetmonOpenPort(lpszPrnName, &bXcv)) {
if (!bXcv) { // Not an XcvOpen call
if (*phPrinter = _ppprn_make_hprinter(pIniPort, lpszPrnName)) {
if (__ppprn_inc_user_refcout( *phPrinter ) != MAXDWORD ) { dwRet = ROUTER_SUCCESS; } else { _ppprn_free_hprinter( *phPrinter ); // This will also free the hUser
*phPrinter = NULL; // Make sure we don't return anything and the router stops.
dwRet = ROUTER_STOP_ROUTING; }
} else {
SetLastError(ERROR_OUTOFMEMORY);
gpInetMon->InetmonClosePort(pIniPort, NULL ); dwRet = ROUTER_STOP_ROUTING; } } else { // XcvOpen call
if (*phPrinter = _ppprn_make_xcv_hprinter(pIniPort)) { dwRet = ROUTER_SUCCESS; } else { SetLastError(ERROR_OUTOFMEMORY);
//
// We don't need to dec-ref port since we never add-ref in XCV Open
//
dwRet = ROUTER_STOP_ROUTING; } } }
semLeaveCrit();
DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPOpenPrinter : Return Value(%d), LastError(%d)"), dwRet, GetLastError()));
return dwRet; }
#else
// Win9X Code
BOOL PPOpenPrinter( LPTSTR lpszPrnName, LPHANDLE phPrinter, LPPRINTER_DEFAULTS pDefaults) { PCINETMONPORT pIniPort; BOOL bRet = FALSE; DWORD dwRet = ROUTER_UNKNOWN; DWORD dwLE; BOOL bXcv = FALSE;
DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPOpenPrinter: Name(%s)"), lpszPrnName));
semEnterCrit();
// Open the port for the printer, and create the true
// printer handle.
//
if ((pIniPort = gpInetMon->InetmonOpenPort(lpszPrnName, &bXcv)) && !bXcv) {
if (*phPrinter = _ppprn_make_hprinter(pIniPort, lpszPrnName)) {
dwRet = ROUTER_SUCCESS;
} else {
SetLastError(ERROR_OUTOFMEMORY);
gpInetMon->InetmonClosePort(pIniPort, NULL ); } }
semLeaveCrit();
DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPOpenPrinter : Return Value(%d), LastError(%d)"), dwRet, GetLastError()));
return dwRet; }
#endif
/*****************************************************************************\
* PPStartDocPrinter * * Ends a print job on the specified printer. Returns a print job ID if * successful. Otherwise, it returns zero. * \*****************************************************************************/ DWORD PPStartDocPrinter( HANDLE hPrinter, DWORD dwLevel, LPBYTE pDocInfo) { PCINETMONPORT pIniPort = NULL; PJOBMAP pjmJob; DWORD idJob = 0;
DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPStartDocPrinter: Printer(%08lX) dwLevel(%d)"), hPrinter, dwLevel));
semEnterCrit();
if (pIniPort = utlValidatePrinterHandle(hPrinter)) {
// Look at the support levels, then do the StartDocPrinter on
// the port.
//
switch (dwLevel) {
case PRINT_LEVEL_1:
// Serialize access to the port. Don't allow startdoc on
// the printer if one is already in progress.
//
if (PP_ChkStatus(hPrinter, PP_STARTDOC)) {
SetLastError(ERROR_BUSY);
} else {
if (pjmJob = PP_OpenJobInfo(hPrinter, pIniPort, ((PDOC_INFO_1) pDocInfo)->pDocName)) {
// Get the JobId for the start-doc, then set the info
// into the printer-handle.
//
if (pIniPort->StartDocPort(dwLevel, pDocInfo, pjmJob)) {
idJob = pjmJobId(pjmJob, PJM_LOCALID);
PP_ClrStatus(hPrinter, PP_CANCELLED); PP_SetStatus(hPrinter, (PP_STARTDOC | PP_FIRSTWRITE));
} else {
PP_CloseJobInfo(hPrinter); }
} else {
SetLastError(ERROR_OUTOFMEMORY); } } break;
default: DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: PPStartDocPrinter: Invalid Level (%d)"), dwLevel)); SetLastError(ERROR_INVALID_LEVEL); break; } }
semLeaveCrit();
return idJob; }
/*****************************************************************************\
* PPStartPagePrinter * * Informs the spool subsystem that a page is about to be started on this * printer. Returns TRUE if successful. Otherwise, FALSE if an error occurs. * \*****************************************************************************/ BOOL PPStartPagePrinter( HANDLE hPrinter) { BOOL bRet = FALSE;
DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPStartPagePrinter: hPrinter(%08lX)"), hPrinter));
semEnterCrit();
if (utlValidatePrinterHandle(hPrinter) != NULL) {
if (PP_ChkStatus(hPrinter, PP_CANCELLED)) SetLastError(ERROR_PRINT_CANCELLED); else bRet = TRUE; }
semLeaveCrit();
return bRet; }
/*****************************************************************************\
* PPWritePrinter * * Sends the data pointed to by pBuf to the specified printer. Returns TRUE * if successful. Otherwise, it returns FALSE. * \*****************************************************************************/ BOOL PPWritePrinter( HANDLE hPrinter, LPVOID lpvBuf, DWORD cbBuf, LPDWORD pcbWr) { PCINETMONPORT pIniPort; PJOBMAP pjmJob; BOOL bRet = FALSE;
DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPWritePrinter: Printer(%08lX)"), hPrinter));
semEnterCrit();
*pcbWr = 0;
if (pIniPort = utlValidatePrinterHandle(hPrinter)) {
// If we're in a start-doc, and end-doc hasn't been
// called, then we can still write to the port.
//
if ( PP_ChkStatus(hPrinter, PP_STARTDOC) && !PP_ChkStatus(hPrinter, PP_ENDDOC)) {
pjmJob = PP_GetJobInfo(hPrinter);
// If we received a SetJob(CANCEL), during the print-spooling
// process, then we need to mark our job as done.
//
if (!pjmChkState(pjmJob, PJM_CANCEL)) {
bRet = pIniPort->WritePort(pjmJob, (LPBYTE) lpvBuf, cbBuf, pcbWr);
#ifdef WINNT32
pjmAddJobSize (pjmJob, *pcbWr);
// We do not need to update the cache since the job info is stored locally
//
RefreshNotificationPort (pIniPort); #endif
} else {
bRet = TRUE;
if (pIniPort->AbortPort(pjmJob)) {
// If this call was successful, the job-info
// will have been freed. Therefore, it is OK
// to set the printer-jobreq to NULL.
//
PP_SetStatus(hPrinter, PP_CANCELLED); PP_ClrStatus(hPrinter, PP_STARTDOC); PP_CloseJobInfo(hPrinter); } }
} else {
if (PP_ChkStatus(hPrinter, PP_CANCELLED)) SetLastError(ERROR_PRINT_CANCELLED); else SetLastError(ERROR_SPL_NO_STARTDOC); } }
semLeaveCrit();
return bRet; }
/*****************************************************************************\
* PPSetPrinter * * Set printer command. * \*****************************************************************************/ BOOL PPSetPrinter( HANDLE hPrinter, DWORD dwLevel, LPBYTE pbPrinter, DWORD dwCmd) { PCINETMONPORT pIniPort; BOOL bRet = FALSE;
DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPSetPrinter: Printer(%08lX)"), hPrinter));
semEnterCrit();
if (pIniPort = utlValidatePrinterHandle(hPrinter)) {
#ifdef WINNT32
// Set printer parameters.
//
switch (dwLevel) {
case PRINT_LEVEL_0:
// Do not set parameters. (0) represents "no-command".
//
switch (dwCmd) {
case PRINTER_CONTROL_PAUSE: case PRINTER_CONTROL_RESUME: case PRINTER_CONTROL_PURGE: bRet = ppprn_Set(pIniPort, dwCmd);
if (bRet) { pIniPort->InvalidateGetPrinterCache ();
if (dwCmd == PRINTER_CONTROL_PURGE) { //
// Clean job cache if the command is to cancel all documents
//
pIniPort->InvalidateEnumJobsCache (); }
RefreshNotification((LPINET_HPRINTER)hPrinter); }
break;
case 0: bRet = TRUE; break; } break;
default: DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: PPSetPrinter: Invalid Level (%d)"), dwLevel)); SetLastError(ERROR_INVALID_LEVEL); break; } #else
if (dwCmd) {
// Do not set parameters. (0) represents "no-command".
//
switch (dwCmd) {
case PRINTER_CONTROL_PAUSE: case PRINTER_CONTROL_RESUME: case PRINTER_CONTROL_PURGE: bRet = ppprn_Set(pIniPort, dwCmd); break; }
} else {
switch (dwLevel) {
case PRINT_LEVEL_1: case PRINT_LEVEL_2:
case PRINT_LEVEL_0: default: DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: PPSetPrinter: Invalid Level (%d)"), dwLevel)); SetLastError(ERROR_INVALID_LEVEL); break; } } #endif
}
semLeaveCrit();
return bRet; }
|