|
|
/*++
Copyright (c) 1991-1993 Microsoft Corporation
Module Name:
DosPrtW.c
Abstract:
This module provides the UNICODE mapping layer from the old DosPrint APIs to the new all singing all dancing beautiful Print APIs. (The ANSI mapping layer is in DosPrint.c)
Author:
Dave Snipp (DaveSn) 26-Apr-1991
Revision History:
09-Jul-1992 JohnRo Created this file (from DaveSn's DosPrint.c) for RAID 10324: net print vs. UNICODE. 05-Oct-1992 JohnRo RAID 3556: DosPrintQGetInfo(from downlevel) level 3, rc=124. (4&5 too.) RAID 3580: lmsvcs.exe: access violation from OS/2 DosPrintJobGetInfo. RAID 8333: view printer queues hangs DOS LM enh client. Make sure data type in job level 1 is null terminated. Fixed job submitted times. Fixed error code if GlobalAlloc fails. Fixed memory leak in DosPrintQGetInfoW. Fixed DosPrintQEnumW level 5 array bug. Fixed DosPrintJobEnumW levels 2 and 3. 25-Nov-1992 JohnRo RAID 1661: downlevel to NT DosPrintDestEnum not supported. Added code to track down empty queue name. Quiet normal debug output. Avoid const vs. volatile compiler warnings. Avoid other new compiler warnings. 08-Feb-1993 JohnRo RAID 10164: Data misalignment error during XsDosPrintQGetInfo(). 22-Mar-1993 JohnRo RAID 2974: NET PRINT says NT printer is held when it isn't. 11-May-1993 JohnRo RAID 9942: fix queue name in job info level 3. 14-May-1993 JohnRo RAID 9961: DosPrintDestEnum returns NO_ERROR to downlevel but pcReturned=0; should return NERR_DestNotFound. Fixed data type returned from PrjInfoFixedSizeW(). 18-May-1993 JohnRo DosPrintQGetInfoW underestimates number of bytes needed. Use NetpKdPrint() where possible. Made changes suggested by PC-LINT. 04-Jun-1993 JohnRo RAID 10222: DosPrintQEnumW returns ERROR_INVALID_USER_BUFFER when queue is empty. Made changes suggested by PC-LINT 5.0 08-Jul-1993 JohnRo RAID 15509: GetJob() API sometimes returned TRUE, even on error case. Also added some >64KB checks. Added some assert checks... 13-Jul-1993 JohnRo Intermittent empty print queue (was buggy after some MyEnumJobs calls). 29-Mar-1995 AlbertT Support for pause/resume/purge printer queue added. SetJobInfo 1 comment field (translated into document name) support added so that chicago clients can set the doc name.
--*/
#ifndef UNICODE
#error "RxPrint APIs assume RxRemoteApi uses wide characters."
#endif
#define NOMINMAX
#define NOSERVICE // Avoid <winsvc.h> vs. <lmsvc.h> conflicts.
#include <windows.h>
//#include <lm.h>
#include <netdebug.h>
#include <string.h>
#include <align.h>
#ifdef _WINSPOOL_
#error "Include of winspool.h moved, make sure it doesn't get UNICODE."
#endif
#undef UNICODE
#undef TEXT
#define TEXT(quote) quote
#include <winspool.h>
#undef TEXT
#define TEXT(quote) __TEXT(quote)
#define UNICODE
#ifndef _WINSPOOL_
#error "Oops, winspool.h changed, make sure this code is still OK."
#endif
#include <dosprint.h>
#include <dosprtp.h> // CommandALocalJob(), etc.
#include <lmapibuf.h> // NetApiBufferFree(), etc.
#include <lmerr.h> // NO_ERROR, NERR_, and ERROR_ equates.
#include <lmshare.h> // LPSHARE_INFO_1, STYPE_ equates, etc.
#include <prefix.h> // PREFIX_ equates.
#include <stddef.h> // offsetof().
#include <timelib.h> // NetpSystemTimeToGmtTime().
#include <tstring.h> // WCSSIZE(), NetpNCopy{type}To{type}.
#include <wchar.h> // wsclen(), wcscpy(), etc.
#include "myspool.h"
#define STR_CONV_SIZE(psz) ( (strlen(psz)+1) * sizeof(WCHAR) )
// NULL_STR_CONV_SIZE: Compute size needed for converted string, which
// is possibly a null pointer but downlevel really wants ptr to null char.
#define NULL_STR_CONV_SIZE(psz) ( (psz) ? STR_CONV_SIZE(psz) : sizeof(WCHAR) )
#define ARRAY_END ((DWORD) -1)
#define MAX_WORD ( (WORD) (~0) )
#define MY_PROTOCOL_LIMIT_ERROR ERROR_NOT_ENOUGH_MEMORY
#define WIN95_DRIVER_SHARE "\\print$\\WIN40\\0"
VOID NetpSetJobCountForQueue( IN DWORD QueueLevel, IN OUT LPVOID Queue, IN BOOL HasUnicodeStrings, IN DWORD JobCount );
DBGSTATIC LPWSTR PackAnsiStringsToW( LPSTR *pSource, LPBYTE pDest, CONST DWORD *DestOffsets, LPWSTR pEnd ) { // Make sure our end pointer is WCHAR aligned or we'll fault later
pEnd = ROUND_DOWN_POINTER( pEnd, ALIGN_WCHAR );
while (*DestOffsets != ARRAY_END) { if (*pSource) { pEnd-=(strlen(*pSource) + 1);
// Copy the string and convert chars while we're at it.
NetpCopyStrToWStr(pEnd, *pSource);
*(LPWSTR *)(pDest+*DestOffsets) = pEnd; } else { --pEnd; // need 1 char for this.
*pEnd = L'\0'; *(LPWSTR *)(pDest+*DestOffsets) = pEnd; } pSource++; DestOffsets++; }
return pEnd; }
DBGSTATIC DWORD PrjInfoFixedSizeW( IN DWORD Level // assumed valid
) { switch (Level) {
case 0: return sizeof(WORD); // job number.
case 1: return (sizeof(PRJINFOW)); case 2: return (sizeof(PRJINFO2W)); case 3: return (sizeof(PRJINFO3W)); default: NetpAssert( FALSE ); return (0); } /*NOTREACHED*/ }
DBGSTATIC DWORD GetPrjInfoSizeW( IN DWORD Level, IN LPJOB_INFO_2 pJob, IN LPCWSTR QueueNameW ) { NetpAssert( pJob != NULL ); switch (Level) {
case 0:
return sizeof(WORD); // job number.
case 1:
return sizeof(PRJINFOW) + NULL_STR_CONV_SIZE( (LPSTR) (pJob->pParameters) ) + NULL_STR_CONV_SIZE( (LPSTR) (pJob->pStatus) ) + NULL_STR_CONV_SIZE( (LPSTR) (pJob->pDocument) ); // fake pszComment
case 2:
return sizeof(PRJINFO2W) + NULL_STR_CONV_SIZE( (LPSTR) (pJob->pUserName) ) + NULL_STR_CONV_SIZE( (LPSTR) (pJob->pDocument) ) + // fake pszComment
NULL_STR_CONV_SIZE( (LPSTR) (pJob->pDocument) );
case 3:
NetpAssert( QueueNameW != NULL );
return sizeof(PRJINFO3W) + NULL_STR_CONV_SIZE( (LPSTR) (pJob->pUserName) ) + NULL_STR_CONV_SIZE( (LPSTR) (pJob->pDocument) ) + // fake pszComment
NULL_STR_CONV_SIZE( (LPSTR) (pJob->pDocument) ) + NULL_STR_CONV_SIZE( (LPSTR) (pJob->pNotifyName) ) + NULL_STR_CONV_SIZE( (LPSTR) (pJob->pDatatype) ) + NULL_STR_CONV_SIZE( (LPSTR) (pJob->pParameters) ) + NULL_STR_CONV_SIZE( (LPSTR) (pJob->pStatus) ) + WCSSIZE( QueueNameW ) + // pszQueue
NULL_STR_CONV_SIZE( (LPSTR) (pJob->pPrintProcessor) ) + NULL_STR_CONV_SIZE( (LPSTR) (pJob->pParameters) ) + NULL_STR_CONV_SIZE( (LPSTR) (pJob->pDriverName) ) + NULL_STR_CONV_SIZE( (LPSTR) (pJob->pPrinterName) );
default: NetpKdPrint(( PREFIX_DOSPRINT "GetPrjInfoSizeW: invalid level!\n" )); return 0;
} /*NOTREACHED*/ }
// Print job info string table (for level 1).
DBGSTATIC CONST DWORD PrjInfo1StringsW[]={ offsetof(PRJINFOW, pszParms), offsetof(PRJINFOW, pszStatus), offsetof(PRJINFOW, pszComment), ARRAY_END};
// Print job info string table (for level 2).
DBGSTATIC CONST DWORD PrjInfo2StringsW[]={ offsetof(PRJINFO2W, pszUserName), offsetof(PRJINFO2W, pszComment), offsetof(PRJINFO2W, pszDocument), (DWORD) -1};
// Print job info string table (for items which level 3 has on top of level 2).
DBGSTATIC CONST DWORD PrjInfo3StringsW[]={ offsetof(PRJINFO3W, pszNotifyName), offsetof(PRJINFO3W, pszDataType), offsetof(PRJINFO3W, pszParms), offsetof(PRJINFO3W, pszStatus), offsetof(PRJINFO3W, pszQProcName), offsetof(PRJINFO3W, pszQProcParms), offsetof(PRJINFO3W, pszDriverName), offsetof(PRJINFO3W, pszPrinterName), (DWORD) -1};
DBGSTATIC LPWSTR CopyJobToPrjInfoW( IN DWORD Level, IN LPJOB_INFO_2 pJob, IN LPCWSTR QueueNameW, OUT PBYTE pBuffer, IN OUT LPWSTR pEnd ) { LPSTR *pSourceStrings; NET_API_STATUS rc;
NetpAssert( pBuffer != NULL ); NetpAssert( pEnd != NULL ); NetpAssert( pJob != NULL );
switch (Level) {
case 0:
{ PWORD pJobIds = (PWORD) pBuffer; *pJobIds = (WORD)pJob->JobId; } break;
case 1: { LPSTR SourceStrings[sizeof(PrjInfo1StringsW)/sizeof(DWORD)]; PPRJINFOW pPrjInfo = (LPVOID) pBuffer;
pSourceStrings=SourceStrings; *pSourceStrings++ = (LPSTR) (pJob->pParameters); *pSourceStrings++ = (LPSTR) (pJob->pStatus); *pSourceStrings++ = (LPSTR) (pJob->pDocument); // fake pszComment
pEnd = PackAnsiStringsToW( SourceStrings, (LPBYTE) (LPVOID) pPrjInfo, PrjInfo1StringsW, pEnd);
pPrjInfo->uJobId = (WORD)pJob->JobId;
if (pJob->pUserName) (VOID) NetpNCopyStrToWStr( (LPWSTR) (pPrjInfo->szUserName), (LPSTR) (pJob->pUserName), LM20_UNLEN+1); else pPrjInfo->szUserName[0] = L'\0';
if (pJob->pNotifyName) (VOID) NetpNCopyStrToWStr( (LPWSTR) (pPrjInfo->szNotifyName), (LPSTR) (pJob->pNotifyName), LM20_CNLEN+1); else pPrjInfo->szNotifyName[0] = L'\0';
if (pJob->pDatatype) { (VOID) NetpNCopyStrToWStr( (LPWSTR) (pPrjInfo->szDataType), (LPSTR) (pJob->pDatatype), DTLEN+1); pPrjInfo->szDataType[DTLEN] = L'\0'; } else { pPrjInfo->szDataType[0] = L'\0'; }
pPrjInfo->uPosition = (WORD)pJob->Position;
pPrjInfo->fsStatus = PrjStatusFromJobStatus( pJob->Status );
rc = NetpSystemTimeToGmtTime( &pJob->Submitted, &pPrjInfo->ulSubmitted ); NetpAssert( rc == NO_ERROR );
pPrjInfo->ulSize = pJob->Size; } break;
case 2: /*FALLTHROUGH*/ case 3: { PPRJINFO2W pPrjInfo = (LPVOID) pBuffer; LPSTR SourceStrings[sizeof(PrjInfo2StringsW)/sizeof(DWORD)];
pSourceStrings=SourceStrings; *pSourceStrings++ = (LPSTR) (pJob->pUserName); *pSourceStrings++ = (LPSTR) (pJob->pDocument); // fake pszComment
*pSourceStrings++ = (LPSTR) (pJob->pDocument);
pEnd = PackAnsiStringsToW( SourceStrings, (LPBYTE) (LPVOID) pPrjInfo, PrjInfo2StringsW, pEnd);
pPrjInfo->uJobId = (WORD)pJob->JobId; pPrjInfo->uPriority = (WORD)pJob->Priority;
pPrjInfo->uPosition = (WORD)pJob->Position;
pPrjInfo->fsStatus = PrjStatusFromJobStatus( pJob->Status );
rc = NetpSystemTimeToGmtTime( &pJob->Submitted, &pPrjInfo->ulSubmitted ); NetpAssert( rc == NO_ERROR );
pPrjInfo->ulSize = pJob->Size; }
if (Level == 3) { PPRJINFO3W pPrjInfo = (LPVOID) pBuffer; LPSTR SourceStrings[sizeof(PrjInfo3StringsW)/sizeof(DWORD)];
//
// Copy queue name first, as it is already right char set.
//
NetpAssert( QueueNameW != NULL ); pEnd-=(wcslen(QueueNameW) + 1);
(VOID) wcscpy(pEnd, QueueNameW);
pPrjInfo->pszQueue = pEnd;
//
// Copy and convert other strings.
//
pSourceStrings=SourceStrings; *pSourceStrings++ = (LPSTR) (pJob->pNotifyName); *pSourceStrings++ = (LPSTR) (pJob->pDatatype); *pSourceStrings++ = (LPSTR) (pJob->pParameters); *pSourceStrings++ = (LPSTR) (pJob->pStatus); *pSourceStrings++ = (LPSTR) (pJob->pPrintProcessor); *pSourceStrings++ = (LPSTR) (pJob->pParameters); *pSourceStrings++ = (LPSTR) (pJob->pDriverName); *pSourceStrings++ = (LPSTR) (pJob->pPrinterName);
pEnd = PackAnsiStringsToW( SourceStrings, (LPBYTE) (LPVOID) pPrjInfo, PrjInfo3StringsW, pEnd);
pPrjInfo->pDriverData = NULL; }
break;
default: NetpKdPrint(( PREFIX_DOSPRINT "CopyJobToPrjInfoW: invalid level!\n" ));
}
return pEnd; }
DBGSTATIC DWORD GetPrqInfoSizeW( IN DWORD Level, IN LPCWSTR QueueNameW, IN LPPRINTER_INFO_2 pPrinter ) { NetpAssert( QueueNameW != NULL ); NetpAssert( (*QueueNameW) != L'\0' );
switch (Level) {
case 0:
return ( (LM20_QNLEN+1) * sizeof(WCHAR) );
case 1: /*FALLTHROUGH*/ case 2:
return sizeof(PRQINFOW) + NULL_STR_CONV_SIZE( pPrinter->pSepFile ) + NULL_STR_CONV_SIZE( pPrinter->pPrintProcessor ) + NULL_STR_CONV_SIZE( pPrinter->pPortName ) + NULL_STR_CONV_SIZE( pPrinter->pParameters ) + NULL_STR_CONV_SIZE( pPrinter->pComment );
case 3: /*FALLTHROUGH*/ case 4:
NetpAssert( QueueNameW != NULL );
return sizeof(PRQINFO3W) + WCSSIZE( QueueNameW ) + // pszName
NULL_STR_CONV_SIZE( pPrinter->pSepFile ) + NULL_STR_CONV_SIZE( pPrinter->pPrintProcessor ) + NULL_STR_CONV_SIZE( pPrinter->pParameters ) + NULL_STR_CONV_SIZE( pPrinter->pComment ) + NULL_STR_CONV_SIZE( pPrinter->pPortName ) + NULL_STR_CONV_SIZE( pPrinter->pDriverName );
case 5:
NetpAssert( QueueNameW != NULL );
return sizeof(LPWSTR) + WCSSIZE( QueueNameW ); // pszName
default: NetpKdPrint(( PREFIX_DOSPRINT "GetPrqInfoSizeW: invalid level!\n" ));
}
return 0; }
DBGSTATIC DWORD GetDrvInfoSizeW( IN DWORD Level, IN LPDRIVER_INFO_3A pDriverInfo3, IN LPCSTR pUNCSharePath, OUT LPDWORD pdwDependentFileCount ) { LPSTR psz; DWORD dwSize;
switch (Level) { case 52: dwSize = sizeof(PRQINFO52W) + NULL_STR_CONV_SIZE(pDriverInfo3->pName) + NULL_STR_CONV_SIZE(GetFileNameA(pDriverInfo3->pDriverPath)) + NULL_STR_CONV_SIZE(GetFileNameA(pDriverInfo3->pDataFile)) + NULL_STR_CONV_SIZE(GetFileNameA(pDriverInfo3->pConfigFile)) + NULL_STR_CONV_SIZE(GetFileNameA(pDriverInfo3->pHelpFile)) + NULL_STR_CONV_SIZE(pDriverInfo3->pDefaultDataType) + NULL_STR_CONV_SIZE(pDriverInfo3->pMonitorName) + NULL_STR_CONV_SIZE(pUNCSharePath);
*pdwDependentFileCount = 0; for ( psz = pDriverInfo3->pDependentFiles; psz && *psz ; psz += strlen(psz) + 1 ) {
dwSize += NULL_STR_CONV_SIZE(GetDependentFileNameA(psz)); (*pdwDependentFileCount)++; }
//
// For the '\0's
//
dwSize += (MAX_DEPENDENT_FILES-*pdwDependentFileCount)*sizeof(WCHAR); return dwSize;
default: NetpKdPrint(( PREFIX_DOSPRINT "GetDrvInfoSizeW: invalid level!\n" ));
} return 0;
}
DBGSTATIC DWORD PrqInfoFixedSizeW( IN DWORD Level // assumed valid
) { switch (Level) { case 0: return ( (LM20_QNLEN+1) * sizeof(WCHAR) ); case 1: /*FALLTHROUGH*/ case 2: return (sizeof(PRQINFOW)); case 3: /*FALLTHROUGH*/ case 4: return (sizeof(PRQINFO3W)); case 5: return (sizeof(LPWSTR)); default: NetpAssert( FALSE ); // Level should be valid!
return (0); } /*NOTREACHED*/ }
// String table for Q levels 1,2
DBGSTATIC CONST DWORD PrqInfo1StringsW[]={ offsetof(PRQINFOW, pszSepFile), offsetof(PRQINFOW, pszPrProc), offsetof(PRQINFOW, pszDestinations), offsetof(PRQINFOW, pszParms), offsetof(PRQINFOW, pszComment), ARRAY_END};
// String table for Q levels 3,4.
DBGSTATIC CONST DWORD PrqInfo3StringsW[]={ offsetof(PRQINFO3W, pszSepFile), offsetof(PRQINFO3W, pszPrProc), offsetof(PRQINFO3W, pszParms), offsetof(PRQINFO3W, pszComment), offsetof(PRQINFO3W, pszPrinters), offsetof(PRQINFO3W, pszDriverName), (DWORD) -1};
// Print driver info3 string table (for level 52)
DBGSTATIC CONST DWORD PrqInfo52StringsW[]={ offsetof(PRQINFO52W, pszModelName), offsetof(PRQINFO52W, pszDriverName), offsetof(PRQINFO52W, pszDataFileName), offsetof(PRQINFO52W, pszMonitorName), offsetof(PRQINFO52W, pszDriverPath), offsetof(PRQINFO52W, pszDefaultDataType), offsetof(PRQINFO52W, pszHelpFile), offsetof(PRQINFO52W, pszConfigFile), offsetof(PRQINFO52W, pszDependentNames[0]), offsetof(PRQINFO52W, pszDependentNames[1]), offsetof(PRQINFO52W, pszDependentNames[2]), offsetof(PRQINFO52W, pszDependentNames[3]), offsetof(PRQINFO52W, pszDependentNames[4]), offsetof(PRQINFO52W, pszDependentNames[5]), offsetof(PRQINFO52W, pszDependentNames[6]), offsetof(PRQINFO52W, pszDependentNames[7]), offsetof(PRQINFO52W, pszDependentNames[8]), offsetof(PRQINFO52W, pszDependentNames[9]), offsetof(PRQINFO52W, pszDependentNames[10]), offsetof(PRQINFO52W, pszDependentNames[11]), offsetof(PRQINFO52W, pszDependentNames[12]), offsetof(PRQINFO52W, pszDependentNames[13]), offsetof(PRQINFO52W, pszDependentNames[14]), offsetof(PRQINFO52W, pszDependentNames[15]), offsetof(PRQINFO52W, pszDependentNames[16]), offsetof(PRQINFO52W, pszDependentNames[17]), offsetof(PRQINFO52W, pszDependentNames[18]), offsetof(PRQINFO52W, pszDependentNames[19]), offsetof(PRQINFO52W, pszDependentNames[20]), offsetof(PRQINFO52W, pszDependentNames[21]), offsetof(PRQINFO52W, pszDependentNames[22]), offsetof(PRQINFO52W, pszDependentNames[23]), offsetof(PRQINFO52W, pszDependentNames[24]), offsetof(PRQINFO52W, pszDependentNames[25]), offsetof(PRQINFO52W, pszDependentNames[26]), offsetof(PRQINFO52W, pszDependentNames[27]), offsetof(PRQINFO52W, pszDependentNames[28]), offsetof(PRQINFO52W, pszDependentNames[29]), offsetof(PRQINFO52W, pszDependentNames[30]), offsetof(PRQINFO52W, pszDependentNames[31]), offsetof(PRQINFO52W, pszDependentNames[32]), offsetof(PRQINFO52W, pszDependentNames[33]), offsetof(PRQINFO52W, pszDependentNames[34]), offsetof(PRQINFO52W, pszDependentNames[35]), offsetof(PRQINFO52W, pszDependentNames[36]), offsetof(PRQINFO52W, pszDependentNames[37]), offsetof(PRQINFO52W, pszDependentNames[38]), offsetof(PRQINFO52W, pszDependentNames[39]), offsetof(PRQINFO52W, pszDependentNames[40]), offsetof(PRQINFO52W, pszDependentNames[41]), offsetof(PRQINFO52W, pszDependentNames[42]), offsetof(PRQINFO52W, pszDependentNames[43]), offsetof(PRQINFO52W, pszDependentNames[44]), offsetof(PRQINFO52W, pszDependentNames[45]), offsetof(PRQINFO52W, pszDependentNames[46]), offsetof(PRQINFO52W, pszDependentNames[47]), offsetof(PRQINFO52W, pszDependentNames[48]), offsetof(PRQINFO52W, pszDependentNames[49]), offsetof(PRQINFO52W, pszDependentNames[50]), offsetof(PRQINFO52W, pszDependentNames[51]), offsetof(PRQINFO52W, pszDependentNames[52]), offsetof(PRQINFO52W, pszDependentNames[53]), offsetof(PRQINFO52W, pszDependentNames[54]), offsetof(PRQINFO52W, pszDependentNames[55]), offsetof(PRQINFO52W, pszDependentNames[56]), offsetof(PRQINFO52W, pszDependentNames[57]), offsetof(PRQINFO52W, pszDependentNames[58]), offsetof(PRQINFO52W, pszDependentNames[59]), offsetof(PRQINFO52W, pszDependentNames[60]), offsetof(PRQINFO52W, pszDependentNames[61]), offsetof(PRQINFO52W, pszDependentNames[62]), offsetof(PRQINFO52W, pszDependentNames[63]), (DWORD) -1};
DBGSTATIC LPWSTR CopyPrinterToPrqInfoW( IN LPPRINTER_INFO_2 pPrinter, IN DWORD Level, OUT LPBYTE pBuffer, IN LPCWSTR QueueNameW, OUT LPWSTR pEnd ) { LPSTR *pSourceStrings;
NetpAssert( pEnd != NULL ); NetpAssert( QueueNameW != NULL ); NetpAssert( (*QueueNameW) != L'\0' );
switch (Level) {
case 0: (VOID) wcsncpy( (LPWSTR) (LPVOID) pBuffer, QueueNameW, LM20_QNLEN); break;
case 1: /*FALLTHROUGH*/ case 2:
{ LPSTR SourceStrings[sizeof(PrqInfo1StringsW)/sizeof(DWORD)]; PPRQINFOW pPrqInfo = (LPVOID) pBuffer;
pSourceStrings=SourceStrings; *pSourceStrings++ = pPrinter->pSepFile; *pSourceStrings++ = pPrinter->pPrintProcessor; *pSourceStrings++ = pPrinter->pPortName; *pSourceStrings++ = pPrinter->pParameters; *pSourceStrings++ = pPrinter->pComment;
pEnd = PackAnsiStringsToW( SourceStrings, (LPBYTE) (LPVOID) pPrqInfo, PrqInfo1StringsW, pEnd);
NetpAssert( QueueNameW != NULL );
(VOID) wcsncpy( pPrqInfo->szName, // dest
QueueNameW, // src
LM20_QNLEN); // char count
pPrqInfo->szName[LM20_QNLEN] = (USHORT)0;
pPrqInfo->uPriority = (WORD)pPrinter->Priority; pPrqInfo->uStartTime = (WORD)pPrinter->StartTime; pPrqInfo->uUntilTime = (WORD)pPrinter->UntilTime;
pPrqInfo->fsStatus = PrqStatusFromPrinterStatus( pPrinter->Status );
pPrqInfo->cJobs = (WORD)pPrinter->cJobs; }
break;
case 3: /*FALLTHROUGH*/ case 4: { LPSTR SourceStrings[sizeof(PrqInfo3StringsW)/sizeof(DWORD)]; PPRQINFO3W pPrqInfo = (LPVOID) pBuffer;
//
// Copy queue name first, as it is already right char set.
//
NetpAssert( QueueNameW != NULL ); pEnd-=(wcslen(QueueNameW) + 1);
(VOID) wcscpy(pEnd, QueueNameW);
pPrqInfo->pszName = pEnd;
//
// Copy and convert other strings.
//
pSourceStrings=SourceStrings; *pSourceStrings++ = pPrinter->pSepFile; *pSourceStrings++ = pPrinter->pPrintProcessor; *pSourceStrings++ = pPrinter->pParameters; *pSourceStrings++ = pPrinter->pComment; *pSourceStrings++ = pPrinter->pPortName; // pszPrinters
*pSourceStrings++ = pPrinter->pDriverName;
pEnd = PackAnsiStringsToW( SourceStrings, (LPBYTE) (LPVOID) pPrqInfo, PrqInfo3StringsW, pEnd);
pPrqInfo->uPriority = (WORD)pPrinter->Priority; pPrqInfo->uStartTime = (WORD)pPrinter->StartTime; pPrqInfo->uUntilTime = (WORD)pPrinter->UntilTime;
pPrqInfo->fsStatus = PrqStatusFromPrinterStatus( pPrinter->Status );
pPrqInfo->cJobs = (WORD)pPrinter->cJobs; pPrqInfo->pDriverData = NULL;
// Note: if level is 4, caller will add array of jobs after this.
break; }
case 5: NetpAssert( QueueNameW != NULL );
pEnd -= (wcslen( QueueNameW ) + 1); * (LPWSTR *) pBuffer = pEnd;
(VOID) wcscpy( pEnd, // dest
QueueNameW ); // src
break;
default: NetpKdPrint(( PREFIX_DOSPRINT "CopyPrinterToPrqInfoW: invalid level!\n" ));
}
return pEnd; }
DBGSTATIC LPWSTR CopyDriverToPrqInfoW( IN LPDRIVER_INFO_3A pDriver3, IN DWORD dwDependentFileCount, IN LPSTR pUNCSharePath, IN DWORD Level, OUT LPBYTE pBuffer, OUT LPWSTR pEnd ) { LPSTR *pSourceStrings; LPSTR psz;
NetpAssert( pEnd != NULL ); NetpAssert(MAX_DEPENDENT_FILES == 64);
switch (Level) {
case 52: { PPRQINFO52W pPrqInfo = (LPVOID) pBuffer; LPSTR SourceStrings[sizeof(PrqInfo52StringsW)/sizeof(DWORD)];
ZeroMemory((LPBYTE)SourceStrings, sizeof(SourceStrings));
pSourceStrings=SourceStrings; *pSourceStrings++ = pDriver3->pName; *pSourceStrings++ = GetFileNameA(pDriver3->pDriverPath); *pSourceStrings++ = GetFileNameA(pDriver3->pDataFile); *pSourceStrings++ = GetFileNameA(pDriver3->pMonitorName); *pSourceStrings++ = pUNCSharePath; *pSourceStrings++ = GetFileNameA(pDriver3->pDefaultDataType); *pSourceStrings++ = GetFileNameA(pDriver3->pHelpFile); *pSourceStrings++ = GetFileNameA(pDriver3->pConfigFile);
for ( psz = pDriver3->pDependentFiles ; psz && *psz ; psz += strlen(psz) + 1 ) {
*pSourceStrings++ = GetDependentFileNameA(psz); }
pEnd = PackAnsiStringsToW( SourceStrings, (LPBYTE) (LPVOID)pPrqInfo, PrqInfo52StringsW, pEnd);
pPrqInfo->uVersion = (WORD)pDriver3->cVersion; pPrqInfo->cDependentNames = (WORD)dwDependentFileCount; }
break;
default: NetpKdPrint(( PREFIX_DOSPRINT "CopyPrinterToPrqInfoW: invalid level!\n" ));
}
return pEnd; }
DBGSTATIC NET_API_STATUS ComputeSpaceNeededForJobs( IN LPCWSTR QueueNameW, IN DWORD QLevel, IN HANDLE PrinterHandle, OUT LPDWORD pcbNeeded ) { NET_API_STATUS ApiStatus; DWORD cJobs; DWORD cbJobs; DWORD cbNeeded = 0; DWORD JobLevel; LPJOB_INFO_2 pJob = NULL; LPJOB_INFO_2 pJobs = NULL;
NetpAssert( (QLevel==2) || (QLevel==4) ); NetpAssert( QueueNameW != NULL );
if (QLevel==2) { JobLevel = 1; } else { JobLevel = 2; }
if (!MyEnumJobs(PrinterHandle, 0, (DWORD) -1, 2, NULL, 0, &cbJobs, &cJobs)) {
ApiStatus = (NET_API_STATUS) GetLastError(); if (ApiStatus == ERROR_INSUFFICIENT_BUFFER) {
pJobs = (LPVOID) GlobalAlloc(GMEM_FIXED, cbJobs); if (pJobs == NULL) {
ApiStatus = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; }
} else { NetpKdPrint(( PREFIX_DOSPRINT "ComputeSpaceNeededForJobs: got error " FORMAT_API_STATUS " from MyEnumJobs(first).\n", ApiStatus )); goto Cleanup; } }
if (!MyEnumJobs(PrinterHandle, 0, (DWORD) -1, 2, (LPBYTE)pJobs, cbJobs, &cbJobs, &cJobs)) {
ApiStatus = (NET_API_STATUS) GetLastError(); NetpAssert( ApiStatus != ERROR_INSUFFICIENT_BUFFER ); NetpKdPrint(( PREFIX_DOSPRINT "ComputeSpaceNeededForJobs: got error " FORMAT_API_STATUS " from MyEnumJobs(second)\n", ApiStatus )); goto Cleanup; }
if (cJobs == 0) { cbNeeded = 0; ApiStatus = NO_ERROR; goto Cleanup; } if (pJobs == NULL) { NetpKdPrint(( PREFIX_DOSPRINT "ComputeSpaceNeededForJobs: never allocated array!\n" )); ApiStatus = NERR_InternalError; goto Cleanup; }
pJob=pJobs;
while (cJobs--) { cbNeeded+=GetPrjInfoSizeW(JobLevel, pJob++, QueueNameW); }
*pcbNeeded=(WORD)cbNeeded; // final byte count for this queue's jobs.
ApiStatus = NO_ERROR;
Cleanup: if (pJobs != NULL) { (VOID) GlobalFree(pJobs); }
*pcbNeeded = cbNeeded; // final byte count for this queue's jobs.
return (ApiStatus);
} // ComputeSpaceNeededForJobs
DBGSTATIC NET_API_STATUS AppendJobsToPrqW( IN LPCWSTR QueueNameW, IN DWORD QLevel, IN HANDLE PrinterHandle, OUT LPBYTE pbBuf, IN DWORD cbBuf, IN LPVOID pEnd, OUT LPVOID * pNewEnd, OUT LPDWORD pcbNeeded, OUT LPDWORD pcReturned, IN BOOL AllowPartialData ) { DWORD cJobs; DWORD cbJobs; DWORD cbNeeded = 0; DWORD cbPrj; DWORD JobLevel; DWORD rc; DWORD JobSize; DWORD BytesLeft; DWORD JobsStored; LPJOB_INFO_2 pJob = NULL; LPJOB_INFO_2 pJobs = NULL;
NetpAssert( (QLevel==2) || (QLevel==4) ); NetpAssert( QueueNameW != NULL );
if (QLevel==2) { cbPrj = sizeof(PRJINFOW); JobLevel = 1; } else { cbPrj = sizeof(PRJINFO2W); JobLevel = 2; }
if (!MyEnumJobs(PrinterHandle, 0, (DWORD) -1, 2, NULL, 0, &cbJobs, pcReturned)) {
rc = GetLastError(); if (rc == ERROR_INSUFFICIENT_BUFFER) {
pJobs = (LPVOID) GlobalAlloc(GMEM_FIXED, cbJobs); if (pJobs == NULL) {
rc = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; }
} else { NetpKdPrint(( PREFIX_DOSPRINT "AppendJobsToPrqW: got error " FORMAT_API_STATUS " from MyEnumJobs(first)\n", rc )); goto Cleanup; } }
if (!MyEnumJobs(PrinterHandle, 0, (DWORD) -1, 2, (LPBYTE)pJobs, cbJobs, &cbJobs, pcReturned)) {
rc = GetLastError(); NetpAssert( rc != ERROR_INSUFFICIENT_BUFFER ); NetpKdPrint(( PREFIX_DOSPRINT "AppendJobsToPrqW: got error " FORMAT_API_STATUS " from MyEnumJobs(second)\n", rc )); goto Cleanup; }
if (*pcReturned == 0) { cbNeeded = 0; rc = NO_ERROR; goto Cleanup; } if (pJobs == NULL) { NetpKdPrint(( PREFIX_DOSPRINT "AppendJobsToPrqW: never allocated array!\n" )); rc = NERR_InternalError; goto Cleanup; }
cJobs = *pcReturned; pJob=pJobs;
while (cJobs--) cbNeeded+=GetPrjInfoSizeW(JobLevel, pJob++, QueueNameW);
*pcbNeeded = cbNeeded; // final byte count for this queue's jobs.
if (cbNeeded <= cbBuf) {
cJobs = *pcReturned; pJob=pJobs; while (cJobs--) { pEnd = CopyJobToPrjInfoW(JobLevel, pJob++, QueueNameW, pbBuf, pEnd); pbBuf += cbPrj; // Note: Wasn't DWORD aligned
} rc = NO_ERROR;
} else {
//
// See if the user wants to receive as much data as we can fit.
//
if( AllowPartialData == TRUE ) {
cJobs = *pcReturned; pJob = pJobs; JobsStored = 0; BytesLeft = cbBuf;
while( cJobs-- ) {
JobSize = GetPrjInfoSizeW( JobLevel, pJob, QueueNameW );
if( JobSize <= BytesLeft ) {
//
// This job will fit. Add it in.
//
pEnd = CopyJobToPrjInfoW( JobLevel, pJob++, QueueNameW, pbBuf, pEnd );
pbBuf += cbPrj; // Note: Wasn't DWORD aligned
BytesLeft -= JobSize; JobsStored++;
} else {
//
// The buffer is full.
//
break; } }
if( JobsStored != 0 ) {
//
// Return what we were able to store.
//
*pcReturned = JobsStored; rc = NO_ERROR;
} else {
rc = NERR_BufTooSmall; }
} else {
rc = NERR_BufTooSmall; } }
Cleanup: if (pJobs != NULL) { (VOID) GlobalFree(pJobs); }
*pcbNeeded = cbNeeded; // final byte count for this queue's jobs.
if (pNewEnd != NULL) { *pNewEnd = pEnd; }
return (rc);
}
SPLERR SPLENTRY DosPrintQGetInfoW( LPWSTR pszServer, LPWSTR pszQueueName, WORD uLevel, PBYTE pbBuf, WORD cbBuf, PUSHORT pcbNeeded ) { DWORD cJobsReturned; LPWSTR pEnd; DWORD rc; HANDLE hPrinter = INVALID_HANDLE_VALUE; LPPRINTER_INFO_2 pPrinter = NULL; LPDRIVER_INFO_3A pDriver = NULL; CHAR szDriverDir[MAX_PATH]; DWORD cbNeeded = 0, dwDependentFileCount; DWORD cbNeededForJobs;
if (pszServer && *pszServer) { rc = RxPrintQGetInfo(pszServer, pszQueueName, uLevel, pbBuf, cbBuf, &cbNeeded); if (cbNeeded > MAX_WORD) { rc = MY_PROTOCOL_LIMIT_ERROR; goto Cleanup; } *pcbNeeded = (USHORT)cbNeeded; goto Cleanup; }
*pcbNeeded = 0; // in case an error occurs.
if ( !NetpIsPrintQLevelValid( uLevel, FALSE ) ) { rc = ERROR_INVALID_LEVEL; goto Cleanup; } if ( (pszQueueName==NULL) || ((*pszQueueName)==L'\0') ) { rc = ERROR_INVALID_PARAMETER; goto Cleanup; }
if ( !MyOpenPrinterW( pszQueueName, &hPrinter, NULL) ) {
rc = GetLastError(); if ( rc == ERROR_INVALID_PRINTER_NAME ) rc = NERR_QNotFound; goto Cleanup;
}
//
// Level 52 is meant for point and print from a Windows 95 clients
// can't use with other clients since no environment info is passed
//
if ( uLevel == 52 ) {
cbNeeded = sizeof(szDriverDir)-2; szDriverDir[0] = szDriverDir[1] = '\\'; if ( !GetComputerNameA(szDriverDir+2, &cbNeeded) ) {
rc = GetLastError(); goto Cleanup; }
if ( strlen(szDriverDir) + strlen(WIN95_DRIVER_SHARE) + 1 > sizeof(szDriverDir) ) {
rc = ERROR_NOT_ENOUGH_MEMORY; NetpAssert( rc != NO_ERROR ); // Always break
goto Cleanup; }
strcat(szDriverDir, WIN95_DRIVER_SHARE);
(VOID)MyGetPrinterDriver(hPrinter, WIN95_ENVIRONMENT, 3, NULL, 0, &cbNeeded); rc = GetLastError(); if ( rc != ERROR_INSUFFICIENT_BUFFER ) goto Cleanup;
pDriver = (LPVOID) GlobalAlloc(GMEM_FIXED, cbNeeded); if ( !pDriver ) {
rc = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; }
if ( !MyGetPrinterDriver(hPrinter, WIN95_ENVIRONMENT, 3, (LPVOID)pDriver, cbNeeded, &cbNeeded) ) {
rc = GetLastError(); goto Cleanup; }
cbNeeded=GetDrvInfoSizeW(uLevel, pDriver, szDriverDir, &dwDependentFileCount); if ( dwDependentFileCount > MAX_DEPENDENT_FILES ) {
rc = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } } else {
if (!MyGetPrinter(hPrinter, 2, NULL, 0, &cbNeeded)) {
rc = GetLastError(); if (rc == ERROR_INSUFFICIENT_BUFFER) {
pPrinter = (LPVOID) GlobalAlloc(GMEM_FIXED, cbNeeded); if (pPrinter == NULL) {
rc = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } } else { goto Cleanup; }
}
if (!MyGetPrinter(hPrinter, 2, (LPBYTE)pPrinter, cbNeeded, &cbNeeded)) {
rc = GetLastError(); goto Cleanup; }
// How much for just the queue structure and its strings?
cbNeeded=GetPrqInfoSizeW(uLevel, pszQueueName, pPrinter); }
if (cbNeeded > MAX_WORD) { rc = MY_PROTOCOL_LIMIT_ERROR; goto Cleanup; } *pcbNeeded = (WORD)cbNeeded; // Tell caller the size (so far).
//
// Build the queue structure itself.
//
if (cbNeeded <= (DWORD) cbBuf) {
if ( uLevel == 52 ) {
ZeroMemory(pbBuf, cbNeeded); pEnd = CopyDriverToPrqInfoW(pDriver, dwDependentFileCount, szDriverDir, uLevel, pbBuf, (LPWSTR) (pbBuf+cbBuf) ); } else {
pEnd = CopyPrinterToPrqInfoW(pPrinter, uLevel, pbBuf, pszQueueName, (LPWSTR) (pbBuf+cbBuf) ); }
} else {
//
// Too small. Well, need to find total size before we can tell caller.
//
if ( (uLevel==2) || (uLevel==4) ) { rc = ComputeSpaceNeededForJobs( pszQueueName, uLevel, // Q info level
hPrinter, & cbNeededForJobs ); if (rc != NO_ERROR) { goto Cleanup; } cbNeeded += cbNeededForJobs; } if (cbNeeded > MAX_WORD) { rc = MY_PROTOCOL_LIMIT_ERROR; goto Cleanup; } rc = NERR_BufTooSmall; goto Cleanup; }
//
// Append jobs if necessary.
//
if ( (uLevel==2) || (uLevel==4) ) { DWORD cbPrq = PrqInfoFixedSizeW( uLevel );
rc = AppendJobsToPrqW( pszQueueName, uLevel, // Q info level
hPrinter, pbBuf + cbPrq, // put first job here
cbBuf - cbNeeded, // bytes avail for jobs
pEnd, // str area
NULL, // don't need new pEnd
& cbNeededForJobs, & cJobsReturned, cbBuf == MAX_WORD ? TRUE : FALSE ); // If the buffer is at its max, get what we can.
if( cbNeeded + cbNeededForJobs > MAX_WORD ) { *pcbNeeded = MAX_WORD; } else { *pcbNeeded = (USHORT) (cbNeeded + cbNeededForJobs); }
//
// Update job count in queue structure, as it may be out of date.
//
NetpSetJobCountForQueue( uLevel, // queue info level
pbBuf, // queue structure to update
TRUE, // yes, UNICODE strings
cJobsReturned ); // actual job count
if (rc != NO_ERROR) { goto Cleanup; }
}
rc = NO_ERROR;
Cleanup:
if (hPrinter != INVALID_HANDLE_VALUE) { (VOID) MyClosePrinter( hPrinter ); }
if (pPrinter) { (VOID) GlobalFree( pPrinter ); }
if (pDriver) {
(VOID) GlobalFree( pDriver ); }
return rc; }
SPLERR SPLENTRY DosPrintJobGetInfoW( LPWSTR pszServer, BOOL bRemote, WORD uJobId, WORD uLevel, PBYTE pbBuf, WORD cbBuf, PUSHORT pcbNeeded ) { DWORD cb; HANDLE hPrinter = INVALID_HANDLE_VALUE; LPSTR QueueNameA = NULL; LPWSTR QueueNameW = NULL; LPJOB_INFO_2 pJob = NULL; LPWSTR pEnd; DWORD rc; DWORD cbNeeded = 0;
if (bRemote) { rc = RxPrintJobGetInfo(pszServer, uJobId, uLevel, pbBuf, cbBuf, &cbNeeded); *pcbNeeded = (USHORT)cbNeeded; return rc; }
*pcbNeeded = 0; // in case an error occurs.
if ( !NetpIsPrintJobLevelValid( uLevel, FALSE ) ) { rc = ERROR_INVALID_LEVEL; goto Cleanup; }
//
// The 3.51 spooler has been changed to accept Get/SetJobs on the
// local server handle. We will still do security checks against
// the Job's security descriptor. This also avoids the costly
// FindLocalJob() call.
//
if (!MyOpenPrinterW( pszServer, &hPrinter, NULL)) { rc = GetLastError(); NetpKdPrint((PREFIX_DOSPRINT "DosPrintJobSetInfoW: " "MyOpenPrinter( NULL, &hPrinter, NULL ) failed" FORMAT_API_STATUS "\n", rc ));
hPrinter = INVALID_HANDLE_VALUE; goto Cleanup; } NetpAssert( hPrinter != INVALID_HANDLE_VALUE );
//
// Note: this should really call MyGetJobW, since it looks
// like the code later thunks from ansi back to unicode.
//
if (!MyGetJobA(hPrinter, uJobId, 2, NULL, 0, &cb)) {
rc=GetLastError();
NetpAssert( rc != NO_ERROR ); if (rc == ERROR_INSUFFICIENT_BUFFER) {
pJob = (LPVOID) GlobalAlloc(GMEM_FIXED, cb); if (pJob == NULL) { rc = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; }
if ( !MyGetJobA(hPrinter, uJobId, 2, (LPBYTE)pJob, cb, &cb) ) { rc=GetLastError(); NetpAssert( rc != NO_ERROR ); goto Cleanup; }
} else { if (rc == ERROR_INVALID_PARAMETER) { rc = NERR_JobNotFound; } goto Cleanup; // Job deleted? Not enough mem?
}
} if (pJob == NULL) { NetpKdPrint((PREFIX_DOSPRINT "DosPrintJobGetInfoW: " "*** STILL INVALID RESULT FROM MyGetJob, pJob IS NULL!\n" )); rc = NERR_InternalError; goto Cleanup; }
NetpAssert( pJob != NULL ); NetpAssert( pJob->pPrinterName != NULL ); QueueNameA = FindQueueNameInPrinterNameA( (pJob->pPrinterName) ); NetpAssert( QueueNameA != NULL ); QueueNameW = NetpAllocWStrFromStr( QueueNameA ); if (QueueNameW == NULL) { rc = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } NetpAssert( QueueNameW != NULL );
cb=GetPrjInfoSizeW(uLevel, pJob, QueueNameW);
*pcbNeeded=(WORD)cb;
if (cb > (DWORD) cbBuf) { rc = NERR_BufTooSmall; goto Cleanup; }
pEnd = (LPVOID) (pbBuf+cbBuf);
(VOID) CopyJobToPrjInfoW(uLevel, pJob, QueueNameW, pbBuf, pEnd);
rc = NO_ERROR;
Cleanup:
if (hPrinter != INVALID_HANDLE_VALUE) { (VOID) MyClosePrinter( hPrinter ); } if (pJob != NULL) { (VOID) GlobalFree( pJob ); } if (QueueNameW != NULL) { (VOID) NetApiBufferFree( QueueNameW ); }
return (rc);
}
SPLERR SPLENTRY DosPrintJobDelW( LPWSTR pszServer, BOOL bRemote, WORD uJobId ) {
if (bRemote) return RxPrintJobDel(pszServer, uJobId);
return (CommandALocalJobA(NULL, pszServer, NULL, uJobId, 0, NULL, JOB_CONTROL_CANCEL ) ); }
SPLERR SPLENTRY DosPrintJobContinueW( LPWSTR pszServer, BOOL bRemote, WORD uJobId ) {
if (bRemote) return RxPrintJobContinue(pszServer, uJobId);
return (CommandALocalJobA(NULL, pszServer, NULL, uJobId, 0, NULL, JOB_CONTROL_RESUME ) ); }
SPLERR SPLENTRY DosPrintJobPauseW( LPWSTR pszServer, BOOL bRemote, WORD uJobId ) {
if (bRemote) return RxPrintJobPause(pszServer, uJobId);
return (CommandALocalJobA(NULL, pszServer, NULL, uJobId, 0, NULL, JOB_CONTROL_PAUSE ) ); }
SPLERR SPLENTRY DosPrintJobEnumW( LPWSTR pszServer, LPWSTR pszQueueName, WORD uLevel, PBYTE pbBuf, WORD cbBuf, PWORD pcReturned, PWORD pcTotal ) { DWORD cbPrinter; LPJOB_INFO_2 pJob = NULL; LPJOB_INFO_2 pJobs; DWORD cb, cbJobs, cReturned, cJobs; HANDLE hPrinter = INVALID_HANDLE_VALUE; LPWSTR pEnd; DWORD rc; DWORD cTotal;
if (pszServer && *pszServer) { rc = RxPrintJobEnum(pszServer, pszQueueName, uLevel, pbBuf, cbBuf, &cReturned, &cTotal); *pcReturned = (WORD)cReturned; *pcTotal = (WORD)cTotal; goto Cleanup; }
*pcReturned=0; *pcTotal = 0;
if ( !NetpIsPrintJobLevelValid( uLevel, FALSE ) ) { rc = ERROR_INVALID_LEVEL; goto Cleanup; }
if (!MyOpenPrinterW( pszQueueName, &hPrinter, NULL)) { rc = GetLastError(); goto Cleanup; } NetpAssert( hPrinter != INVALID_HANDLE_VALUE );
if (!MyEnumJobs(hPrinter, 0, (DWORD) -1, 2, NULL, 0, &cbJobs, &cReturned)) {
rc = GetLastError(); NetpAssert( rc != NO_ERROR ); if (rc == ERROR_INSUFFICIENT_BUFFER) {
if (pJob = (LPVOID) GlobalAlloc(GMEM_FIXED, cbJobs)) {
if (!MyEnumJobs(hPrinter, 0, (DWORD) -1, 2, (LPBYTE)pJob, cbJobs, &cbJobs, &cReturned)) {
rc = GetLastError(); NetpAssert( rc != NO_ERROR ); NetpAssert( rc != ERROR_INSUFFICIENT_BUFFER ); NetpKdPrint(( PREFIX_DOSPRINT "DosPrintJobEnumW: got error " FORMAT_API_STATUS " from MyEnumJobs(first)\n", rc )); goto Cleanup; } } else {
rc = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } } else { NetpKdPrint(( PREFIX_DOSPRINT "DosPrintJobEnumW: got error " FORMAT_API_STATUS " from MyEnumJobs(first)\n", rc )); goto Cleanup; } }
if (cReturned == 0) { *pcReturned = 0; *pcTotal = 0; rc = NO_ERROR; goto Cleanup; } if (pJob == NULL) { NetpKdPrint(( PREFIX_DOSPRINT "DosPrintJobEnumW: never allocated array!\n" )); rc = NERR_InternalError; goto Cleanup; }
*pcTotal = (WORD)cReturned;
cb=0; cJobs=cReturned; pJobs=pJob; while (cJobs--) cb+=GetPrjInfoSizeW(uLevel, pJobs++, pszQueueName);
if (cb <= (DWORD) cbBuf) {
DWORD cbFixedPortion = PrjInfoFixedSizeW( uLevel ); NetpAssert( cbFixedPortion != 0 ); // level already checked!
pEnd = (LPWSTR)(pbBuf+cbBuf);
cJobs=cReturned; pJobs=pJob;
while (cJobs--) {
pEnd = CopyJobToPrjInfoW(uLevel, pJobs++, pszQueueName, pbBuf, pEnd); pbBuf += cbFixedPortion; }
*pcReturned = (WORD)cReturned; rc = NO_ERROR;
} else {
rc = NERR_BufTooSmall; goto Cleanup; }
Cleanup:
if (hPrinter != INVALID_HANDLE_VALUE) { (VOID) MyClosePrinter( hPrinter ); } if (pJob != NULL) { (VOID) GlobalFree( pJob ); }
return rc; }
SPLERR SPLENTRY DosPrintDestEnumW( IN LPWSTR pszServer OPTIONAL, IN WORD uLevel, OUT PBYTE pbBuf, IN WORD cbBuf, OUT PUSHORT pcReturned, OUT PUSHORT pcTotal ) { DWORD cReturned=0, cTotal=0, rc;
if (pszServer && *pszServer) { rc = RxPrintDestEnum(pszServer, uLevel, pbBuf, cbBuf, &cReturned, &cTotal); *pcReturned = (USHORT)cReturned; *pcTotal = (USHORT)cTotal; return rc; }
// Stub for local dest enum - no entries, dest not found.
*pcReturned = 0; *pcTotal = 0; return ERROR_NOT_SUPPORTED; }
SPLERR SPLENTRY DosPrintDestControlW( LPWSTR pszServer, LPWSTR pszDevName, WORD uControl ) { if (pszServer && *pszServer) return RxPrintDestControl(pszServer, pszDevName, uControl);
return ERROR_NOT_SUPPORTED; }
SPLERR SPLENTRY DosPrintDestGetInfoW( LPWSTR pszServer, LPWSTR pszName, WORD uLevel, PBYTE pbBuf, WORD cbBuf, PUSHORT pcbNeeded ) { DWORD cbNeeded = 0, rc;
if (pszServer && *pszServer) { rc = RxPrintDestGetInfo(pszServer, pszName, uLevel, pbBuf, cbBuf, &cbNeeded); *pcbNeeded = (USHORT)cbNeeded; return rc; }
return ERROR_NOT_SUPPORTED; }
SPLERR SPLENTRY DosPrintDestAddW( LPWSTR pszServer, WORD uLevel, PBYTE pbBuf, WORD cbBuf ) { if (pszServer && *pszServer) return RxPrintDestAdd(pszServer, uLevel, pbBuf, cbBuf);
return ERROR_NOT_SUPPORTED; }
SPLERR SPLENTRY DosPrintDestSetInfoW( LPWSTR pszServer, LPWSTR pszName, WORD uLevel, PBYTE pbBuf, WORD cbBuf, WORD uParmNum ) { if (pszServer && *pszServer) return RxPrintDestSetInfo(pszServer, pszName, uLevel, pbBuf, cbBuf, uParmNum);
return ERROR_NOT_SUPPORTED; }
SPLERR SPLENTRY DosPrintDestDelW( LPWSTR pszServer, LPWSTR pszPrinterName ) { if (pszServer && *pszServer) return RxPrintDestDel(pszServer, pszPrinterName);
return ERROR_NOT_SUPPORTED; }
SPLERR SPLENTRY DosPrintQEnumW( LPWSTR pszServer, WORD uLevel, PBYTE pbBuf, WORD cbBuf, PUSHORT pcReturned, PUSHORT pcTotal ) { DWORD cJobsReturned; DWORD Total, cbNeeded, rc; HANDLE hPrinter = INVALID_HANDLE_VALUE; DWORD i; DWORD JobFixedEntrySize = 0; DWORD JobLevel; LPSHARE_INFO_1 pShareInfo = NULL; DWORD cbPrinter; LPPRINTER_INFO_2 pPrinter = NULL; BOOL BufferTooSmall=FALSE; DWORD cReturned = 0; DWORD cTotal = 0; #if DBG
LPVOID OutputBufferStart = pbBuf; #endif
LPVOID pEnd; DWORD SharesRead;
if ( !NetpIsPrintQLevelValid( uLevel, FALSE ) ) { rc = ERROR_INVALID_LEVEL; goto Cleanup; }
if (pszServer && *pszServer) { rc = RxPrintQEnum(pszServer, uLevel, pbBuf, cbBuf, &cReturned, &cTotal); *pcReturned = (USHORT)cReturned; *pcTotal = (USHORT)cTotal; goto Cleanup; }
*pcReturned = 0; *pcTotal = 0;
rc=NetShareEnum( NULL, 1, (LPBYTE *)(LPVOID)&pShareInfo, MAX_PREFERRED_LENGTH, &SharesRead, &Total, NULL); if (rc != NO_ERROR) {
NetpKdPrint((PREFIX_DOSPRINT "DosPrintQEnumW: NetShareEnum returned " FORMAT_API_STATUS "\n", rc)); goto Cleanup; }
pEnd = (pbBuf + cbBuf);
if (uLevel==2) { JobLevel = 1; JobFixedEntrySize = PrjInfoFixedSizeW( JobLevel ); } else if (uLevel == 4) { JobLevel = 2; JobFixedEntrySize = PrjInfoFixedSizeW( JobLevel ); }
for (i=0; i<SharesRead; i++) {
if (pShareInfo[i].shi1_type != STYPE_PRINTQ) { continue; }
NetpAssert( pShareInfo[i].shi1_netname != NULL ); NetpAssert( (*pShareInfo[i].shi1_netname) != L'\0' ); if (STRLEN( pShareInfo[i].shi1_netname ) > LM20_QNLEN) { continue; }
if ( !MyOpenPrinterW(pShareInfo[i].shi1_netname, &hPrinter, NULL)) { rc = (NET_API_STATUS) GetLastError(); NetpKdPrint(( PREFIX_DOSPRINT "DosPrintQEnumW: MyOpenPrinter failed, status " FORMAT_API_STATUS ".\n", rc )); NetpAssert( rc != NO_ERROR ); goto Cleanup; } NetpAssert( hPrinter != INVALID_HANDLE_VALUE );
if (!MyGetPrinter(hPrinter, 2, NULL, 0, &cbPrinter)) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { rc = (NET_API_STATUS) GetLastError(); NetpKdPrint(( PREFIX_DOSPRINT "DosPrintQEnumW: MyGetPrinter(first) failed, status " FORMAT_API_STATUS ".\n", rc )); NetpAssert( rc != NO_ERROR ); goto Cleanup; } } NetpAssert( cbPrinter != 0 );
pPrinter = (LPVOID) GlobalAlloc(GMEM_FIXED, cbPrinter); if (pPrinter == NULL) { rc = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; }
if ( !MyGetPrinter(hPrinter, 2, (LPBYTE)pPrinter, cbPrinter, &cbPrinter)) { rc = (NET_API_STATUS) GetLastError(); NetpKdPrint(( PREFIX_DOSPRINT "DosPrintQEnumW: MyGetPrinter(second) failed, status " FORMAT_API_STATUS ".\n", rc )); NetpAssert( rc != NO_ERROR ); goto Cleanup; }
cbNeeded=GetPrqInfoSizeW(uLevel, pShareInfo[i].shi1_netname, // Q nam
pPrinter); NetpAssert( cbNeeded > 0 ); NetpAssert( cbNeeded <= (DWORD) MAX_WORD );
if ( (!BufferTooSmall) && ((DWORD)cbBuf >= cbNeeded) ) {
LPVOID pbQueue = pbBuf; //
// Handle queue structure itself.
//
pEnd = CopyPrinterToPrqInfoW(pPrinter, uLevel, pbBuf, pShareInfo[i].shi1_netname, pEnd);
pbBuf += PrqInfoFixedSizeW( uLevel ); cbBuf -= (WORD) cbNeeded;
//
// Append job structures if needed.
//
if ( (uLevel==2) || (uLevel==4) ) { // info level includes jobs
NetpAssert( pbBuf < (LPBYTE) pEnd ); rc = AppendJobsToPrqW( pShareInfo[i].shi1_netname, uLevel, // Q info level
hPrinter, pbBuf, // first job here
cbBuf, // bytes avail
pEnd, // str area
& pEnd, // set new end ptr
& cbNeeded, & cJobsReturned, FALSE ); // Only accept all the data.
if (rc == NERR_BufTooSmall) { BufferTooSmall = TRUE; // continue, as we need pcTotal...
} else if (rc != NO_ERROR) { goto Cleanup; } else { // Must be NO_ERROR.
NetpAssert( cbNeeded <= (DWORD) MAX_WORD ); NetpAssert( pbBuf < (LPBYTE) pEnd ); NetpAssert( JobFixedEntrySize !=0 );
pbBuf += (JobFixedEntrySize * cJobsReturned); cbBuf -= (WORD) cbNeeded; (*pcReturned)++;
// Correct possible out of date
// job count in queue structure.
NetpSetJobCountForQueue( uLevel, pbQueue, TRUE, // yes, UNICODE strs
cJobsReturned ); }
} else { // info level does not include jobs
(*pcReturned)++; }
} else { // not enough mem for Q struct
BufferTooSmall = TRUE; // Continue, as we want to compute pcTotal for subsequent queues.
}
(*pcTotal)++;
NetpAssert( pPrinter != NULL ); (VOID) GlobalFree(pPrinter); pPrinter = NULL;
NetpAssert( hPrinter != INVALID_HANDLE_VALUE ); (VOID) MyClosePrinter(hPrinter); hPrinter = INVALID_HANDLE_VALUE;
} // for each share
Cleanup:
if (hPrinter != INVALID_HANDLE_VALUE) { (VOID) MyClosePrinter( hPrinter ); } if (pPrinter != NULL) { (VOID) GlobalFree( pPrinter ); } if (pShareInfo != NULL) { (VOID) NetApiBufferFree(pShareInfo); }
if (BufferTooSmall) { rc = NERR_BufTooSmall; }
return (rc); }
SPLERR SPLENTRY DosPrintQSetInfoW( LPWSTR pszServer, LPWSTR pszQueueName, WORD uLevel, PBYTE pbBuf, WORD cbBuf, WORD uParmNum ) { if (pszServer && *pszServer) return RxPrintQSetInfo(pszServer, pszQueueName, uLevel, pbBuf, cbBuf, uParmNum);
return ERROR_NOT_SUPPORTED; }
SPLERR SPLENTRY DosPrintQPauseW( LPWSTR pszServer, LPWSTR pszQueueName ) { if (pszServer && *pszServer) return RxPrintQPause(pszServer, pszQueueName);
return (CommandALocalPrinterW( pszQueueName, PRINTER_CONTROL_PAUSE ) ); }
SPLERR SPLENTRY DosPrintQContinueW( LPWSTR pszServer, LPWSTR pszQueueName ) { if (pszServer && *pszServer) return RxPrintQContinue(pszServer, pszQueueName);
return (CommandALocalPrinterW( pszQueueName, PRINTER_CONTROL_RESUME ) ); }
SPLERR SPLENTRY DosPrintQPurgeW( LPWSTR pszServer, LPWSTR pszQueueName ) { if (pszServer && *pszServer) return RxPrintQPurge(pszServer, pszQueueName);
return (CommandALocalPrinterW( pszQueueName, PRINTER_CONTROL_PURGE ) ); }
SPLERR SPLENTRY DosPrintQAddW( LPWSTR pszServer, WORD uLevel, PBYTE pbBuf, WORD cbBuf ) { if (pszServer && *pszServer) return RxPrintQAdd(pszServer, uLevel, pbBuf, cbBuf);
return ERROR_NOT_SUPPORTED; }
SPLERR SPLENTRY DosPrintQDelW( LPWSTR pszServer, LPWSTR pszQueueName ) { if (pszServer && *pszServer) return RxPrintQDel(pszServer, pszQueueName);
return ERROR_NOT_SUPPORTED; }
SPLERR SPLENTRY DosPrintJobSetInfoW( LPWSTR pszServer, BOOL bRemote, WORD uJobId, WORD uLevel, PBYTE pbBuf, WORD cbBuf, WORD uParmNum ) { if (bRemote) return RxPrintJobSetInfo(pszServer, uJobId, uLevel, pbBuf, cbBuf, uParmNum);
//
// Hack for Chicago: support Level 1, ParmNum 0xb so that jobs
// are set with the comment field.
//
if (uLevel == 1 && uParmNum == PRJ_COMMENT_PARMNUM) {
HANDLE hPrinter = INVALID_HANDLE_VALUE; CHAR szDocument[MAX_PATH]; PJOB_INFO_1 pJob = NULL; DWORD cbJob; SPLERR rc;
//
// Allocate maximum size of JOB_INFO_1A. Later, this
// should be moved into the spooler's header file.
//
cbJob = sizeof(JOB_INFO_1) + 6 * MAX_PATH;
pJob = (PJOB_INFO_1) GlobalAlloc(GMEM_FIXED, cbJob);
if (pJob == NULL) { rc = GetLastError(); goto Cleanup; }
//
// The 3.51 spooler has been changed to accept Get/SetJobs on the
// local server handle. We will still do security checks against
// the Job's security descriptor. This also avoids the costly
// FindLocalJob() call.
//
if (!MyOpenPrinterW( pszServer, &hPrinter, NULL)) { rc = GetLastError(); NetpKdPrint((PREFIX_DOSPRINT "DosPrintJobSetInfoW: " "MyOpenPrinter( NULL, &hPrinter, NULL ) failed" FORMAT_API_STATUS "\n", rc ));
hPrinter = INVALID_HANDLE_VALUE; goto Cleanup; } NetpAssert( hPrinter != INVALID_HANDLE_VALUE );
//
// We need to get a copy of the old job info. Later, the
// spooler should be changed to allow "don't change" values.
//
if (!MyGetJobA( hPrinter, uJobId, 1, (PBYTE)pJob, cbJob, &cbJob )) { rc = GetLastError(); NetpKdPrint((PREFIX_DOSPRINT "DosPrintJobSetInfoW: " "MyGetJob failed" FORMAT_API_STATUS "\n", rc ));
goto Cleanup; }
//
// Put in new document name.
//
NetpNCopyWStrToStr( szDocument, (LPWSTR)pbBuf, sizeof( szDocument ) / sizeof( szDocument[0] ));
pJob->pDocument = szDocument;
//
// Don't try and change the position, since this requires
// admin access (and isn't necessary).
//
pJob->Position = JOB_POSITION_UNSPECIFIED;
rc = CommandALocalJobA( hPrinter, NULL, NULL, uJobId, 1, (PBYTE)pJob, 0 );
if (rc) { NetpKdPrint((PREFIX_DOSPRINT "DosPrintJobSetInfoW: " "CommandALocalJobA failed " FORMAT_API_STATUS "\n", rc )); }
Cleanup: if (pJob) { GlobalFree( pJob ); } if (hPrinter != INVALID_HANDLE_VALUE) { MyClosePrinter( hPrinter ); } return rc; }
return ERROR_NOT_SUPPORTED; }
VOID NetpSetJobCountForQueue( IN DWORD QueueLevel, IN OUT LPVOID Queue, IN BOOL HasUnicodeStrings, IN DWORD JobCount ) { NetpAssert( NetpIsPrintQLevelValid( QueueLevel, FALSE ) ); NetpAssert( Queue != NULL );
if (QueueLevel == 2) { if (HasUnicodeStrings) { PPRQINFOW pq = Queue; pq->cJobs = (WORD) JobCount; } else { PPRQINFOA pq = Queue; pq->cJobs = (WORD) JobCount; } } else if (QueueLevel == 4) { if (HasUnicodeStrings) { PPRQINFO3W pq = Queue; pq->cJobs = (WORD) JobCount; } else { PPRQINFO3A pq = Queue; pq->cJobs = (WORD) JobCount; } } else { NetpAssert( FALSE ); // Should never get here!
}
} // NetpSetJobCountForQueue
|