windows-nt/Source/XPSP1/NT/printscan/print/spooler/inetpp2/server/ppprn.cxx

1285 lines
31 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*****************************************************************************\
* 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;
}