1086 lines
27 KiB
C++
1086 lines
27 KiB
C++
#include "procs.hxx"
|
|
#pragma hdrstop
|
|
|
|
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
All rights reserved
|
|
|
|
Module Name:
|
|
|
|
PrintWrp.c
|
|
|
|
Abstract:
|
|
|
|
Wide end to Win95 Ansi printing APIs
|
|
|
|
Author:
|
|
Felix Wong (t-felixw)
|
|
|
|
Environment:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "dswarn.h"
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <data.h>
|
|
|
|
typedef struct _SPOOL *PSPOOL;
|
|
typedef struct _NOTIFY *PNOTIFY;
|
|
|
|
typedef struct _NOTIFY {
|
|
PNOTIFY pNext;
|
|
HANDLE hEvent; // event to trigger on notification
|
|
DWORD fdwFlags; // flags to watch for
|
|
DWORD fdwOptions; // PRINTER_NOTIFY_*
|
|
DWORD dwReturn; // used by WPC when simulating FFPCN
|
|
PSPOOL pSpool;
|
|
} NOTIFY;
|
|
|
|
typedef struct _SPOOL {
|
|
DWORD signature;
|
|
HANDLE hPrinter;
|
|
HANDLE hFile;
|
|
DWORD JobId;
|
|
LPBYTE pBuffer;
|
|
DWORD cbBuffer;
|
|
DWORD Status;
|
|
DWORD fdwFlags;
|
|
DWORD cCacheWrite;
|
|
DWORD cWritePrinters;
|
|
DWORD cFlushBuffers;
|
|
DWORD dwTickCount;
|
|
DWORD dwCheckJobInterval;
|
|
PNOTIFY pNotify;
|
|
} SPOOL;
|
|
|
|
#define SPOOL_STATUS_ANSI 0x00000004
|
|
#define MIN_DEVMODE_SIZEW 72
|
|
#define MIN_DEVMODE_SIZEA 40
|
|
#define NULL_TERMINATED 0
|
|
|
|
|
|
BOOL
|
|
ConvertAnsiToUnicodeBuf(
|
|
LPBYTE pAnsiBlob,
|
|
LPBYTE pUnicodeBlob,
|
|
DWORD dwAnsiSize,
|
|
DWORD dwUnicodeSize,
|
|
PDWORD pOffsets
|
|
);
|
|
|
|
|
|
BOOL
|
|
bValidDevModeW(
|
|
const DEVMODEW *pDevModeW
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check whether a devmode is valid to be RPC'd across to the spooler.
|
|
|
|
Arguments:
|
|
|
|
pDevMode - DevMode to check.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Devmode can be RPC'd to spooler.
|
|
FALSE - Invalid Devmode.
|
|
|
|
--*/
|
|
|
|
{
|
|
if( !pDevModeW ){
|
|
return FALSE;
|
|
}
|
|
|
|
if( pDevModeW->dmSize < MIN_DEVMODE_SIZEW ){
|
|
|
|
//
|
|
// The only valid case is if pDevModeW is NULL. If it's
|
|
// not NULL, then a bad devmode was passed in and the
|
|
// app should fix it's code.
|
|
//
|
|
ASSERT( pDevModeW->dmSize >= MIN_DEVMODE_SIZEW );
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
LPSTR
|
|
AllocateAnsiString(
|
|
LPWSTR pPrinterName
|
|
)
|
|
{
|
|
LPSTR pAnsiString;
|
|
|
|
if (!pPrinterName)
|
|
return NULL;
|
|
|
|
pAnsiString = (LPSTR)LocalAlloc(LPTR, wcslen(pPrinterName)*sizeof(CHAR) +
|
|
sizeof(CHAR));
|
|
|
|
if (pAnsiString)
|
|
UnicodeToAnsiString(pPrinterName, pAnsiString, NULL_TERMINATED);
|
|
|
|
return pAnsiString;
|
|
}
|
|
|
|
|
|
LPSTR
|
|
FreeAnsiString(
|
|
LPSTR pAnsiString
|
|
)
|
|
{
|
|
if (!pAnsiString)
|
|
return NULL;
|
|
|
|
return (LPSTR)LocalFree(pAnsiString);
|
|
}
|
|
|
|
|
|
/***************************** Function Header ******************************
|
|
* AllocateAnsiDevMode
|
|
* Allocate an ANSI version of the DEVMODE structure, and optionally
|
|
* copy the contents of the ANSI version passed in.
|
|
*
|
|
* RETURNS:
|
|
* Address of newly allocated structure, 0 if storage not available.
|
|
*
|
|
* HISTORY:
|
|
* 09:23 on 10-Aug-92 -by- Lindsay Harris [lindsayh]
|
|
* Made it usable.
|
|
*
|
|
* Originally "written" by DaveSn.
|
|
*
|
|
***************************************************************************/
|
|
|
|
LPDEVMODEA
|
|
AllocateAnsiDevMode(
|
|
LPDEVMODEW pUNICODEDevMode
|
|
)
|
|
{
|
|
LPDEVMODEA pAnsiDevMode;
|
|
LPBYTE p1, p2;
|
|
DWORD dwSize;
|
|
|
|
//
|
|
// If the devmode is NULL, then return NULL -- KrishnaG
|
|
//
|
|
if ( !pUNICODEDevMode || !pUNICODEDevMode->dmSize ) {
|
|
return NULL;
|
|
}
|
|
|
|
ASSERT( bValidDevModeW( pUNICODEDevMode ));
|
|
|
|
//
|
|
// Determine output structure size. This has two components: the
|
|
// DEVMODEW structure size, plus any private data area. The latter
|
|
// is only meaningful when a structure is passed in.
|
|
//
|
|
dwSize = pUNICODEDevMode->dmSize + pUNICODEDevMode->dmDriverExtra
|
|
+ sizeof(DEVMODEA) - sizeof(DEVMODEW);
|
|
|
|
pAnsiDevMode = (LPDEVMODEA) LocalAlloc(LPTR, dwSize);
|
|
|
|
if( !pAnsiDevMode ) {
|
|
return NULL; /* This is bad news */
|
|
}
|
|
|
|
//
|
|
// Copy dmDeviceName which is a string
|
|
//
|
|
UnicodeToAnsiString(pUNICODEDevMode->dmDeviceName,
|
|
(LPSTR)(pAnsiDevMode->dmDeviceName),
|
|
ComputeMaxStrlenW(pUNICODEDevMode->dmDeviceName,
|
|
sizeof pUNICODEDevMode->dmDeviceName));
|
|
|
|
//
|
|
// Does the devmode we got have a dmFormName? (Windows 3.1 had
|
|
// DevMode of size 40 and did not have dmFormName)
|
|
//
|
|
if ( (LPBYTE)pUNICODEDevMode + pUNICODEDevMode->dmSize >
|
|
(LPBYTE) pUNICODEDevMode->dmFormName ) {
|
|
|
|
//
|
|
// Copy everything between dmDeviceName and dmFormName
|
|
//
|
|
p1 = (LPBYTE) pUNICODEDevMode->dmDeviceName +
|
|
sizeof(pUNICODEDevMode->dmDeviceName);
|
|
p2 = (LPBYTE) pUNICODEDevMode->dmFormName;
|
|
|
|
|
|
CopyMemory((LPBYTE) pAnsiDevMode->dmDeviceName +
|
|
sizeof(pAnsiDevMode->dmDeviceName),
|
|
p1,
|
|
p2 - p1);
|
|
|
|
//
|
|
// Copy dmFormName which is a string
|
|
//
|
|
UnicodeToAnsiString(pUNICODEDevMode->dmFormName,
|
|
(LPSTR)(pAnsiDevMode->dmFormName),
|
|
ComputeMaxStrlenW(pUNICODEDevMode->dmFormName,
|
|
sizeof pUNICODEDevMode->dmFormName));
|
|
|
|
//
|
|
// Copy everything after dmFormName
|
|
//
|
|
p1 = (LPBYTE) pUNICODEDevMode->dmFormName +
|
|
sizeof(pUNICODEDevMode->dmFormName);
|
|
p2 = (LPBYTE) pUNICODEDevMode + pUNICODEDevMode->dmSize
|
|
+ pUNICODEDevMode->dmDriverExtra;
|
|
|
|
CopyMemory((LPBYTE) pAnsiDevMode->dmFormName +
|
|
sizeof(pAnsiDevMode->dmFormName),
|
|
p1,
|
|
p2 - p1);
|
|
|
|
pAnsiDevMode->dmSize = pUNICODEDevMode->dmSize + sizeof(DEVMODEA)
|
|
- sizeof(DEVMODEW);
|
|
} else {
|
|
|
|
//
|
|
// Copy everything after dmDeviceName
|
|
//
|
|
p1 = (LPBYTE) pUNICODEDevMode->dmDeviceName +
|
|
sizeof(pUNICODEDevMode->dmDeviceName);
|
|
p2 = (LPBYTE) pUNICODEDevMode + pUNICODEDevMode->dmSize + pUNICODEDevMode->dmDriverExtra;
|
|
|
|
CopyMemory((LPBYTE) pAnsiDevMode->dmDeviceName +
|
|
sizeof(pAnsiDevMode->dmDeviceName),
|
|
p1,
|
|
p2-p1);
|
|
|
|
pAnsiDevMode->dmSize = pUNICODEDevMode->dmSize
|
|
+ sizeof(pAnsiDevMode->dmDeviceName)
|
|
- sizeof(pUNICODEDevMode->dmDeviceName);
|
|
}
|
|
|
|
ASSERT(pAnsiDevMode->dmDriverExtra == pUNICODEDevMode->dmDriverExtra);
|
|
|
|
|
|
return pAnsiDevMode;
|
|
}
|
|
|
|
/************************** Function Header ******************************
|
|
* CopyUnicodeDevModeFromAnsiDevMode
|
|
* Converts the ANSI version of the DEVMODE to the UNICODE version.
|
|
*
|
|
* RETURNS:
|
|
* Nothing.
|
|
*
|
|
* HISTORY:
|
|
* 09:57 on 10-Aug-92 -by- Lindsay Harris [lindsayh]
|
|
* This one actually works!
|
|
*
|
|
* Originally dreamed up by DaveSn.
|
|
*
|
|
**************************************************************************/
|
|
|
|
void
|
|
CopyUnicodeDevModeFromAnsiDevMode(
|
|
LPDEVMODEW pUNICODEDevMode, /* Filled in by us */
|
|
LPDEVMODEA pAnsiDevMode /* Source of data to fill above */
|
|
)
|
|
{
|
|
LPBYTE p1, p2, pExtra;
|
|
WORD dmSize, dmDriverExtra;
|
|
|
|
//
|
|
// NOTE: THE TWO INPUT STRUCTURES MAY BE THE SAME.
|
|
//
|
|
dmSize = pAnsiDevMode->dmSize;
|
|
dmDriverExtra = pAnsiDevMode->dmDriverExtra;
|
|
pExtra = (LPBYTE) pAnsiDevMode + pAnsiDevMode->dmSize;
|
|
|
|
//
|
|
// Copy dmDeviceName which is a string
|
|
//
|
|
AnsiToUnicodeString((LPSTR)(pAnsiDevMode->dmDeviceName),
|
|
(pUNICODEDevMode->dmDeviceName),
|
|
ComputeMaxStrlenA((LPSTR)(pAnsiDevMode->dmDeviceName),
|
|
sizeof pUNICODEDevMode->dmDeviceName));
|
|
|
|
//
|
|
// Does the devmode we got have a dmFormName? (Windows 3.1 had
|
|
// DevMode of size 40 and did not have dmFormName)
|
|
//
|
|
if ( (LPBYTE)pAnsiDevMode + dmSize >
|
|
(LPBYTE) pAnsiDevMode->dmFormName ) {
|
|
|
|
//
|
|
// Copy everything between dmDeviceName and dmFormName
|
|
//
|
|
p1 = (LPBYTE) pAnsiDevMode->dmDeviceName +
|
|
sizeof(pAnsiDevMode->dmDeviceName);
|
|
p2 = (LPBYTE) pAnsiDevMode->dmFormName;
|
|
|
|
MoveMemory((LPBYTE) pUNICODEDevMode->dmDeviceName +
|
|
sizeof(pUNICODEDevMode->dmDeviceName),
|
|
p1,
|
|
p2 - p1);
|
|
|
|
//
|
|
// Copy dmFormName which is a string
|
|
//
|
|
AnsiToUnicodeString((LPSTR)(pAnsiDevMode->dmFormName),
|
|
pUNICODEDevMode->dmFormName,
|
|
ComputeMaxStrlenA((LPSTR)pAnsiDevMode->dmFormName,
|
|
sizeof pUNICODEDevMode->dmFormName));
|
|
|
|
//
|
|
// Copy everything after dmFormName
|
|
//
|
|
p1 = (LPBYTE) pAnsiDevMode->dmFormName +
|
|
sizeof(pAnsiDevMode->dmFormName);
|
|
p2 = (LPBYTE) pAnsiDevMode + dmSize + dmDriverExtra;
|
|
|
|
MoveMemory((LPBYTE) pUNICODEDevMode->dmFormName +
|
|
sizeof(pUNICODEDevMode->dmFormName),
|
|
p1,
|
|
p2 - p1);
|
|
|
|
|
|
pUNICODEDevMode->dmSize = dmSize + sizeof(DEVMODEW) - sizeof(DEVMODEA);
|
|
} else {
|
|
|
|
//
|
|
// Copy everything after dmDeviceName
|
|
//
|
|
p1 = (LPBYTE) pAnsiDevMode->dmDeviceName +
|
|
sizeof(pAnsiDevMode->dmDeviceName);
|
|
p2 = (LPBYTE) pAnsiDevMode + dmSize + dmDriverExtra;
|
|
|
|
MoveMemory((LPBYTE) pUNICODEDevMode->dmDeviceName +
|
|
sizeof(pUNICODEDevMode->dmDeviceName),
|
|
p1,
|
|
p2 - p1);
|
|
|
|
|
|
pUNICODEDevMode->dmSize = dmSize + sizeof(pUNICODEDevMode->dmDeviceName)
|
|
- sizeof(pAnsiDevMode->dmDeviceName);
|
|
}
|
|
|
|
ASSERT(pUNICODEDevMode->dmDriverExtra == dmDriverExtra);
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
ConvertAnsiToUnicodeStrings(
|
|
LPBYTE pStructure,
|
|
LPDWORD pOffsets
|
|
)
|
|
{
|
|
register DWORD i=0;
|
|
LPSTR pAnsi;
|
|
LPWSTR pUnicode;
|
|
|
|
while (pOffsets[i] != -1) {
|
|
pAnsi = *(LPSTR *)(pStructure+pOffsets[i]);
|
|
if (pAnsi) {
|
|
pUnicode = (LPWSTR)LocalAlloc( LPTR,
|
|
strlen(pAnsi)*sizeof(WCHAR)+
|
|
sizeof(WCHAR));
|
|
if (pUnicode) {
|
|
AnsiToUnicodeString(pAnsi,
|
|
pUnicode,
|
|
NULL_TERMINATED);
|
|
*(LPWSTR *)(pStructure+pOffsets[i]) = pUnicode;
|
|
LocalFree(pAnsi);
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
LPBYTE
|
|
AllocateAnsiStructure(
|
|
LPBYTE pUnicodeStructure,
|
|
DWORD cbStruct,
|
|
LPDWORD pOffsets
|
|
)
|
|
{
|
|
DWORD i, j;
|
|
LPSTR *ppAnsiString;
|
|
LPWSTR *ppUnicodeString;
|
|
LPBYTE pAnsiStructure;
|
|
|
|
|
|
if (!pUnicodeStructure) {
|
|
return NULL;
|
|
}
|
|
pAnsiStructure = (LPBYTE)LocalAlloc(LPTR, cbStruct);
|
|
|
|
if (pAnsiStructure) {
|
|
|
|
memcpy(pAnsiStructure, pUnicodeStructure, cbStruct);
|
|
|
|
for (i = 0 ; pOffsets[i] != -1 ; ++i) {
|
|
|
|
ppUnicodeString = (LPWSTR *)(pUnicodeStructure+pOffsets[i]);
|
|
ppAnsiString = (LPSTR *)(pAnsiStructure+pOffsets[i]);
|
|
|
|
*ppAnsiString = AllocateAnsiString(*ppUnicodeString);
|
|
|
|
if (*ppUnicodeString && !*ppAnsiString) {
|
|
|
|
for( j = 0 ; j < i ; ++j) {
|
|
ppAnsiString = (LPSTR *)(pAnsiStructure+pOffsets[j]);
|
|
FreeAnsiString(*ppAnsiString);
|
|
}
|
|
LocalFree(pAnsiStructure);
|
|
pAnsiStructure = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return pAnsiStructure;
|
|
}
|
|
|
|
void
|
|
FreeAnsiStructure(
|
|
LPBYTE pAnsiStructure,
|
|
LPDWORD pOffsets
|
|
)
|
|
{
|
|
DWORD i=0;
|
|
|
|
if ( pAnsiStructure == NULL ) {
|
|
return;
|
|
}
|
|
|
|
while (pOffsets[i] != -1) {
|
|
|
|
FreeAnsiString(*(LPSTR *)(pAnsiStructure+pOffsets[i]));
|
|
i++;
|
|
}
|
|
|
|
LocalFree( pAnsiStructure );
|
|
}
|
|
|
|
|
|
BOOL
|
|
EnumJobsW(
|
|
HANDLE hPrinter,
|
|
DWORD FirstJob,
|
|
DWORD NoJobs,
|
|
DWORD Level,
|
|
LPBYTE pJob,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded,
|
|
LPDWORD pcReturned
|
|
)
|
|
{
|
|
DWORD i, cbStruct, *pOffsets;
|
|
|
|
switch (Level) {
|
|
|
|
case 1:
|
|
pOffsets = JobInfo1StringsA;
|
|
cbStruct = sizeof(JOB_INFO_1W);
|
|
break;
|
|
|
|
case 2:
|
|
pOffsets = JobInfo2StringsA;
|
|
cbStruct = sizeof(JOB_INFO_2W);
|
|
break;
|
|
|
|
case 3:
|
|
return EnumJobsA( hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned );
|
|
|
|
default:
|
|
SetLastError(ERROR_INVALID_LEVEL);
|
|
return FALSE;
|
|
}
|
|
|
|
if (EnumJobsA(hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded,
|
|
pcReturned)) {
|
|
|
|
i=*pcReturned;
|
|
|
|
while (i--) {
|
|
|
|
ConvertAnsiToUnicodeStrings(pJob, pOffsets);
|
|
|
|
//
|
|
// Convert the devmode in place for INFO_2.
|
|
//
|
|
if( Level == 2 ){
|
|
|
|
PJOB_INFO_2W pJobInfo2 = (PJOB_INFO_2W)pJob;
|
|
|
|
if( pJobInfo2->pDevMode ){
|
|
CopyUnicodeDevModeFromAnsiDevMode(
|
|
(LPDEVMODEW)pJobInfo2->pDevMode,
|
|
(LPDEVMODEA)pJobInfo2->pDevMode);
|
|
}
|
|
}
|
|
|
|
pJob += cbStruct;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
} else
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
GetPrinterW(
|
|
HANDLE hPrinter,
|
|
DWORD Level,
|
|
LPBYTE pPrinter,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded
|
|
)
|
|
{
|
|
DWORD *pOffsets;
|
|
|
|
switch (Level) {
|
|
|
|
//case STRESSINFOLEVEL:
|
|
// pOffsets = PrinterInfoStressOffsetsA;
|
|
// break;
|
|
|
|
case 1:
|
|
pOffsets = PrinterInfo1StringsA;
|
|
break;
|
|
|
|
case 2:
|
|
pOffsets = PrinterInfo2StringsA;
|
|
break;
|
|
|
|
case 3:
|
|
pOffsets = PrinterInfo3StringsA;
|
|
break;
|
|
|
|
case 4:
|
|
pOffsets = PrinterInfo4StringsA;
|
|
break;
|
|
|
|
case 5:
|
|
pOffsets = PrinterInfo5StringsA;
|
|
break;
|
|
|
|
default:
|
|
SetLastError(ERROR_INVALID_LEVEL);
|
|
return FALSE;
|
|
}
|
|
|
|
if (GetPrinterA(hPrinter, Level, pPrinter, cbBuf, pcbNeeded)) {
|
|
|
|
if (pPrinter) {
|
|
|
|
ConvertAnsiToUnicodeStrings(pPrinter, pOffsets);
|
|
|
|
if ((Level == 2) && pPrinter) {
|
|
|
|
PRINTER_INFO_2W *pPrinterInfo2 = (PRINTER_INFO_2W *)pPrinter;
|
|
|
|
if (pPrinterInfo2->pDevMode)
|
|
CopyUnicodeDevModeFromAnsiDevMode(
|
|
(LPDEVMODEW)pPrinterInfo2->pDevMode,
|
|
(LPDEVMODEA)pPrinterInfo2->pDevMode);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
SetPrinterW(
|
|
HANDLE hPrinter,
|
|
DWORD Level,
|
|
LPBYTE pPrinter,
|
|
DWORD Command
|
|
)
|
|
{
|
|
LPBYTE pAnsiStructure; /* Ansi version of input data */
|
|
DWORD cbStruct; /* Size of the output structure */
|
|
DWORD *pOffsets; /* -1 terminated list of addresses */
|
|
DWORD ReturnValue=FALSE;
|
|
|
|
switch (Level) {
|
|
|
|
case 0:
|
|
//
|
|
// This could be 2 cases. STRESSINFOLEVEL, or the real 0 level.
|
|
// If Command is 0 then it is STRESSINFOLEVEL, else real 0 level
|
|
//
|
|
/*
|
|
if ( !Command ) {
|
|
|
|
pOffsets = PrinterInfoStressStringsA;
|
|
cbStruct = sizeof( PRINTER_INFO_STRESSA );
|
|
}
|
|
*/
|
|
break;
|
|
|
|
case 1:
|
|
pOffsets = PrinterInfo1StringsA;
|
|
cbStruct = sizeof( PRINTER_INFO_1W );
|
|
break;
|
|
|
|
case 2:
|
|
pOffsets = PrinterInfo2StringsA;
|
|
cbStruct = sizeof( PRINTER_INFO_2W );
|
|
break;
|
|
|
|
case 3:
|
|
pOffsets = PrinterInfo3StringsA;
|
|
cbStruct = sizeof( PRINTER_INFO_3);
|
|
break;
|
|
|
|
case 4:
|
|
pOffsets = PrinterInfo4StringsA;
|
|
cbStruct = sizeof( PRINTER_INFO_4W );
|
|
break;
|
|
|
|
case 5:
|
|
pOffsets = PrinterInfo5StringsA;
|
|
cbStruct = sizeof( PRINTER_INFO_5W );
|
|
break;
|
|
|
|
case 6:
|
|
break;
|
|
|
|
default:
|
|
SetLastError( ERROR_INVALID_LEVEL );
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// The structure needs to have its CONTENTS converted from
|
|
// ANSI to Unicode. The above switch() statement filled in
|
|
// the two important pieces of information needed to accomplish
|
|
// this goal. First is the size of the structure, second is
|
|
// a list of the offset within the structure to UNICODE
|
|
// string pointers. The AllocateUnicodeStructure() call will
|
|
// allocate a wide version of the structure, copy its contents
|
|
// and convert the strings to Unicode as it goes. That leaves
|
|
// us to deal with any other pieces needing conversion.
|
|
//
|
|
|
|
//
|
|
// If Level == 0 and Command != 0 then pPrintert is a DWORD
|
|
//
|
|
if ( Level == 6 || (!Level && Command) ) {
|
|
|
|
if ( Level == 6 || Command == PRINTER_CONTROL_SET_STATUS )
|
|
pAnsiStructure = pPrinter;
|
|
else
|
|
pAnsiStructure = NULL;
|
|
} else {
|
|
|
|
pAnsiStructure = AllocateAnsiStructure(pPrinter, cbStruct, pOffsets);
|
|
if (pPrinter && !pAnsiStructure)
|
|
return FALSE;
|
|
}
|
|
|
|
#define pPrinterInfo2A ((LPPRINTER_INFO_2A)pAnsiStructure)
|
|
#define pPrinterInfo2W ((LPPRINTER_INFO_2W)pPrinter)
|
|
|
|
// The Level 2 structure has a DEVMODE struct in it: convert now
|
|
|
|
if ( Level == 2 &&
|
|
pAnsiStructure &&
|
|
pPrinterInfo2W->pDevMode ) {
|
|
|
|
if( bValidDevModeW( pPrinterInfo2W->pDevMode )){
|
|
pPrinterInfo2A->pDevMode = AllocateAnsiDevMode(
|
|
pPrinterInfo2W->pDevMode );
|
|
|
|
if( !pPrinterInfo2A->pDevMode) {
|
|
FreeAnsiStructure(pAnsiStructure, pOffsets);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
ReturnValue = SetPrinterA( hPrinter, Level, pAnsiStructure, Command );
|
|
|
|
|
|
// Free the DEVMODE we allocated (if we did!), then the
|
|
// the Unicode structure and its contents.
|
|
|
|
|
|
if (Level == 2 &&
|
|
pAnsiStructure &&
|
|
pPrinterInfo2A->pDevMode ) {
|
|
|
|
LocalFree( pPrinterInfo2A->pDevMode );
|
|
}
|
|
|
|
//
|
|
// STRESS_INFO and Levels 1-5
|
|
//
|
|
if ( Level != 6 && (Level || !Command) )
|
|
FreeAnsiStructure( pAnsiStructure, pOffsets );
|
|
|
|
#undef pPrinterInfo2A
|
|
#undef pPrinterInfo2W
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
BOOL
|
|
SetJobW(
|
|
HANDLE hPrinter,
|
|
DWORD JobId,
|
|
DWORD Level,
|
|
LPBYTE pJob,
|
|
DWORD Command
|
|
)
|
|
{
|
|
BOOL ReturnValue=FALSE;
|
|
LPBYTE pAnsiStructure=NULL;
|
|
LPDEVMODEA pDevModeA = NULL;
|
|
DWORD cbStruct;
|
|
DWORD *pOffsets;
|
|
|
|
switch (Level) {
|
|
|
|
case 0:
|
|
break;
|
|
|
|
case 1:
|
|
pOffsets = JobInfo1StringsA;
|
|
cbStruct = sizeof(JOB_INFO_1W);
|
|
break;
|
|
|
|
case 2:
|
|
pOffsets = JobInfo2StringsA;
|
|
cbStruct = sizeof(JOB_INFO_2W);
|
|
break;
|
|
|
|
case 3:
|
|
return SetJobA( hPrinter, JobId, Level, pJob, Command );
|
|
|
|
default:
|
|
SetLastError(ERROR_INVALID_LEVEL);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if (Level) {
|
|
pAnsiStructure = AllocateAnsiStructure(pJob, cbStruct, pOffsets);
|
|
if (pJob && !pAnsiStructure)
|
|
return FALSE;
|
|
}
|
|
|
|
if ( Level == 2 && pAnsiStructure && pJob ) {
|
|
|
|
if( bValidDevModeW( ((LPJOB_INFO_2W)pJob)->pDevMode )){
|
|
|
|
pDevModeA = AllocateAnsiDevMode(((LPJOB_INFO_2W)pJob)->pDevMode);
|
|
|
|
if( !pDevModeA ){
|
|
ReturnValue = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
((LPJOB_INFO_2A) pAnsiStructure)->pDevMode = pDevModeA;
|
|
}
|
|
}
|
|
|
|
ReturnValue = SetJobA(hPrinter, JobId, Level, pAnsiStructure, Command);
|
|
|
|
if ( pDevModeA ) {
|
|
|
|
LocalFree(pDevModeA);
|
|
}
|
|
|
|
Cleanup:
|
|
FreeAnsiStructure(pAnsiStructure, pOffsets);
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
BOOL
|
|
GetJobW(
|
|
HANDLE hPrinter,
|
|
DWORD JobId,
|
|
DWORD Level,
|
|
LPBYTE pJob,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded
|
|
)
|
|
{
|
|
DWORD *pOffsets;
|
|
LPBYTE pJobA = NULL;
|
|
DWORD cbNeededA = 0;
|
|
DWORD cbBufA = 0;
|
|
DWORD dwJobStructSizeW = 0;
|
|
DWORD dwJobStructSizeA = 0;
|
|
BOOL fRetval;
|
|
|
|
switch (Level) {
|
|
|
|
case 1:
|
|
pOffsets = JobInfo1StringsA;
|
|
dwJobStructSizeW = sizeof(JOB_INFO_1W);
|
|
dwJobStructSizeA = sizeof(JOB_INFO_1A);
|
|
break;
|
|
|
|
case 2:
|
|
pOffsets = JobInfo2StringsA;
|
|
dwJobStructSizeW = sizeof(JOB_INFO_2W);
|
|
dwJobStructSizeA = sizeof(JOB_INFO_2A);
|
|
break;
|
|
|
|
case 3:
|
|
return GetJobA( hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded );
|
|
|
|
default:
|
|
SetLastError(ERROR_INVALID_LEVEL);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// GetJobA is broken. THis is a workaround here which will work
|
|
// sometimes. The AV problem however goes away.
|
|
//
|
|
// Ramv bug fix: The user has passed in a certain amount of
|
|
// unicode memory. This has to be appropriately translated into
|
|
// equivalent ANSI memory.
|
|
//
|
|
//
|
|
// The translation is to take the entire blob of memory and
|
|
// subtract sizeof(JOB_INFO_2W) and then divide the remaining memory
|
|
// into 2.
|
|
//
|
|
// we also have to contend with GetJobA's erroneous return values
|
|
// when we pass in a buffer of sixe 0, it gives back wrong results
|
|
//
|
|
//
|
|
//
|
|
|
|
cbBufA = cbBuf > dwJobStructSizeW ?
|
|
(cbBuf-dwJobStructSizeW)/sizeof(WCHAR) + dwJobStructSizeA : 64;
|
|
|
|
|
|
pJobA = (LPBYTE)AllocADsMem( cbBufA);
|
|
|
|
if (!pJobA){
|
|
goto error;
|
|
}
|
|
|
|
|
|
fRetval = GetJobA (hPrinter, JobId, Level, pJobA, cbBufA, &cbNeededA);
|
|
|
|
if ( fRetval) {
|
|
|
|
//
|
|
// RamV bug fix.
|
|
// The size that we get back is actually the size of
|
|
// the ANSI array needed. We need our array to be larger for
|
|
// unicode by an amount = (total lengths of all strings +1)
|
|
// times the sizeof(WCHAR)
|
|
//
|
|
|
|
|
|
//
|
|
// Looks like we have sufficient memory here for our operations
|
|
// we need to copy the memory blob from Ansi to Unicode
|
|
//
|
|
|
|
|
|
//
|
|
// Thanks to win95 returning erroneous values, we are forced
|
|
// to fail this call even though it succeeded and send back
|
|
// the cbNeededA value converted into the Unicode value
|
|
//
|
|
|
|
if (cbBuf == 0){
|
|
*pcbNeeded = 2*cbNeededA; // just being conservative here by
|
|
|
|
// allocating a little more space than needed
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto error;
|
|
}
|
|
|
|
if (!ConvertAnsiToUnicodeBuf(
|
|
pJobA,
|
|
pJob,
|
|
dwJobStructSizeA,
|
|
dwJobStructSizeW,
|
|
pOffsets)){
|
|
|
|
goto error;
|
|
}
|
|
|
|
//
|
|
// Convert the devmode in place for INFO_2.
|
|
//
|
|
if( Level == 2 ){
|
|
|
|
PJOB_INFO_2W pJobInfo2 = (PJOB_INFO_2W)pJob;
|
|
|
|
if( pJobInfo2->pDevMode ){
|
|
CopyUnicodeDevModeFromAnsiDevMode(
|
|
(LPDEVMODEW)pJobInfo2->pDevMode,
|
|
(LPDEVMODEA)pJobInfo2->pDevMode);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// RamV bug fix.
|
|
// The size that we get back is actually the size of
|
|
// the ANSI array needed. We need our array to be larger for
|
|
// unicode by an amount = (total lengths of all strings +1)
|
|
// times the sizeof(WCHAR)
|
|
//
|
|
|
|
if(cbNeededA) {
|
|
//
|
|
// we need to translate this into unicode terms
|
|
//
|
|
|
|
*pcbNeeded = dwJobStructSizeW +
|
|
(cbBufA + cbNeededA - dwJobStructSizeA)*sizeof(WCHAR);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
error:
|
|
if(pJobA) {
|
|
FreeADsMem(pJobA);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
ConvertAnsiToUnicodeBuf(
|
|
LPBYTE pAnsiBlob,
|
|
LPBYTE pUnicodeBlob,
|
|
DWORD dwAnsiSize,
|
|
DWORD dwUnicodeSize,
|
|
PDWORD pOffsets
|
|
)
|
|
|
|
{
|
|
DWORD i = 0;
|
|
LPSTR pAnsi;
|
|
LPBYTE pUnicode;
|
|
LPBYTE pszString = pUnicodeBlob + dwUnicodeSize;
|
|
LPBYTE pStringPos = NULL;
|
|
|
|
memcpy(pUnicodeBlob, pAnsiBlob, dwAnsiSize);
|
|
|
|
pUnicode = pszString;
|
|
while (pOffsets[i] != -1) {
|
|
pAnsi = *(LPSTR *)(pAnsiBlob + pOffsets[i]);
|
|
|
|
if (!AnsiToUnicodeString((LPSTR)pAnsi,
|
|
(LPWSTR)pUnicode,
|
|
NULL_TERMINATED )){
|
|
return(FALSE);
|
|
}
|
|
|
|
pStringPos = pUnicodeBlob +pOffsets[i];
|
|
|
|
*((LPBYTE *)pStringPos) = pUnicode;
|
|
|
|
pUnicode = pUnicode + (wcslen((LPWSTR)(pUnicode))+1)* sizeof(WCHAR);
|
|
|
|
i++;
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
OpenPrinterW(
|
|
LPWSTR pPrinterName,
|
|
LPHANDLE phPrinter,
|
|
LPPRINTER_DEFAULTSW pDefault
|
|
)
|
|
{
|
|
BOOL ReturnValue = FALSE;
|
|
LPSTR pAnsiPrinterName = NULL;
|
|
PRINTER_DEFAULTSA AnsiDefaults={NULL, NULL, 0};
|
|
|
|
pAnsiPrinterName = AllocateAnsiString(pPrinterName);
|
|
|
|
if (pPrinterName && !pAnsiPrinterName)
|
|
goto Cleanup;
|
|
|
|
if (pDefault) {
|
|
|
|
AnsiDefaults.pDatatype = AllocateAnsiString(pDefault->pDatatype);
|
|
if (pDefault->pDatatype && !AnsiDefaults.pDatatype)
|
|
goto Cleanup;
|
|
|
|
//
|
|
// Milestones etc. 4.5 passes in a bogus devmode in pDefaults.
|
|
// Be sure to validate here.
|
|
//
|
|
if( bValidDevModeW( pDefault->pDevMode )){
|
|
|
|
AnsiDefaults.pDevMode = AllocateAnsiDevMode(
|
|
pDefault->pDevMode );
|
|
|
|
if( !AnsiDefaults.pDevMode ){
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
AnsiDefaults.DesiredAccess = pDefault->DesiredAccess;
|
|
}
|
|
|
|
ReturnValue = OpenPrinterA(pAnsiPrinterName, phPrinter, &AnsiDefaults);
|
|
|
|
/* Ramv This code below causes AV. I have disabled it
|
|
MattRim 1-10-00: Leaving this disabled. phPrinter is an opaque handle
|
|
to an undocumented structure. Trying to manipulate it is a surefire way
|
|
to cause AVs if a service pack/O.S. upgrade ever changes the implementation
|
|
of this Win9x-internal structure.
|
|
if (ReturnValue) {
|
|
|
|
((PSPOOL)*phPrinter)->Status |= SPOOL_STATUS_ANSI;
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
Cleanup:
|
|
|
|
if (AnsiDefaults.pDevMode)
|
|
LocalFree(AnsiDefaults.pDevMode);
|
|
|
|
FreeAnsiString(AnsiDefaults.pDatatype);
|
|
FreeAnsiString(pAnsiPrinterName);
|
|
|
|
return ReturnValue;
|
|
}
|
|
|