|
|
/* ---File: printer.c -----------------------------------------------------
* * Description: * Contains functions for managing network print queues. * * This document contains confidential/proprietary information. * Copyright (c) 1990-1992 Microsoft Corporation, All Rights Reserved. * * Revision History: * [00] 21-Nov-90 stevecat created * [01] 03-Jan-91 stevecat Modified to use Windows MDI * [02] 25-Mar-91 stevecat Modified to use NT WINSPOOL APIs * [03] 13-Jan-92 stevecat New PrintMan UI * [04] 01-Mar-92 davesn New APIs * * ---------------------------------------------------------------------- */ /* Notes -
Global Functions:
AllocQueue () - Allocate memory for QUEUE struct and initialize it DeleteQJ () - Delete selected print job or all jobs on a queue DestroyPrinter () - Delete printer and memory associated with it FreeQueue () - Free local memory for QUEUE struct. GetJobs () - Retrieve info on print queues and theirjobs PauseResumeQJ () - Pause or Continue selected print job or queue
Local Functions:
*/ #include "printman.h"
VOID FreeJobInfo( PQUEUE pQueue );
/* --- Function: AllocQueue -------------------------------------------------
* * AllocQueue (LPTSTR pPrinterName) * * Description: * Allocate local memory for QUEUE struct and initialize it. * * ---------------------------------------------------------------------- */
PQUEUE AllocQueue( LPTSTR pPrinterName ) { PQUEUE pQueue;
if( ( pQueue = AllocSplMem( sizeof( QUEUE ) ) ) &&( pQueue->pPrinterName = AllocSplStr( pPrinterName ) ) ) { pQueue->pPrinter = NULL; pQueue->cbPrinterBuf = 0; pQueue->pJobs = NULL; pQueue->cJobs = 0; pQueue->cbJobsBuf = 0; } else if( pQueue ) { FreeSplMem( pQueue ); pQueue = NULL; } return pQueue; }
/* --- Function: FreeQueue -------------------------------------------------
* * FreeQueue(PQUEUE pQueue) * * Description: * Free local memory for QUEUE struct. * * ---------------------------------------------------------------------- */
BOOL FreeQueue( PQUEUE pQueue ) { if(pQueue->pServerName) FreeSplStr(pQueue->pServerName); FreeSplStr(pQueue->pPrinterName); FreeSplMem(pQueue);
return TRUE; }
/* --- Function: DeleteQJ ---------------------------------------------------
* * DeleteQJ (PQUEUE pQueue) * * Description: * Delete selected print job or all jobs on print queue * * ---------------------------------------------------------------------- */ DWORD DeleteQJ (HWND hwnd, PQUEUE pQueue) { DWORD Error = 0;
if (!pQueue) return 0;
if (pQueue->SelJobId) { // Cancel the print job
if (!SetJob(pQueue->hPrinter, pQueue->SelJobId, 0, NULL, JOB_CONTROL_CANCEL)) { Error = GetLastError(); DBGMSG( DBG_WARNING, ("PrintManager.DeleteQJ::SetJob.Cancel failed %d.\n", Error) ); } } else { // Make sure user wants to delete ALL jobs before actually doing it,
// if there's more than one job queued:
if ( ( pQueue->cJobs == 1 ) ||( Message( hwnd, MSG_CONFIRMATION, IDS_PRINTMANAGER, IDS_DELETEALLPRINTJOBS_S, pQueue->pPrinterName ) == IDOK ) )
// Delete all jobs on printer
if (!SetPrinter(pQueue->hPrinter, 0, NULL, PRINTER_CONTROL_PURGE)) { Error = GetLastError(); DBGMSG( DBG_WARNING, ("PrintManager.DeleteQJ::SetPrinter failed %d.\n", Error) ); } } return Error; }
/* --- Function: DestroyPrinter ---------------------------------------------
* * DestroyPrinter(PQUEUE pQueue) * * Description: * Delete printer and free all memory for it. * * ---------------------------------------------------------------------- */ BOOL DestroyPrinter( PQUEUE pQueue ) { if (pQueue->pPrinter) FreeSplMem(pQueue->pPrinter);
if( pQueue->pJobs ) FreeSplMem(pQueue->pJobs);
if( pQueue->cbSelJob > 0 ) FreeSplMem(pQueue->pSelJob);
FreeQueue(pQueue);
return TRUE; }
VOID DestroyServer( PSERVER_CONTEXT pServerContext ) { FreeSplStr( pServerContext->pServerName );
if (pServerContext->pPrinters ) FreeSplMem( pServerContext->pPrinters );
FreeSplMem( pServerContext ); }
VOID DestroyMDIWinInfo( PMDIWIN_INFO pInfo ) { if( pInfo->WindowType == MDIWIN_SERVER ) DestroyServer( pInfo->pContext ); else DestroyPrinter( pInfo->pContext );
CloseHandle( pInfo->DataMutex ); CloseHandle( pInfo->RefreshSignal );
FreeSplMem( pInfo->pColumns ); FreeSplMem( pInfo ); }
int GetSelectedJobIndex( PQUEUE pQueue ) { BOOL JobIdFound = FALSE; DWORD i;
i = 0;
while( !JobIdFound && ( i < pQueue->cEnumJobs ) ) { if( pQueue->pJobs[i].JobId == pQueue->SelJobId ) JobIdFound = TRUE; else i++; }
return ( JobIdFound ? i : -1 ); }
LPJOB_INFO_2 UpdateJobInfo( HANDLE hPrinter, DWORD JobId, LPJOB_INFO_2 pJob, PDWORD pcbBuf ) { DWORD cbNeeded; DWORD Error; BOOL ForgetIt = FALSE;
DBGMSG( DBG_TRACE, ( "UpdateJobInfo, JobId == %d\n", JobId ) );
if( !GetJob( hPrinter, JobId, 2, (LPBYTE)pJob, *pcbBuf, &cbNeeded ) ) { Error = GetLastError();
if( Error == ERROR_INSUFFICIENT_BUFFER ) { pJob = ReallocSplMem( pJob, cbNeeded );
if( pJob ) { if( !GetJob( hPrinter, JobId, 2, (LPBYTE)pJob, cbNeeded, &cbNeeded ) ) ForgetIt = TRUE; } else ForgetIt = TRUE; } else ForgetIt = TRUE;
if( ForgetIt ) { if( pJob ) FreeSplMem( pJob ); pJob = NULL; *pcbBuf = 0; } } else *pcbBuf = cbNeeded;
DBGMSG( DBG_TRACE, ( "UpdateJobInfo returned %08x\n", pJob ) );
return pJob; }
/* --- Function: GetJobs ----------------------------------------------------
* * GetJobs (HWND hWnd, PQUEUE pQueue) * * Description: * Retrieve current Printer status and its Jobs from WINSPOOL API. * * ---------------------------------------------------------------------- */ BOOL GetJobs( PVOID pContext, PDWORD pFlags ) { LPPRINTER_INFO_2 pNewPrinter = NULL; DWORD cbNewPrinterBuf; PQUEUE pQueue; DWORD Error; DWORD cbNewJobsBuf; LPJOB_INFO_2 pNewJobs = NULL; DWORD cNewJobs; int SelectedJobIndex; DWORD TryEnumJobs; BOOL rc;
pQueue = (PQUEUE)pContext;
if( !pQueue ) { DBGMSG( DBG_WARNING, ( "GetJobs called with pQueue == NULL\n" ) ); return FALSE; }
if( !pQueue->hPrinter ) { LEAVE_PROTECTED_DATA( pQueue->pMDIWinInfo ); DBGMSG( DBG_WARNING, ( "GetJobs called with hPrinter == NULL, re-opening!\n" ) ); ReopenPrinter(pQueue, pQueue->pMDIWinInfo->WindowType, FALSE); ENTER_PROTECTED_DATA( pQueue->pMDIWinInfo ); }
if (!pQueue->hPrinter) return FALSE;
pQueue->Error = 0;
if( *pFlags & PRINTER_CHANGE_PRINTER ) { if( cbNewPrinterBuf = pQueue->cbPrinterBuf ) pNewPrinter = AllocSplMem( cbNewPrinterBuf );
DBG_IN_PROTECTED_DATA( pQueue->pMDIWinInfo ); LEAVE_PROTECTED_DATA( pQueue->pMDIWinInfo ); ENTER_PROTECTED_HANDLE( pQueue->pMDIWinInfo );
rc = GetGeneric( (PROC)GetPrinter, 2, (LPBYTE *)&pNewPrinter, cbNewPrinterBuf, &cbNewPrinterBuf, pQueue->hPrinter, NULL );
LEAVE_PROTECTED_HANDLE( pQueue->pMDIWinInfo ); #if DBG
if( rc && !pNewPrinter ) { DBGMSG( DBG_ERROR, ( "GetGeneric( GetPrinter ) returned TRUE, but pNewBuffer is NULL.\n" "\tPrinter: %ls\n", pQueue->pPrinterName ) ); } #endif /* DBG */
ENTER_PROTECTED_DATA( pQueue->pMDIWinInfo );
if (!rc) {
//
// Attempt to reopen
//
if (pQueue->hPrinter) {
ClosePrinter(pQueue->hPrinter); pQueue->hPrinter = NULL; }
LEAVE_PROTECTED_DATA( pQueue->pMDIWinInfo );
ReopenPrinter(pQueue, pQueue->pMDIWinInfo->WindowType, FALSE);
ENTER_PROTECTED_DATA( pQueue->pMDIWinInfo );
#ifdef SEP_WAITHANDLE
if (pQueue->hPrinterWait) {
ClosePrinter(pQueue->hPrinterWait); pQueue->hPrinterWait = NULL; } #endif
//
// Try again
//
rc = GetGeneric( (PROC)GetPrinter, 2, (LPBYTE *)&pNewPrinter, cbNewPrinterBuf, &cbNewPrinterBuf, pQueue->hPrinter, NULL ); }
if (rc) {
if( pQueue->pPrinter ) FreeSplMem( pQueue->pPrinter );
pQueue->pPrinter = pNewPrinter; pQueue->cbPrinterBuf = cbNewPrinterBuf;
pQueue->pMDIWinInfo->Status &= ~PRINTER_STATUS_UNKNOWN;
} else {
DBGMSG( DBG_WARNING, ("GetPrinter failed for %ls: Error %d\n", pQueue->pPrinterName, pQueue->Error ) );
pQueue->pMDIWinInfo->Status |= PRINTER_STATUS_UNKNOWN;
if( pQueue->pPrinter ) FreeSplMem( pQueue->pPrinter );
if( pNewPrinter ) FreeSplMem( pNewPrinter );
pQueue->pPrinter = NULL; pQueue->cbPrinterBuf = 0;
FreeJobInfo( pQueue );
return FALSE; } }
if( *pFlags & PRINTER_CHANGE_JOB ) { /* Try to enumerate a buffer big enough to fill three pages of information,
* so that we can scroll up or down a full page before it becomes necessary * to refresh the buffer. (Though with a refresh rate of once per second, * this will probably happen anyway.) * Note that pQueue->FirstEnumJob was set in Refresh (printman.c). * If it is 0, we may be currently scrolled to the top of the list, * in which case the buffer will extend two pages forward. */ TryEnumJobs = ( pQueue->pMDIWinInfo->cNumLines * 3 );
if( cbNewJobsBuf = pQueue->cbJobsBuf ) pNewJobs = AllocSplMem( cbNewJobsBuf );
DBG_IN_PROTECTED_DATA( pQueue->pMDIWinInfo ); LEAVE_PROTECTED_DATA( pQueue->pMDIWinInfo );
ENTER_PROTECTED_HANDLE( pQueue->pMDIWinInfo );
rc = ENUM_JOBS( pQueue->hPrinter, pQueue->FirstEnumJob, TryEnumJobs, 2, pNewJobs, cbNewJobsBuf, &cbNewJobsBuf, &cNewJobs );
LEAVE_PROTECTED_HANDLE( pQueue->pMDIWinInfo );
ENTER_PROTECTED_DATA( pQueue->pMDIWinInfo );
if( rc ) { DBGMSG( DBG_TRACE, ( "EnumJobs returned %d job%s @%08x in %d (0x%x) bytes for %s\n", cNewJobs, ( cNewJobs == 1 ? " " : "s" ), pNewJobs, cbNewJobsBuf, cbNewJobsBuf, pQueue->pPrinterName ) );
if( pQueue->pJobs ) { FreeSplMem( pQueue->pJobs ); }
/* Free up the previously allocated buffer
* if we don't need it any more: */ if( pNewJobs && ( cNewJobs == 0 ) ) { DBGMSG( DBG_TRACE, ( "Freeing %d (0x%x) bytes @%08x\n", cbNewJobsBuf, cbNewJobsBuf, pNewJobs ) ); FreeSplMem( pNewJobs ); pNewJobs = NULL; cbNewJobsBuf = 0; }
pQueue->pJobs = pNewJobs; pQueue->cbJobsBuf = cbNewJobsBuf;
/* We shouldn't really get here if pQueue->pPrinter is non-NULL,
* but it seems to be happening sometimes. */ if( pQueue->pPrinter ) pQueue->cJobs = pQueue->pPrinter->cJobs; else pQueue->cJobs = 0;
pQueue->cEnumJobs = cNewJobs; }
else { Error = GetLastError( );
DBGMSG( DBG_WARNING, ("EnumJobs failed for %ls: Error %d\n", pQueue->pPrinterName, Error) );
if( Error != ERROR_INSUFFICIENT_BUFFER ) { FreeJobInfo( pQueue ); pQueue->Error = Error; } }
if( pQueue->pJobs ) { SelectedJobIndex = GetSelectedJobIndex( pQueue );
DBGMSG( DBG_TRACE, ( "Selected job index == %d\n", SelectedJobIndex ) );
/* The selected job may have been scrolled out of buffer range.
* In this case we allocate some job info for it: */ if( ( pQueue->SelJobId ) && ( SelectedJobIndex == -1 ) ) { DBGMSG( DBG_TRACE, ( "Selected job is scrolled out of range\n" ) );
/* If it's just gone out of range, set the selected-job pointer
* to NULL, so we don't try to Realloc part of the buffer. * (cbSelJob is non-null if we were out of range last time round, * because we allocated a job info structure.) */ if( pQueue->cbSelJob == 0 ) pQueue->pSelJob = NULL;
pQueue->pSelJob = UpdateJobInfo( pQueue->hPrinter, pQueue->SelJobId, pQueue->pSelJob, &pQueue->cbSelJob );
/* If the returned job info is NULL, either the job is no longer
* around, or there was some sort of error. * In either case, deselect the current job: */ if( !pQueue->pSelJob ) { pQueue->SelJobId = 0; pQueue->pMDIWinInfo->ObjSelected = NOSELECTION; } }
/* Otherwise just point the selected-job pointer at the appropriate
* bit of the buffer: */ else { /* If there was a job info allocated earlier, free it up.
* cbSelJob must be 0 if there is no specially allocated buffer: */ if( pQueue->cbSelJob ) { FreeSplMem( pQueue->pSelJob ); pQueue->pSelJob = NULL; pQueue->cbSelJob = 0; }
if( pQueue->SelJobId ) { pQueue->pSelJob = &pQueue->pJobs[SelectedJobIndex]; pQueue->pMDIWinInfo->ObjSelected = ( pQueue->FirstEnumJob + SelectedJobIndex );
DBGMSG( DBG_TRACE, ( "Selected job == %08x\n", pQueue->pSelJob ) ); } } }
else { /* Make sure any previous selection is canceled:
*/ pQueue->pSelJob = NULL; pQueue->SelJobId = 0; pQueue->pMDIWinInfo->ObjSelected = NOSELECTION; } }
return TRUE; }
/*
* */ VOID FreeJobInfo( PQUEUE pQueue ) { if (pQueue->pJobs) FreeSplMem(pQueue->pJobs);
pQueue->pJobs = NULL; pQueue->cbJobsBuf = 0;
pQueue->cEnumJobs = 0; pQueue->cJobs = 0; }
/* OpenPrinterForSpecifiedAccess
* * Attempts to open the printer for the requested access. * The following access permissions are valid: * * PRINTER_ALL_ACCESS * PRINTER_READ * READ_CONTROL * * If PRINTER_ACCESS_HIGHEST_PERMITTED is specified, * this function will attempt to open the printer using each of the above * permissions until it is successful. * */ BOOL OpenPrinterForSpecifiedAccess( LPTSTR pName, LPHANDLE pHandle, DWORD AccessRequested, OPTIONAL PDWORD pAccessGranted ) { PRINTER_DEFAULTS PrinterDefaults; BOOL rc = FALSE; BOOL TryAll = FALSE;
PrinterDefaults.pDatatype = NULL; PrinterDefaults.pDevMode = NULL;
switch( AccessRequested ) { case PRINTER_ACCESS_HIGHEST_PERMITTED: TryAll = TRUE; /* fall through ... */
case PRINTER_ALL_ACCESS: PrinterDefaults.DesiredAccess = PRINTER_ALL_ACCESS; rc = OpenPrinter( pName, pHandle, &PrinterDefaults ); if( rc || !TryAll || (( GetLastError( ) != ERROR_ACCESS_DENIED ) && ( GetLastError( ) != ERROR_PRIVILEGE_NOT_HELD)) ) break;
case PRINTER_READ: PrinterDefaults.DesiredAccess = PRINTER_READ; rc = OpenPrinter( pName, pHandle, &PrinterDefaults ); if( rc || !TryAll || (( GetLastError( ) != ERROR_ACCESS_DENIED ) && ( GetLastError( ) != ERROR_PRIVILEGE_NOT_HELD)) ) break;
case READ_CONTROL: PrinterDefaults.DesiredAccess = READ_CONTROL; rc = OpenPrinter( pName, pHandle, &PrinterDefaults ); }
if( pAccessGranted ) { if( rc ) *pAccessGranted = PrinterDefaults.DesiredAccess; else *pAccessGranted = PRINTER_ACCESS_DENIED; }
return rc; }
|