Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

644 lines
18 KiB

/* ---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;
}