5194 lines
117 KiB
C
5194 lines
117 KiB
C
/*++
|
||
|
||
Copyright (c) 1990-1996 Microsoft Corporation
|
||
All rights reserved
|
||
|
||
Module Name:
|
||
|
||
Winspool.c
|
||
|
||
Abstract:
|
||
|
||
Bulk of winspool.drv code
|
||
|
||
Author:
|
||
|
||
Environment:
|
||
|
||
User Mode -Win32
|
||
|
||
Revision History:
|
||
mattfe april 14 94 added caching to writeprinter
|
||
mattfe jan 95 Add SetAllocFailCount api
|
||
|
||
13-Jun-1996 Thu 15:07:16 updated -by- Daniel Chou (danielc)
|
||
Make PrinterProperties call PrinterPropertySheets and
|
||
DocumentProperties call DocumentPropertySheets
|
||
|
||
--*/
|
||
|
||
#include <nt.h>
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
#include <stddef.h>
|
||
#include <ntddrdr.h>
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <rpc.h>
|
||
#include "winspl.h"
|
||
#include <offsets.h>
|
||
#include <browse.h>
|
||
#include "client.h"
|
||
#include <change.h>
|
||
#include <windows.h>
|
||
#include <winddiui.h>
|
||
#include "wingdip.h"
|
||
#include "gdispool.h"
|
||
|
||
#include "shlobj.h"
|
||
#include "shlobjp.h"
|
||
|
||
extern
|
||
LONG
|
||
DocumentPropertySheets(
|
||
PPROPSHEETUI_INFO pCPSUIInfo,
|
||
LPARAM lParam
|
||
);
|
||
|
||
extern
|
||
LONG
|
||
DevicePropertySheets(
|
||
PPROPSHEETUI_INFO pCPSUIInfo,
|
||
LPARAM lParam
|
||
);
|
||
|
||
|
||
VOID
|
||
vUpdateTrayIcon(
|
||
IN HANDLE hPrinter,
|
||
IN DWORD JobId
|
||
);
|
||
|
||
extern LPWSTR InterfaceAddress;
|
||
|
||
MODULE_DEBUG_INIT( DBG_ERROR | DBG_WARN, DBG_ERROR );
|
||
|
||
LPWSTR szEnvironment = LOCAL_ENVIRONMENT;
|
||
|
||
LPTSTR szComma = L",";
|
||
LPTSTR szFilePort = L"FILE:";
|
||
DWORD ClientHandleCount = 0;
|
||
|
||
HANDLE hShell32 = NULL;
|
||
|
||
LPWSTR
|
||
SelectFormNameFromDevMode(
|
||
HANDLE hPrinter,
|
||
PDEVMODEW pDevModeW,
|
||
LPWSTR pFormName
|
||
);
|
||
|
||
#define DM_MATCH( dm, sp ) ((((sp)+50)/100-dm)<15&&(((sp)+50)/100-dm)>-15)
|
||
#define DM_PAPER_WL (DM_PAPERWIDTH | DM_PAPERLENGTH)
|
||
|
||
#define JOB_CANCEL_CHECK_INTERVAL 2000 // 2 seconds
|
||
|
||
|
||
LPWSTR
|
||
IsaFileName(
|
||
LPWSTR pOutputFile,
|
||
LPWSTR FullPathName
|
||
);
|
||
|
||
|
||
|
||
INT
|
||
UnicodeToAnsiString(
|
||
LPWSTR pUnicode,
|
||
LPSTR pAnsi,
|
||
DWORD StringLength);
|
||
|
||
|
||
|
||
LONG
|
||
CallCommonPropertySheetUI(
|
||
HWND hWndOwner,
|
||
PFNPROPSHEETUI pfnPropSheetUI,
|
||
LPARAM lParam,
|
||
LPDWORD pResult
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function dymically load the compstui.dll and call its entry
|
||
|
||
|
||
Arguments:
|
||
|
||
pfnPropSheetUI - Pointer to callback function
|
||
|
||
lParam - lParam for the pfnPropSheetUI
|
||
|
||
pResult - pResult for the CommonPropertySheetUI
|
||
|
||
|
||
Return Value:
|
||
|
||
LONG - as describe in compstui.h
|
||
|
||
|
||
Author:
|
||
|
||
01-Nov-1995 Wed 13:11:19 created -by- Daniel Chou (danielc)
|
||
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
HINSTANCE hInstCPSUI;
|
||
FARPROC pProc;
|
||
LONG Result = ERR_CPSUI_GETLASTERROR;
|
||
|
||
//
|
||
// ONLY need to call the ANSI version of LoadLibrary
|
||
//
|
||
|
||
if ((hInstCPSUI = LoadLibraryA("compstui.dll")) &&
|
||
(pProc = GetProcAddress(hInstCPSUI, "CommonPropertySheetUIW"))) {
|
||
|
||
RpcTryExcept {
|
||
|
||
Result = (*pProc)(hWndOwner, pfnPropSheetUI, lParam, pResult);
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
Result = ERR_CPSUI_GETLASTERROR;
|
||
|
||
} RpcEndExcept
|
||
|
||
}
|
||
|
||
if (hInstCPSUI) {
|
||
|
||
FreeLibrary(hInstCPSUI);
|
||
}
|
||
|
||
return(Result);
|
||
}
|
||
|
||
|
||
// Simple for Now !!!
|
||
|
||
DWORD
|
||
TranslateExceptionCode(
|
||
DWORD ExceptionCode
|
||
)
|
||
{
|
||
switch (ExceptionCode) {
|
||
|
||
case EXCEPTION_ACCESS_VIOLATION:
|
||
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
||
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
|
||
case EXCEPTION_FLT_DENORMAL_OPERAND:
|
||
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
||
case EXCEPTION_FLT_INEXACT_RESULT:
|
||
case EXCEPTION_FLT_INVALID_OPERATION:
|
||
case EXCEPTION_FLT_OVERFLOW:
|
||
case EXCEPTION_FLT_STACK_CHECK:
|
||
case EXCEPTION_FLT_UNDERFLOW:
|
||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||
case EXCEPTION_INT_OVERFLOW:
|
||
case EXCEPTION_PRIV_INSTRUCTION:
|
||
case ERROR_NOACCESS:
|
||
case RPC_S_INVALID_BOUND:
|
||
|
||
return ERROR_INVALID_PARAMETER;
|
||
break;
|
||
default:
|
||
return ExceptionCode;
|
||
}
|
||
}
|
||
|
||
void
|
||
MarshallUpStructure(
|
||
LPBYTE lpStructure,
|
||
LPDWORD lpOffsets
|
||
)
|
||
{
|
||
register DWORD i=0;
|
||
|
||
while (lpOffsets[i] != -1) {
|
||
|
||
if ((*(LPBYTE *)(lpStructure+lpOffsets[i]))) {
|
||
(*(LPBYTE *)(lpStructure+lpOffsets[i]))+=(DWORD)lpStructure;
|
||
}
|
||
|
||
i++;
|
||
}
|
||
}
|
||
|
||
BOOL
|
||
EnumPrintersW(
|
||
DWORD Flags,
|
||
LPWSTR Name,
|
||
DWORD Level,
|
||
LPBYTE pPrinterEnum,
|
||
DWORD cbBuf,
|
||
LPDWORD pcbNeeded,
|
||
LPDWORD pcReturned
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
DWORD cbStruct;
|
||
DWORD *pOffsets;
|
||
|
||
switch (Level) {
|
||
|
||
case STRESSINFOLEVEL:
|
||
pOffsets = PrinterInfoStressOffsets;
|
||
cbStruct = sizeof(PRINTER_INFO_STRESS);
|
||
break;
|
||
|
||
case 1:
|
||
pOffsets = PrinterInfo1Offsets;
|
||
cbStruct = sizeof(PRINTER_INFO_1);
|
||
break;
|
||
|
||
case 2:
|
||
pOffsets = PrinterInfo2Offsets;
|
||
cbStruct = sizeof(PRINTER_INFO_2);
|
||
break;
|
||
|
||
case 4:
|
||
pOffsets = PrinterInfo4Offsets;
|
||
cbStruct = sizeof(PRINTER_INFO_4);
|
||
break;
|
||
|
||
case 5:
|
||
pOffsets = PrinterInfo5Offsets;
|
||
cbStruct = sizeof(PRINTER_INFO_5);
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
if (pPrinterEnum)
|
||
memset(pPrinterEnum, 0, cbBuf);
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcEnumPrinters(Flags, Name, Level, pPrinterEnum, cbBuf,
|
||
pcbNeeded, pcReturned)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else {
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
if (pPrinterEnum) {
|
||
|
||
DWORD i=*pcReturned;
|
||
|
||
while (i--) {
|
||
|
||
MarshallUpStructure(pPrinterEnum, pOffsets);
|
||
|
||
pPrinterEnum+=cbStruct;
|
||
}
|
||
}
|
||
}
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
OpenPrinterW(
|
||
LPWSTR pPrinterName,
|
||
LPHANDLE phPrinter,
|
||
LPPRINTER_DEFAULTS pDefault
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
DEVMODE_CONTAINER DevModeContainer;
|
||
HANDLE hPrinter;
|
||
PSPOOL pSpool;
|
||
DWORD dwSize = 0;
|
||
|
||
//
|
||
// Pre-initialize the out parameter, so that *phPrinter is NULL
|
||
// on failure. This fixes Borland Paradox 7.
|
||
//
|
||
try {
|
||
*phPrinter = NULL;
|
||
} except( EXCEPTION_EXECUTE_HANDLER ){
|
||
SetLastError(TranslateExceptionCode(GetExceptionCode()));
|
||
return FALSE;
|
||
}
|
||
|
||
if (pDefault && pDefault->pDevMode)
|
||
{
|
||
dwSize = pDefault->pDevMode->dmSize + pDefault->pDevMode->dmDriverExtra;
|
||
if (dwSize) {
|
||
DevModeContainer.cbBuf = pDefault->pDevMode->dmSize +
|
||
pDefault->pDevMode->dmDriverExtra;
|
||
DevModeContainer.pDevMode = (LPBYTE)pDefault->pDevMode;
|
||
} else {
|
||
DevModeContainer.cbBuf = 0;
|
||
DevModeContainer.pDevMode = NULL;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DevModeContainer.cbBuf = 0;
|
||
DevModeContainer.pDevMode = NULL;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcOpenPrinter(pPrinterName, &hPrinter,
|
||
pDefault ? pDefault->pDatatype : NULL,
|
||
&DevModeContainer,
|
||
pDefault ? pDefault->DesiredAccess : 0 )) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
if (ReturnValue) {
|
||
|
||
pSpool = AllocSplMem(sizeof(SPOOL));
|
||
|
||
if (pSpool) {
|
||
|
||
memset(pSpool, 0, sizeof(SPOOL));
|
||
pSpool->signature = SP_SIGNATURE;
|
||
pSpool->hPrinter = hPrinter;
|
||
pSpool->hFile = INVALID_HANDLE_VALUE;
|
||
pSpool->pBuffer = NULL;
|
||
pSpool->cCacheWrite = 0;
|
||
pSpool->dwTickCount = 0;
|
||
pSpool->cWritePrinters = 0;
|
||
|
||
//
|
||
// This is to fix passing a bad pHandle to OpenPrinter!!
|
||
//
|
||
try {
|
||
*phPrinter = pSpool;
|
||
} except(1) {
|
||
RpcClosePrinter(&hPrinter);
|
||
FreeSplMem(pSpool);
|
||
SetLastError(TranslateExceptionCode(GetExceptionCode()));
|
||
return(FALSE);
|
||
}
|
||
|
||
InterlockedIncrement( &ClientHandleCount );
|
||
|
||
} else {
|
||
|
||
RpcClosePrinter(&hPrinter);
|
||
ReturnValue = FALSE;
|
||
}
|
||
}
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
ResetPrinterW(
|
||
HANDLE hPrinter,
|
||
LPPRINTER_DEFAULTS pDefault
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
DEVMODE_CONTAINER DevModeContainer;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
DWORD dwFlags = 0;
|
||
LPWSTR pDatatype = NULL;
|
||
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
|
||
FlushBuffer(pSpool);
|
||
|
||
|
||
if (pDefault && pDefault->pDatatype) {
|
||
if (pDefault->pDatatype == (LPWSTR)-1) {
|
||
pDatatype = NULL;
|
||
dwFlags |= RESET_PRINTER_DATATYPE;
|
||
} else {
|
||
pDatatype = pDefault->pDatatype;
|
||
}
|
||
} else {
|
||
pDatatype = NULL;
|
||
}
|
||
|
||
DevModeContainer.cbBuf = 0;
|
||
DevModeContainer.pDevMode = NULL;
|
||
|
||
if( pDefault ){
|
||
|
||
if (pDefault->pDevMode == (LPDEVMODE)-1) {
|
||
|
||
dwFlags |= RESET_PRINTER_DEVMODE;
|
||
|
||
} else if( bValidDevModeW( pDefault->pDevMode )){
|
||
|
||
DevModeContainer.cbBuf = pDefault->pDevMode->dmSize +
|
||
pDefault->pDevMode->dmDriverExtra;
|
||
DevModeContainer.pDevMode = (LPBYTE)pDefault->pDevMode;
|
||
}
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcResetPrinterEx(pSpool->hPrinter,
|
||
pDatatype, &DevModeContainer,
|
||
dwFlags
|
||
)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
SetJobW(
|
||
HANDLE hPrinter,
|
||
DWORD JobId,
|
||
DWORD Level,
|
||
LPBYTE pJob,
|
||
DWORD Command
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
GENERIC_CONTAINER GenericContainer;
|
||
GENERIC_CONTAINER *pGenericContainer;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
|
||
switch (Level) {
|
||
|
||
case 0:
|
||
break;
|
||
|
||
case 1:
|
||
case 2:
|
||
case 3:
|
||
if (!pJob) {
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
return FALSE;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (pJob) {
|
||
|
||
GenericContainer.Level = Level;
|
||
GenericContainer.pData = pJob;
|
||
pGenericContainer = &GenericContainer;
|
||
|
||
} else
|
||
|
||
pGenericContainer = NULL;
|
||
|
||
if (ReturnValue = RpcSetJob(pSpool->hPrinter, JobId,
|
||
(JOB_CONTAINER *)pGenericContainer,
|
||
Command)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
GetJobW(
|
||
HANDLE hPrinter,
|
||
DWORD JobId,
|
||
DWORD Level,
|
||
LPBYTE pJob,
|
||
DWORD cbBuf,
|
||
LPDWORD pcbNeeded
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
DWORD *pOffsets;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
FlushBuffer(pSpool);
|
||
|
||
switch (Level) {
|
||
|
||
case 1:
|
||
pOffsets = JobInfo1Offsets;
|
||
break;
|
||
|
||
case 2:
|
||
pOffsets = JobInfo2Offsets;
|
||
break;
|
||
|
||
case 3:
|
||
pOffsets = JobInfo3Offsets;
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (pJob)
|
||
memset(pJob, 0, cbBuf);
|
||
|
||
if (ReturnValue = RpcGetJob(pSpool->hPrinter, JobId, Level, pJob, cbBuf,
|
||
pcbNeeded)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else {
|
||
|
||
MarshallUpStructure(pJob, pOffsets);
|
||
ReturnValue = TRUE;
|
||
}
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
|
||
BOOL
|
||
EnumJobsW(
|
||
HANDLE hPrinter,
|
||
DWORD FirstJob,
|
||
DWORD NoJobs,
|
||
DWORD Level,
|
||
LPBYTE pJob,
|
||
DWORD cbBuf,
|
||
LPDWORD pcbNeeded,
|
||
LPDWORD pcReturned
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
DWORD i, cbStruct, *pOffsets;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
|
||
FlushBuffer(pSpool);
|
||
|
||
switch (Level) {
|
||
|
||
case 1:
|
||
pOffsets = JobInfo1Offsets;
|
||
cbStruct = sizeof(JOB_INFO_1);
|
||
break;
|
||
|
||
case 2:
|
||
pOffsets = JobInfo2Offsets;
|
||
cbStruct = sizeof(JOB_INFO_2);
|
||
break;
|
||
|
||
case 3:
|
||
pOffsets = JobInfo3Offsets;
|
||
cbStruct = sizeof(JOB_INFO_3);
|
||
break;
|
||
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (pJob)
|
||
memset(pJob, 0, cbBuf);
|
||
|
||
if (ReturnValue = RpcEnumJobs(pSpool->hPrinter, FirstJob, NoJobs, Level, pJob,
|
||
cbBuf, pcbNeeded, pcReturned)) {
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else {
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
i=*pcReturned;
|
||
|
||
while (i--) {
|
||
|
||
MarshallUpStructure(pJob, pOffsets);
|
||
pJob += cbStruct;;
|
||
}
|
||
}
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
HANDLE
|
||
AddPrinterW(
|
||
LPWSTR pName,
|
||
DWORD Level,
|
||
LPBYTE pPrinter
|
||
)
|
||
{
|
||
DWORD ReturnValue;
|
||
PRINTER_CONTAINER PrinterContainer;
|
||
DEVMODE_CONTAINER DevModeContainer;
|
||
SECURITY_CONTAINER SecurityContainer;
|
||
HANDLE hPrinter;
|
||
PSPOOL pSpool = NULL;
|
||
PVOID pNewSecurityDescriptor = NULL;
|
||
SECURITY_DESCRIPTOR_CONTROL SecurityDescriptorControl = 0;
|
||
PPRINTER_INFO_2 pPrinterInfo = (PPRINTER_INFO_2)pPrinter;
|
||
|
||
switch (Level) {
|
||
|
||
case 2:
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return NULL;
|
||
}
|
||
|
||
if ( !pPrinter ) {
|
||
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
return NULL;
|
||
}
|
||
|
||
PrinterContainer.Level = Level;
|
||
PrinterContainer.PrinterInfo.pPrinterInfo1 = (PPRINTER_INFO_1)pPrinter;
|
||
|
||
DevModeContainer.cbBuf = 0;
|
||
DevModeContainer.pDevMode = NULL;
|
||
|
||
SecurityContainer.cbBuf = 0;
|
||
SecurityContainer.pSecurity = NULL;
|
||
|
||
if (Level == 2) {
|
||
|
||
if( bValidDevModeW( pPrinterInfo->pDevMode )){
|
||
|
||
DevModeContainer.cbBuf = pPrinterInfo->pDevMode->dmSize +
|
||
pPrinterInfo->pDevMode->dmDriverExtra;
|
||
DevModeContainer.pDevMode = (LPBYTE)pPrinterInfo->pDevMode;
|
||
}
|
||
|
||
if (pPrinterInfo->pSecurityDescriptor) {
|
||
|
||
DWORD sedlen = 0;
|
||
|
||
//
|
||
// We must construct a self relative security descriptor from
|
||
// whatever we get as input: If we get an Absolute SD we should
|
||
// convert it to a self-relative one. (this is a given) and we
|
||
// should also convert any self -relative input SD into a a new
|
||
// self relative security descriptor; this will take care of
|
||
// any holes in the Dacl or the Sacl in the self-relative sd
|
||
//
|
||
pNewSecurityDescriptor = BuildInputSD(
|
||
pPrinterInfo->pSecurityDescriptor,
|
||
&sedlen);
|
||
|
||
if (pNewSecurityDescriptor) {
|
||
SecurityContainer.cbBuf = sedlen;
|
||
SecurityContainer.pSecurity = pNewSecurityDescriptor;
|
||
}
|
||
}
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcAddPrinter(pName,
|
||
(PPRINTER_CONTAINER)&PrinterContainer,
|
||
(PDEVMODE_CONTAINER)&DevModeContainer,
|
||
(PSECURITY_CONTAINER)&SecurityContainer,
|
||
&hPrinter)) {
|
||
SetLastError(ReturnValue);
|
||
hPrinter = FALSE;
|
||
}
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
hPrinter = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
if (hPrinter) {
|
||
|
||
pSpool = AllocSplMem(sizeof(SPOOL));
|
||
|
||
if ( pSpool &&
|
||
( !DevModeContainer.pDevMode ||
|
||
WriteCurDevModeToRegistry(pPrinterInfo->pPrinterName,
|
||
(LPDEVMODEW)DevModeContainer.pDevMode)) ) {
|
||
|
||
pSpool->hPrinter = hPrinter;
|
||
pSpool->signature = SP_SIGNATURE;
|
||
pSpool->hFile = INVALID_HANDLE_VALUE;
|
||
|
||
InterlockedIncrement( &ClientHandleCount );
|
||
|
||
} else {
|
||
|
||
// BUGBUG MEMORY LEAK
|
||
// Doesn't free of pSpool on error path
|
||
|
||
RpcDeletePrinter(hPrinter);
|
||
RpcClosePrinter(&hPrinter);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Free Memory allocated for the SecurityDescriptor
|
||
//
|
||
|
||
if (pNewSecurityDescriptor) {
|
||
LocalFree(pNewSecurityDescriptor);
|
||
}
|
||
|
||
return pSpool;
|
||
}
|
||
|
||
BOOL
|
||
DeletePrinter(
|
||
HANDLE hPrinter
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
|
||
FlushBuffer(pSpool);
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcDeletePrinter(pSpool->hPrinter)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
SpoolerPrinterEvent(
|
||
LPWSTR pName,
|
||
INT PrinterEvent,
|
||
DWORD Flags,
|
||
LPARAM lParam
|
||
)
|
||
/*++
|
||
|
||
//
|
||
// Some printer drivers, like the FAX driver want to do per client
|
||
// initialization at the time a connection is established
|
||
// For example in the FAX case they want to push up UI to get all
|
||
// the client info - Name, Number etc.
|
||
// Or they might want to run Setup, in initialize some other components
|
||
// Thus on a successful conenction we call into the Printer Drivers UI
|
||
// DLL to give them this oportunity
|
||
//
|
||
// mattfe may 1 96
|
||
--*/
|
||
{
|
||
BOOL ReturnValue = FALSE;
|
||
HANDLE hPrinter;
|
||
HANDLE hModule;
|
||
INT_FARPROC pfn;
|
||
|
||
if (OpenPrinter((LPWSTR)pName, &hPrinter, NULL)) {
|
||
|
||
if (hModule = LoadPrinterDriver(hPrinter)) {
|
||
|
||
if (pfn = GetProcAddress(hModule, "DrvPrinterEvent")) {
|
||
|
||
try {
|
||
|
||
ReturnValue = (*pfn)( pName, PrinterEvent, Flags, lParam );
|
||
|
||
} except(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
|
||
}
|
||
}
|
||
|
||
FreeLibrary(hModule);
|
||
}
|
||
|
||
ClosePrinter(hPrinter);
|
||
}
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
BOOL
|
||
AddPrinterConnectionW(
|
||
LPWSTR pName
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
HANDLE hPrinter, hModule;
|
||
FARPROC pfn;
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcAddPrinterConnection(pName)) {
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
} else
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue=FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
if ( ReturnValue ) {
|
||
|
||
SpoolerPrinterEvent( pName, PRINTER_EVENT_ADD_CONNECTION, 0, (LPARAM)NULL );
|
||
}
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
DeletePrinterConnectionW(
|
||
LPWSTR pName
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
DWORD LastError;
|
||
|
||
SpoolerPrinterEvent( pName, PRINTER_EVENT_DELETE_CONNECTION, 0, (LPARAM)NULL );
|
||
|
||
RpcTryExcept {
|
||
|
||
if (LastError = RpcDeletePrinterConnection(pName)) {
|
||
SetLastError(LastError);
|
||
ReturnValue = FALSE;
|
||
} else
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue=FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
SetPrinterW(
|
||
HANDLE hPrinter,
|
||
DWORD Level,
|
||
LPBYTE pPrinter,
|
||
DWORD Command
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
PRINTER_CONTAINER PrinterContainer;
|
||
DEVMODE_CONTAINER DevModeContainer;
|
||
SECURITY_CONTAINER SecurityContainer;
|
||
PPRINTER_INFO_2 pPrinterInfo2;
|
||
PPRINTER_INFO_3 pPrinterInfo3;
|
||
PRINTER_INFO_6 PrinterInfo6;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
PVOID pNewSecurityDescriptor = NULL;
|
||
DWORD sedlen = 0;
|
||
DWORD dwSize = 0;
|
||
|
||
|
||
if ( !ValidatePrinterHandle(hPrinter) ) {
|
||
return(FALSE);
|
||
}
|
||
|
||
DevModeContainer.cbBuf = 0;
|
||
DevModeContainer.pDevMode = NULL;
|
||
|
||
SecurityContainer.cbBuf = 0;
|
||
SecurityContainer.pSecurity = NULL;
|
||
|
||
switch (Level) {
|
||
|
||
case STRESSINFOLEVEL:
|
||
|
||
//
|
||
// Internally we treat the Level 0, Command PRINTER_CONTROL_SET_STATUS
|
||
// as Level 6 since level 0 could be STRESS_INFO (for rpc)
|
||
//
|
||
if ( Command == PRINTER_CONTROL_SET_STATUS ) {
|
||
|
||
PrinterInfo6.dwStatus = (DWORD)pPrinter;
|
||
pPrinter = (LPBYTE)&PrinterInfo6;
|
||
Command = 0;
|
||
Level = 6;
|
||
}
|
||
break;
|
||
|
||
case 2:
|
||
|
||
pPrinterInfo2 = (PPRINTER_INFO_2)pPrinter;
|
||
|
||
if (pPrinterInfo2 == NULL) {
|
||
|
||
DBGMSG(DBG_TRACE, ("Error: SetPrinter pPrinterInfo2 is NULL\n"));
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
return FALSE;
|
||
}
|
||
|
||
if( bValidDevModeW( pPrinterInfo2->pDevMode )){
|
||
|
||
DevModeContainer.cbBuf = pPrinterInfo2->pDevMode->dmSize +
|
||
pPrinterInfo2->pDevMode->dmDriverExtra;
|
||
DevModeContainer.pDevMode = (LPBYTE)pPrinterInfo2->pDevMode;
|
||
}
|
||
|
||
if (pPrinterInfo2->pSecurityDescriptor) {
|
||
|
||
//
|
||
// We must construct a self relative security descriptor from
|
||
// whatever we get as input: If we get an Absolute SD we should
|
||
// convert it to a self-relative one. (this is a given) and we
|
||
// should also convert any self -relative input SD into a a new
|
||
// self relative security descriptor; this will take care of
|
||
// any holes in the Dacl or the Sacl in the self-relative sd
|
||
//
|
||
|
||
pNewSecurityDescriptor = BuildInputSD(pPrinterInfo2->pSecurityDescriptor,
|
||
&sedlen);
|
||
if (pNewSecurityDescriptor) {
|
||
SecurityContainer.cbBuf = sedlen;
|
||
SecurityContainer.pSecurity = pNewSecurityDescriptor;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case 3:
|
||
|
||
pPrinterInfo3 = (PPRINTER_INFO_3)pPrinter;
|
||
|
||
if (pPrinterInfo3 == NULL) {
|
||
|
||
DBGMSG(DBG_TRACE, ("Error: SetPrinter pPrinterInfo3 is NULL\n"));
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
return FALSE;
|
||
}
|
||
|
||
if (pPrinterInfo3->pSecurityDescriptor) {
|
||
|
||
//
|
||
// We must construct a self relative security descriptor from
|
||
// whatever we get as input: If we get an Absolute SD we should
|
||
// convert it to a self-relative one. (this is a given) and we
|
||
// should also convert any self -relative input SD into a a new
|
||
// self relative security descriptor; this will take care of
|
||
// any holes in the Dacl or the Sacl in the self-relative sd
|
||
//
|
||
|
||
pNewSecurityDescriptor = BuildInputSD(pPrinterInfo3->pSecurityDescriptor,
|
||
&sedlen);
|
||
if (pNewSecurityDescriptor) {
|
||
SecurityContainer.cbBuf = sedlen;
|
||
SecurityContainer.pSecurity = pNewSecurityDescriptor;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case 4:
|
||
case 5:
|
||
if ( pPrinter == NULL ) {
|
||
|
||
DBGMSG(DBG_TRACE,("Error SetPrinter pPrinter is NULL\n"));
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
return FALSE;
|
||
}
|
||
break;
|
||
|
||
case 6:
|
||
if ( pPrinter == NULL ) {
|
||
|
||
DBGMSG(DBG_TRACE,("Error SetPrinter pPrinter is NULL\n"));
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
return FALSE;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
PrinterContainer.Level = Level;
|
||
PrinterContainer.PrinterInfo.pPrinterInfo1 = (PPRINTER_INFO_1)pPrinter;
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcSetPrinter(pSpool->hPrinter,
|
||
(PPRINTER_CONTAINER)&PrinterContainer,
|
||
(PDEVMODE_CONTAINER)&DevModeContainer,
|
||
(PSECURITY_CONTAINER)&SecurityContainer,
|
||
Command)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
//
|
||
// Need to write DevMode to registry so that dos apps doing
|
||
// ExtDeviceMode can pick up the new devmode
|
||
//
|
||
if ( ReturnValue && Level == 2 && DevModeContainer.pDevMode ) {
|
||
|
||
(VOID)WriteCurDevModeToRegistry(pPrinterInfo2->pPrinterName,
|
||
(LPDEVMODEW)DevModeContainer.pDevMode);
|
||
}
|
||
|
||
|
||
//
|
||
// Did we allocate memory for a new self-relative SD?
|
||
// If we did, let's free it.
|
||
//
|
||
if (pNewSecurityDescriptor) {
|
||
LocalFree(pNewSecurityDescriptor);
|
||
}
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
GetPrinterW(
|
||
HANDLE hPrinter,
|
||
DWORD Level,
|
||
LPBYTE pPrinter,
|
||
DWORD cbBuf,
|
||
LPDWORD pcbNeeded
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
DWORD *pOffsets;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
|
||
switch (Level) {
|
||
|
||
case STRESSINFOLEVEL:
|
||
pOffsets = PrinterInfoStressOffsets;
|
||
break;
|
||
|
||
case 1:
|
||
pOffsets = PrinterInfo1Offsets;
|
||
break;
|
||
|
||
case 2:
|
||
pOffsets = PrinterInfo2Offsets;
|
||
break;
|
||
|
||
case 3:
|
||
pOffsets = PrinterInfo3Offsets;
|
||
break;
|
||
|
||
case 4:
|
||
pOffsets = PrinterInfo4Offsets;
|
||
break;
|
||
|
||
case 5:
|
||
pOffsets = PrinterInfo5Offsets;
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
if (pPrinter)
|
||
memset(pPrinter, 0, cbBuf);
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcGetPrinter(pSpool->hPrinter, Level, pPrinter, cbBuf, pcbNeeded)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else {
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
if (pPrinter) {
|
||
|
||
MarshallUpStructure(pPrinter, pOffsets);
|
||
}
|
||
|
||
}
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
AddPrinterDriverW(
|
||
LPWSTR pName,
|
||
DWORD Level,
|
||
PBYTE lpbDriverInfo
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
DRIVER_CONTAINER DriverContainer;
|
||
BOOL bDefaultEnvironmentUsed = FALSE;
|
||
LPRPC_DRIVER_INFO_3W pRpcDriverInfo3 = NULL;
|
||
DRIVER_INFO_3 *pDriverInfo3 = NULL;
|
||
LPWSTR pStr;
|
||
|
||
//
|
||
// Validate Input Parameters
|
||
//
|
||
if (!lpbDriverInfo) {
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
return(FALSE);
|
||
}
|
||
|
||
DriverContainer.Level = Level;
|
||
|
||
switch (Level) {
|
||
|
||
case 2:
|
||
|
||
if ( (((LPDRIVER_INFO_2)lpbDriverInfo)->pEnvironment == NULL ) ||
|
||
(*((LPDRIVER_INFO_2)lpbDriverInfo)->pEnvironment == L'\0') ) {
|
||
|
||
bDefaultEnvironmentUsed = TRUE;
|
||
((LPDRIVER_INFO_2)lpbDriverInfo)->pEnvironment = szEnvironment;
|
||
}
|
||
|
||
DriverContainer.DriverInfo.Level2 = (DRIVER_INFO_2 *)lpbDriverInfo;
|
||
|
||
break;
|
||
|
||
case 3:
|
||
|
||
if ( (((LPDRIVER_INFO_3)lpbDriverInfo)->pEnvironment == NULL ) ||
|
||
(*((LPDRIVER_INFO_3)lpbDriverInfo)->pEnvironment == L'\0') ) {
|
||
|
||
bDefaultEnvironmentUsed = TRUE;
|
||
((LPDRIVER_INFO_3)lpbDriverInfo)->pEnvironment = szEnvironment;
|
||
}
|
||
|
||
if ( !(pRpcDriverInfo3=AllocSplMem(sizeof(RPC_DRIVER_INFO_3W))) ) {
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
pDriverInfo3 = (DRIVER_INFO_3 *)lpbDriverInfo;
|
||
pRpcDriverInfo3->cVersion = pDriverInfo3->cVersion;
|
||
pRpcDriverInfo3->pName = pDriverInfo3->pName;
|
||
pRpcDriverInfo3->pEnvironment = pDriverInfo3->pEnvironment;
|
||
pRpcDriverInfo3->pDriverPath = pDriverInfo3->pDriverPath;
|
||
pRpcDriverInfo3->pDataFile = pDriverInfo3->pDataFile;
|
||
pRpcDriverInfo3->pConfigFile = pDriverInfo3->pConfigFile;
|
||
pRpcDriverInfo3->pHelpFile = pDriverInfo3->pHelpFile;
|
||
pRpcDriverInfo3->pDependentFiles = pDriverInfo3->pDependentFiles;
|
||
pRpcDriverInfo3->pMonitorName = pDriverInfo3->pMonitorName;
|
||
pRpcDriverInfo3->pDefaultDataType = pDriverInfo3->pDefaultDataType;
|
||
|
||
pStr = pDriverInfo3->pDependentFiles;
|
||
if ( pStr && *pStr ) {
|
||
|
||
while ( *pStr ) {
|
||
|
||
pStr += wcslen(pStr) + 1;
|
||
}
|
||
pRpcDriverInfo3->cchDependentFiles = pStr - pDriverInfo3->pDependentFiles + 1;
|
||
} else {
|
||
|
||
pRpcDriverInfo3->cchDependentFiles = 0;
|
||
}
|
||
|
||
DriverContainer.DriverInfo.Level3 = pRpcDriverInfo3;
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcAddPrinterDriver(pName, &DriverContainer)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else {
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
}
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
if (bDefaultEnvironmentUsed) {
|
||
if ( Level == 2 )
|
||
((LPDRIVER_INFO_2)lpbDriverInfo)->pEnvironment = NULL;
|
||
else //Level == 3
|
||
((LPDRIVER_INFO_3)lpbDriverInfo)->pEnvironment = NULL;
|
||
}
|
||
|
||
if ( pRpcDriverInfo3 ) {
|
||
FreeSplMem(pRpcDriverInfo3);
|
||
}
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
EnumPrinterDriversW(
|
||
LPWSTR pName,
|
||
LPWSTR pEnvironment,
|
||
DWORD Level,
|
||
LPBYTE pDriverInfo,
|
||
DWORD cbBuf,
|
||
LPDWORD pcbNeeded,
|
||
LPDWORD pcReturned
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
DWORD i, cbStruct;
|
||
DWORD *pOffsets;
|
||
|
||
switch (Level) {
|
||
|
||
case 1:
|
||
pOffsets = DriverInfo1Offsets;
|
||
cbStruct = sizeof(DRIVER_INFO_1);
|
||
break;
|
||
|
||
case 2:
|
||
pOffsets = DriverInfo2Offsets;
|
||
cbStruct = sizeof(DRIVER_INFO_2);
|
||
break;
|
||
|
||
case 3:
|
||
pOffsets = DriverInfo3Offsets;
|
||
cbStruct = sizeof(DRIVER_INFO_3);
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (!pEnvironment || !*pEnvironment)
|
||
pEnvironment = szEnvironment;
|
||
|
||
if (ReturnValue = RpcEnumPrinterDrivers(pName, pEnvironment, Level,
|
||
pDriverInfo, cbBuf,
|
||
pcbNeeded, pcReturned)) {
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else {
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
if (pDriverInfo) {
|
||
|
||
i = *pcReturned;
|
||
|
||
while (i--) {
|
||
|
||
MarshallUpStructure(pDriverInfo, pOffsets);
|
||
pDriverInfo += cbStruct;
|
||
}
|
||
}
|
||
}
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
GetPrinterDriverW(
|
||
HANDLE hPrinter,
|
||
LPWSTR pEnvironment,
|
||
DWORD Level,
|
||
LPBYTE pDriverInfo,
|
||
DWORD cbBuf,
|
||
LPDWORD pcbNeeded
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
DWORD *pOffsets;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
DWORD dwServerMajorVersion;
|
||
DWORD dwServerMinorVersion;
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
switch (Level) {
|
||
|
||
case 1:
|
||
pOffsets = DriverInfo1Offsets;
|
||
break;
|
||
|
||
case 2:
|
||
pOffsets = DriverInfo2Offsets;
|
||
break;
|
||
|
||
case 3:
|
||
pOffsets = DriverInfo3Offsets;
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (pDriverInfo)
|
||
memset(pDriverInfo, 0, cbBuf);
|
||
|
||
if (!pEnvironment || !*pEnvironment)
|
||
pEnvironment = szEnvironment;
|
||
|
||
if (ReturnValue = RpcGetPrinterDriver2(pSpool->hPrinter, pEnvironment,
|
||
Level, pDriverInfo, cbBuf,
|
||
pcbNeeded,
|
||
(DWORD)-1, (DWORD)-1,
|
||
&dwServerMajorVersion,
|
||
&dwServerMinorVersion
|
||
)) {
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else {
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
if (pDriverInfo) {
|
||
MarshallUpStructure(pDriverInfo, pOffsets);
|
||
}
|
||
}
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
GetPrinterDriverDirectoryW(
|
||
LPWSTR pName,
|
||
LPWSTR pEnvironment,
|
||
DWORD Level,
|
||
LPBYTE pDriverDirectory,
|
||
DWORD cbBuf,
|
||
LPDWORD pcbNeeded
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
|
||
switch (Level) {
|
||
|
||
case 1:
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (!pEnvironment || !*pEnvironment)
|
||
pEnvironment = szEnvironment;
|
||
|
||
if (ReturnValue = RpcGetPrinterDriverDirectory(pName, pEnvironment,
|
||
Level,
|
||
pDriverDirectory,
|
||
cbBuf, pcbNeeded)) {
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else {
|
||
|
||
ReturnValue = TRUE;
|
||
}
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
DeletePrinterDriverW(
|
||
LPWSTR pName,
|
||
LPWSTR pEnvironment,
|
||
LPWSTR pDriverName
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
|
||
if (!pDriverName || !*pDriverName) {
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
return (FALSE);
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (!pEnvironment || !*pEnvironment)
|
||
pEnvironment = szEnvironment;
|
||
|
||
if (ReturnValue = RpcDeletePrinterDriver(pName,
|
||
pEnvironment,
|
||
pDriverName)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
AddPrintProcessorW(
|
||
LPWSTR pName,
|
||
LPWSTR pEnvironment,
|
||
LPWSTR pPathName,
|
||
LPWSTR pPrintProcessorName
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
|
||
if (!pPrintProcessorName || !*pPrintProcessorName) {
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
if (!pPathName || !*pPathName) {
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
return FALSE;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (!pEnvironment || !*pEnvironment)
|
||
pEnvironment = szEnvironment;
|
||
|
||
if (ReturnValue = RpcAddPrintProcessor(pName, pEnvironment, pPathName,
|
||
pPrintProcessorName)) {
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
EnumPrintProcessorsW(
|
||
LPWSTR pName,
|
||
LPWSTR pEnvironment,
|
||
DWORD Level,
|
||
LPBYTE pPrintProcessorInfo,
|
||
DWORD cbBuf,
|
||
LPDWORD pcbNeeded,
|
||
LPDWORD pcReturned
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
DWORD i, cbStruct;
|
||
DWORD *pOffsets;
|
||
|
||
switch (Level) {
|
||
|
||
case 1:
|
||
pOffsets = PrintProcessorInfo1Offsets;
|
||
cbStruct = sizeof(PRINTPROCESSOR_INFO_1);
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (!pEnvironment || !*pEnvironment)
|
||
pEnvironment = szEnvironment;
|
||
|
||
if (ReturnValue = RpcEnumPrintProcessors(pName, pEnvironment, Level,
|
||
pPrintProcessorInfo, cbBuf,
|
||
pcbNeeded, pcReturned)) {
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else {
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
if (pPrintProcessorInfo) {
|
||
|
||
i = *pcReturned;
|
||
|
||
while (i--) {
|
||
|
||
MarshallUpStructure(pPrintProcessorInfo, pOffsets);
|
||
|
||
pPrintProcessorInfo += cbStruct;
|
||
}
|
||
}
|
||
}
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
GetPrintProcessorDirectoryW(
|
||
LPWSTR pName,
|
||
LPWSTR pEnvironment,
|
||
DWORD Level,
|
||
LPBYTE pPrintProcessorInfo,
|
||
DWORD cbBuf,
|
||
LPDWORD pcbNeeded
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
|
||
switch (Level) {
|
||
|
||
case 1:
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (!pEnvironment || !*pEnvironment)
|
||
pEnvironment = szEnvironment;
|
||
|
||
if (ReturnValue = RpcGetPrintProcessorDirectory(pName, pEnvironment,
|
||
Level,
|
||
pPrintProcessorInfo,
|
||
cbBuf, pcbNeeded)) {
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else {
|
||
|
||
ReturnValue = TRUE;
|
||
}
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
EnumPrintProcessorDatatypesW(
|
||
LPWSTR pName,
|
||
LPWSTR pPrintProcessorName,
|
||
DWORD Level,
|
||
LPBYTE pDatatypes,
|
||
DWORD cbBuf,
|
||
LPDWORD pcbNeeded,
|
||
LPDWORD pcReturned
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
DWORD i, cbStruct;
|
||
DWORD *pOffsets;
|
||
|
||
switch (Level) {
|
||
|
||
case 1:
|
||
pOffsets = PrintProcessorInfo1Offsets;
|
||
cbStruct = sizeof(DATATYPES_INFO_1);
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcEnumPrintProcessorDatatypes(pName,
|
||
pPrintProcessorName,
|
||
Level,
|
||
pDatatypes,
|
||
cbBuf,
|
||
pcbNeeded,
|
||
pcReturned)) {
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else {
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
if (pDatatypes) {
|
||
|
||
i = *pcReturned;
|
||
|
||
while (i--) {
|
||
|
||
MarshallUpStructure(pDatatypes, pOffsets);
|
||
|
||
pDatatypes += cbStruct;
|
||
}
|
||
}
|
||
}
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
|
||
DWORD
|
||
StartDocPrinterW(
|
||
HANDLE hPrinter,
|
||
DWORD Level,
|
||
LPBYTE pDocInfo
|
||
)
|
||
{
|
||
BOOL ReturnValue = FALSE;
|
||
BOOL EverythingWorked = FALSE;
|
||
BOOL PrintingToFile = FALSE;
|
||
GENERIC_CONTAINER DocInfoContainer;
|
||
DWORD JobId, cbNeeded, cbIgnore;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
BYTE Data[1024];
|
||
PADDJOB_INFO_1 pAddJob = (PADDJOB_INFO_1)Data;
|
||
PJOB_INFO_1 pJob;
|
||
PDOC_INFO_1 pDocInfo1 = (PDOC_INFO_1)pDocInfo;
|
||
WCHAR FullPathName[MAX_PATH];
|
||
|
||
try {
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return 0;
|
||
}
|
||
|
||
if ( pSpool->Status & SPOOL_STATUS_STARTDOC ) {
|
||
|
||
SetLastError(ERROR_INVALID_PRINTER_STATE);
|
||
return 0;
|
||
}
|
||
DBGMSG(DBG_TRACE,("Entered StartDocPrinterW client side hPrinter = %x\n", hPrinter));
|
||
switch (Level) {
|
||
|
||
case 1:
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return 0;
|
||
}
|
||
|
||
//
|
||
// Earlier on, if we had a non-null string, we assumed it to be printing to file. Print to file will not
|
||
// go thru the client-side optimization code. Now gdi is passing us pOutputFile name irrespective of
|
||
// whether it is file or not. We must determine if pOutputFile is really a file name
|
||
//
|
||
|
||
|
||
if (pDocInfo1->pOutputFile && (*(pDocInfo1->pOutputFile) != L'\0') && IsaFileName(pDocInfo1->pOutputFile, FullPathName))
|
||
PrintingToFile = TRUE;
|
||
|
||
|
||
if (!PrintingToFile && AddJobW(hPrinter, 1, Data, sizeof(Data), &cbNeeded)) {
|
||
pSpool->JobId = pAddJob->JobId;
|
||
pSpool->hFile = CreateFile(pAddJob->Path, GENERIC_WRITE,
|
||
FILE_SHARE_READ, NULL, CREATE_ALWAYS,
|
||
FILE_ATTRIBUTE_NORMAL |
|
||
FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
||
|
||
if (pSpool->hFile != INVALID_HANDLE_VALUE) {
|
||
|
||
if (pSpool->JobId == (DWORD)-1) {
|
||
|
||
IO_STATUS_BLOCK Iosb;
|
||
NTSTATUS Status;
|
||
QUERY_PRINT_JOB_INFO JobInfo;
|
||
|
||
Status = NtFsControlFile(pSpool->hFile, NULL, NULL, NULL,
|
||
&Iosb,
|
||
FSCTL_GET_PRINT_ID,
|
||
NULL, 0,
|
||
&JobInfo, sizeof(JobInfo));
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
pSpool->JobId = JobInfo.JobId;
|
||
}
|
||
}
|
||
|
||
if (!GetJob(hPrinter, pSpool->JobId, 1, NULL, 0, &cbNeeded)) {
|
||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||
pJob = AllocSplMem(cbNeeded);
|
||
if (pJob) {
|
||
if (GetJob(hPrinter, pSpool->JobId, 1,
|
||
(LPBYTE)pJob, cbNeeded, &cbIgnore)) {
|
||
pJob->pDocument = pDocInfo1->pDocName;
|
||
if (pDocInfo1->pDatatype)
|
||
pJob->pDatatype = pDocInfo1->pDatatype;
|
||
pJob->Position = JOB_POSITION_UNSPECIFIED;
|
||
if (SetJob(hPrinter, pSpool->JobId, 1,
|
||
(LPBYTE)pJob, 0)) {
|
||
EverythingWorked = TRUE;
|
||
}
|
||
}
|
||
|
||
FreeSplMem(pJob);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!PrintingToFile && !EverythingWorked) {
|
||
|
||
if (pSpool->hFile != INVALID_HANDLE_VALUE)
|
||
CloseHandle(pSpool->hFile);
|
||
|
||
SetJob(hPrinter,pSpool->JobId, 0, NULL, JOB_CONTROL_CANCEL);
|
||
ScheduleJob(hPrinter, pSpool->JobId);
|
||
pSpool->hFile = INVALID_HANDLE_VALUE;
|
||
pSpool->JobId = 0;
|
||
}
|
||
}
|
||
|
||
if (EverythingWorked) {
|
||
ReturnValue = pSpool->JobId;
|
||
|
||
} else {
|
||
|
||
//
|
||
// If it's invalid datatype, fail immediately instead of trying
|
||
// StartDocPrinter.
|
||
//
|
||
if( GetLastError() == ERROR_INVALID_DATATYPE ){
|
||
return 0;
|
||
}
|
||
|
||
pSpool->hFile = INVALID_HANDLE_VALUE;
|
||
pSpool->JobId = 0;
|
||
|
||
DocInfoContainer.Level = Level;
|
||
DocInfoContainer.pData = pDocInfo;
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcStartDocPrinter(pSpool->hPrinter,
|
||
(LPDOC_INFO_CONTAINER)&DocInfoContainer,
|
||
&JobId)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = 0;
|
||
|
||
} else
|
||
|
||
ReturnValue = JobId;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = 0;
|
||
|
||
} RpcEndExcept
|
||
}
|
||
|
||
if (ReturnValue) {
|
||
pSpool->Status |= SPOOL_STATUS_STARTDOC;
|
||
}
|
||
|
||
//
|
||
// If the tray icon has not been notified, then do so now. Set
|
||
// the flag so that we won't call it multiple times.
|
||
//
|
||
if( ReturnValue && !( pSpool->Status & SPOOL_STATUS_TRAYICON_NOTIFIED )){
|
||
vUpdateTrayIcon( hPrinter, ReturnValue );
|
||
}
|
||
|
||
} except (1) {
|
||
|
||
SetLastError(TranslateExceptionCode(GetExceptionCode()));
|
||
ReturnValue = 0;
|
||
}
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
StartPagePrinter(
|
||
HANDLE hPrinter
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
try {
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
|
||
FlushBuffer(pSpool);
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcStartPagePrinter(pSpool->hPrinter)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
} except (1) {
|
||
|
||
SetLastError(ERROR_INVALID_HANDLE);
|
||
return(FALSE);
|
||
}
|
||
}
|
||
|
||
BOOL
|
||
FlushBuffer(
|
||
PSPOOL pSpool
|
||
)
|
||
{
|
||
DWORD ReturnValue = TRUE;
|
||
DWORD cbWritten = 0;
|
||
|
||
|
||
SPLASSERT (pSpool != NULL);
|
||
SPLASSERT (pSpool->signature == SP_SIGNATURE);
|
||
|
||
DBGMSG(DBG_TRACE, ("FlushBuffer - pSpool %x\n",pSpool));
|
||
|
||
if (pSpool->cbBuffer) {
|
||
|
||
SPLASSERT(pSpool->pBuffer != NULL);
|
||
|
||
DBGMSG(DBG_TRACE, ("FlushBuffer - Number Cached WritePrinters before Flush %d\n", pSpool->cCacheWrite));
|
||
pSpool->cCacheWrite = 0;
|
||
pSpool->cFlushBuffers++;
|
||
|
||
if (pSpool->hFile != INVALID_HANDLE_VALUE) {
|
||
|
||
// FileIO
|
||
|
||
ReturnValue = WriteFile( pSpool->hFile,
|
||
pSpool->pBuffer,
|
||
pSpool->cbBuffer,
|
||
&cbWritten, NULL);
|
||
|
||
DBGMSG(DBG_TRACE, ("FlushBuffer - WriteFile pSpool %x hFile %x pBuffer %x cbBuffer %d cbWritten %d\n",
|
||
pSpool, pSpool->hFile, pSpool->pBuffer, pSpool->cbBuffer, cbWritten));
|
||
|
||
} else {
|
||
|
||
// RPC IO
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcWritePrinter(pSpool->hPrinter,
|
||
pSpool->pBuffer,
|
||
pSpool->cbBuffer,
|
||
&cbWritten)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
DBGMSG(DBG_WARNING, ("FlushBuffer - RpcWritePrinter Failed Error %d\n",GetLastError() ));
|
||
|
||
} else {
|
||
ReturnValue = TRUE;
|
||
DBGMSG(DBG_TRACE, ("FlushBuffer - RpcWritePrinter Success hPrinter %x pBuffer %x cbBuffer %x cbWritten %x\n",
|
||
pSpool->hPrinter, pSpool->pBuffer,
|
||
pSpool->cbBuffer, cbWritten));
|
||
|
||
}
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
DBGMSG(DBG_WARNING, ("RpcWritePrinter Exception Error %d\n",GetLastError()));
|
||
|
||
} RpcEndExcept
|
||
|
||
}
|
||
|
||
if (pSpool->cbBuffer <= cbWritten) {
|
||
|
||
if ( pSpool->cbBuffer < cbWritten) {
|
||
|
||
// BUGBUG
|
||
// The following case should NEVER EVER happen this needs to be
|
||
// debugged further, however we need to ship Daytona
|
||
// we were seeing it daily during stress before we shipped.
|
||
//
|
||
// MATTFE Sept 2 1994
|
||
|
||
DBGMSG( DBG_WARNING, ("FlushBuffer cbBuffer %d < cbWritten %d ReturnValue %x LastError %d\n",
|
||
pSpool->cbBuffer, cbWritten, ReturnValue, GetLastError() ));
|
||
}
|
||
|
||
// Successful IO
|
||
// Empty the cache buffer count
|
||
|
||
pSpool->cbBuffer = 0;
|
||
|
||
} else if ( cbWritten != 0 ) {
|
||
|
||
// Partial IO
|
||
// Adjust the buffer so it contains the data that was not
|
||
// written
|
||
|
||
SPLASSERT(pSpool->cbBuffer <= BUFFER_SIZE);
|
||
SPLASSERT(cbWritten <= BUFFER_SIZE);
|
||
SPLASSERT(pSpool->cbBuffer >= cbWritten);
|
||
|
||
DBGMSG(DBG_WARNING, ("Partial IO adjusting buffer data\n"));
|
||
|
||
MoveMemory(pSpool->pBuffer,
|
||
pSpool->pBuffer + cbWritten,
|
||
BUFFER_SIZE - cbWritten);
|
||
|
||
pSpool->cbBuffer -= cbWritten;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
DBGMSG(DBG_TRACE, ("FlushBuffer returns %d\n",ReturnValue));
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
|
||
BOOL
|
||
WritePrinter(
|
||
HANDLE hPrinter,
|
||
LPVOID pBuf,
|
||
DWORD cbBuf,
|
||
LPDWORD pcWritten
|
||
)
|
||
{
|
||
BOOL ReturnValue=TRUE;
|
||
DWORD cb;
|
||
DWORD cbWritten = 0;
|
||
DWORD cTotalWritten = 0;
|
||
LPBYTE pBuffer = pBuf;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
PJOB_INFO_1 pJob;
|
||
DWORD cbNeeded;
|
||
DWORD dwTickCount, dwTickCount1;
|
||
|
||
DBGMSG(DBG_TRACE, ("WritePrinter - hPrinter %x pBuf %x cbBuf %d pcWritten %x\n",
|
||
hPrinter, pBuf, cbBuf, pcWritten));
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
|
||
*pcWritten = 0;
|
||
|
||
if ( !(pSpool->Status & SPOOL_STATUS_STARTDOC) ) {
|
||
|
||
SetLastError(ERROR_SPL_NO_STARTDOC);
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
|
||
// Check if local job is cancelled every JOB_CANCEL_CHECK_INTERVAL bytes
|
||
if (!pSpool->cWritePrinters) {
|
||
pSpool->dwTickCount = GetTickCount();
|
||
pSpool->dwCheckJobInterval = JOB_CANCEL_CHECK_INTERVAL;
|
||
}
|
||
|
||
if ( pSpool->hFile != INVALID_HANDLE_VALUE &&
|
||
pSpool->dwTickCount + pSpool->dwCheckJobInterval < (dwTickCount = GetTickCount())) {
|
||
|
||
if (!(ReturnValue = GetJob((HANDLE) pSpool, pSpool->JobId, 1, NULL, 0, &cbNeeded)) &&
|
||
(GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
|
||
|
||
pJob = AllocSplMem(cbNeeded);
|
||
|
||
if (pJob && (ReturnValue = GetJob((HANDLE) pSpool, pSpool->JobId, 1, (LPBYTE)pJob, cbNeeded, &cbNeeded))) {
|
||
|
||
// Don't allow GetJob calls to take more than 1% pSpool->dwCheckJobInterval
|
||
dwTickCount1 = GetTickCount();
|
||
|
||
if (dwTickCount1 > dwTickCount + (pSpool->dwCheckJobInterval/100)) {
|
||
|
||
pSpool->dwCheckJobInterval *= 2;
|
||
|
||
} else if (dwTickCount1 - dwTickCount < JOB_CANCEL_CHECK_INTERVAL/100) {
|
||
|
||
pSpool->dwCheckJobInterval = JOB_CANCEL_CHECK_INTERVAL;
|
||
|
||
}
|
||
|
||
|
||
if (!pJob->pStatus && (pJob->Status & JOB_STATUS_DELETING)) {
|
||
SetLastError(ERROR_PRINT_CANCELLED);
|
||
FreeSplMem(pJob);
|
||
return FALSE;
|
||
}
|
||
FreeSplMem(pJob);
|
||
}
|
||
}
|
||
pSpool->dwTickCount = GetTickCount();
|
||
}
|
||
|
||
pSpool->cWritePrinters++;
|
||
|
||
// WritePrinter will cache on the client side all IO's
|
||
// into BUFFER_SIZE writes. This is done to minimize
|
||
// the number of RPC calls if the app is doing a lot of small
|
||
// sized IO's.
|
||
|
||
while (cbBuf && ReturnValue) {
|
||
|
||
// Special Case FileIO's since file system prefers large
|
||
// writes, RPC is optimal with smaller writes.
|
||
|
||
if ((pSpool->hFile != INVALID_HANDLE_VALUE) &&
|
||
(pSpool->cbBuffer == 0) &&
|
||
(cbBuf > BUFFER_SIZE)) {
|
||
|
||
ReturnValue = WriteFile(pSpool->hFile, pBuffer, cbBuf, &cbWritten, NULL);
|
||
|
||
DBGMSG(DBG_TRACE, ("WritePrinter - WriteFile pSpool %x hFile %x pBuffer %x cbBuffer %d cbWritten %d\n",
|
||
pSpool, pSpool->hFile, pBuffer, pSpool->cbBuffer, *pcWritten));
|
||
|
||
|
||
} else {
|
||
|
||
// Fill cache buffer so IO is optimal size.
|
||
|
||
SPLASSERT(pSpool->cbBuffer <= BUFFER_SIZE);
|
||
|
||
cb = min((BUFFER_SIZE - pSpool->cbBuffer), cbBuf);
|
||
|
||
if (cb != 0) {
|
||
if (pSpool->pBuffer == NULL) {
|
||
pSpool->pBuffer = VirtualAlloc(NULL, BUFFER_SIZE, MEM_COMMIT, PAGE_READWRITE);
|
||
if (pSpool->pBuffer == NULL) {
|
||
DBGMSG(DBG_WARNING, ("VirtualAlloc Failed to allocate 4k buffer %d\n",GetLastError()));
|
||
return FALSE;
|
||
}
|
||
}
|
||
CopyMemory( pSpool->pBuffer + pSpool->cbBuffer, pBuffer, cb);
|
||
pSpool->cbBuffer += cb;
|
||
cbWritten = cb;
|
||
pSpool->cCacheWrite++;
|
||
}
|
||
|
||
if (pSpool->cbBuffer == BUFFER_SIZE) {
|
||
ReturnValue = FlushBuffer(pSpool);
|
||
}
|
||
}
|
||
|
||
// Update Total Byte Count after the Flush or File IO
|
||
// This is done because the IO might fail and thus
|
||
// the correct value written might have changed.
|
||
|
||
SPLASSERT(cbBuf >= cbWritten);
|
||
|
||
cbBuf -= cbWritten;
|
||
pBuffer += cbWritten;
|
||
cTotalWritten += cbWritten;
|
||
|
||
}
|
||
|
||
// Return the number of bytes written.
|
||
|
||
*pcWritten = cTotalWritten;
|
||
|
||
DBGMSG(DBG_TRACE, ("WritePrinter cbWritten %d ReturnValue %d\n",*pcWritten, ReturnValue));
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
EndPagePrinter(
|
||
HANDLE hPrinter
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
try {
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
|
||
FlushBuffer(pSpool);
|
||
|
||
if (pSpool->hFile != INVALID_HANDLE_VALUE)
|
||
return TRUE;
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcEndPagePrinter(pSpool->hPrinter)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
} except (1) {
|
||
|
||
SetLastError(ERROR_INVALID_HANDLE);
|
||
return(FALSE);
|
||
}
|
||
}
|
||
|
||
BOOL
|
||
AbortPrinter(
|
||
HANDLE hPrinter
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
DWORD dwNumWritten = 0;
|
||
DWORD dwPointer = 0;
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)){
|
||
return(FALSE);
|
||
}
|
||
|
||
//
|
||
// No longer in StartDoc mode; also resetting the tray icon notification
|
||
// flag so that upcoming StartDocPrinter/AddJobs indicate a new job.
|
||
//
|
||
pSpool->Status &= ~(SPOOL_STATUS_STARTDOC|SPOOL_STATUS_TRAYICON_NOTIFIED);
|
||
|
||
if (pSpool->hFile != INVALID_HANDLE_VALUE) {
|
||
|
||
if (pSpool->Status & SPOOL_STATUS_ADDJOB) {
|
||
|
||
// Close your handle to the .SPL file, otherwise the
|
||
// DeleteJob will fail in the Spooler
|
||
|
||
if (pSpool->hFile) {
|
||
if (CloseHandle(pSpool->hFile)){
|
||
pSpool->hFile = INVALID_HANDLE_VALUE;
|
||
}
|
||
}
|
||
|
||
if (!SetJob(hPrinter,pSpool->JobId, 0, NULL, JOB_CONTROL_DELETE)) {
|
||
DBGMSG(DBG_WARNING, ("Error: SetJob cancel returned failure with %d\n", GetLastError()));
|
||
// return FALSE;
|
||
}
|
||
|
||
return (ScheduleJob(hPrinter, pSpool->JobId));
|
||
} else {
|
||
DBGMSG(DBG_WARNING, ("Error: pSpool->hFile != INVALID_HANDLE_VALUE and pSpool's status is not SPOOL_STATUS_ADDJOB\n"));
|
||
}
|
||
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcAbortPrinter(pSpool->hPrinter)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
ReadPrinter(
|
||
HANDLE hPrinter,
|
||
LPVOID pBuf,
|
||
DWORD cbBuf,
|
||
LPDWORD pNoBytesRead
|
||
)
|
||
{
|
||
BOOL ReturnValue=TRUE;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
|
||
FlushBuffer(pSpool);
|
||
|
||
|
||
if (pSpool->hFile != INVALID_HANDLE_VALUE) {
|
||
SetLastError(ERROR_INVALID_HANDLE);
|
||
return FALSE;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
cbBuf = min(BUFFER_SIZE, cbBuf);
|
||
|
||
if (ReturnValue = RpcReadPrinter(pSpool->hPrinter, pBuf, cbBuf, pNoBytesRead)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
EndDocPrinter(
|
||
HANDLE hPrinter
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
try {
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
|
||
FlushBuffer(pSpool);
|
||
|
||
//
|
||
// No longer in StartDoc mode; also resetting the tray icon
|
||
// notification flag so that upcoming StartDocPrinter/AddJobs
|
||
// indicate a new job.
|
||
//
|
||
pSpool->Status &= ~(SPOOL_STATUS_STARTDOC|SPOOL_STATUS_TRAYICON_NOTIFIED);
|
||
|
||
if (pSpool->hFile != INVALID_HANDLE_VALUE) {
|
||
|
||
CloseHandle(pSpool->hFile);
|
||
ReturnValue = ScheduleJob(hPrinter, pSpool->JobId);
|
||
pSpool->hFile = INVALID_HANDLE_VALUE;
|
||
pSpool->Status &= ~SPOOL_STATUS_ADDJOB;
|
||
|
||
DBGMSG(DBG_TRACE, ("Exit EndDocPrinter - client side hPrinter %x\n", hPrinter));
|
||
return ReturnValue;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcEndDocPrinter(pSpool->hPrinter)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
DBGMSG(DBG_TRACE, ("Exit EndDocPrinter - client side hPrinter %x\n", hPrinter));
|
||
|
||
return ReturnValue;
|
||
} except (1) {
|
||
SetLastError(ERROR_INVALID_HANDLE);
|
||
return(FALSE);
|
||
}
|
||
}
|
||
|
||
BOOL
|
||
AddJobW(
|
||
HANDLE hPrinter,
|
||
DWORD Level,
|
||
LPBYTE pData,
|
||
DWORD cbBuf,
|
||
LPDWORD pcbNeeded
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
try {
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
|
||
switch (Level) {
|
||
|
||
case 1:
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcAddJob(pSpool->hPrinter, Level, pData,
|
||
cbBuf, pcbNeeded)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else {
|
||
|
||
MarshallUpStructure(pData, AddJobOffsets);
|
||
pSpool->Status |= SPOOL_STATUS_ADDJOB;
|
||
ReturnValue = TRUE;
|
||
}
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
if( ReturnValue ){
|
||
|
||
//
|
||
// Notify the tray icon that a new job has been sent.
|
||
//
|
||
vUpdateTrayIcon( hPrinter, ((PADDJOB_INFO_1)pData)->JobId );
|
||
}
|
||
|
||
return ReturnValue;
|
||
} except (1) {
|
||
SetLastError(TranslateExceptionCode(GetExceptionCode()));
|
||
return(FALSE);
|
||
}
|
||
}
|
||
|
||
BOOL
|
||
ScheduleJob(
|
||
HANDLE hPrinter,
|
||
DWORD JobId
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
try {
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
|
||
//
|
||
// The job has been scheduled, so reset the flag that indicates
|
||
// the tray icon has been notified. Any new AddJob/StartDocPrinter/
|
||
// StartDoc events should send a new notification, since it's really
|
||
// a new job.
|
||
//
|
||
pSpool->Status &= ~SPOOL_STATUS_TRAYICON_NOTIFIED;
|
||
|
||
FlushBuffer(pSpool);
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcScheduleJob(pSpool->hPrinter, JobId)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else {
|
||
|
||
pSpool->Status &= ~SPOOL_STATUS_ADDJOB;
|
||
ReturnValue = TRUE;
|
||
}
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
} except (1) {
|
||
SetLastError(TranslateExceptionCode(GetExceptionCode()));
|
||
return(FALSE);
|
||
}
|
||
}
|
||
|
||
BOOL
|
||
PrinterProperties(
|
||
HWND hWnd,
|
||
HANDLE hPrinter
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is main PrinterProperties entri point and will call into the
|
||
our DevicePropertySheets() for UI pop up
|
||
|
||
|
||
Arguments:
|
||
|
||
hWnd - Handle to the window parent
|
||
|
||
hPrinter - Handle to the printer interested
|
||
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is TRUE.
|
||
If the function fails, the return value is FALSE.
|
||
To get extended error information, call GetLastError.
|
||
|
||
Author:
|
||
|
||
13-Jun-1996 Thu 15:22:36 created -by- Daniel Chou (danielc)
|
||
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PRINTER_INFO_2 *pPI2 = NULL;
|
||
DEVICEPROPERTYHEADER DPHdr;
|
||
LONG Result;
|
||
DWORD cb;
|
||
DWORD dwValue = 1;
|
||
|
||
//
|
||
// Ensure the printer handle is valid
|
||
//
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
|
||
DPHdr.cbSize = sizeof(DPHdr);
|
||
DPHdr.hPrinter = hPrinter;
|
||
DPHdr.Flags = DPS_NOPERMISSION;
|
||
|
||
//
|
||
// Do a GetPrinter() level2 to get the printer name.
|
||
//
|
||
if ((!GetPrinter(hPrinter, 2, NULL, 0, &cb)) &&
|
||
(GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
|
||
(pPI2 = (PPRINTER_INFO_2)LocalAlloc(LMEM_FIXED, cb)) &&
|
||
(GetPrinter(hPrinter, 2, (LPBYTE)pPI2, cb, &cb))) {
|
||
|
||
//
|
||
// Set the printer name.
|
||
//
|
||
DPHdr.pszPrinterName = pPI2->pPrinterName;
|
||
|
||
} else {
|
||
|
||
DPHdr.pszPrinterName = NULL;
|
||
}
|
||
|
||
//
|
||
// Attempt to set the printer data to determine access privilages.
|
||
//
|
||
if (SetPrinterData( hPrinter,
|
||
TEXT( "PrinterPropertiesPermission" ),
|
||
REG_DWORD,
|
||
(LPBYTE)&dwValue,
|
||
sizeof( dwValue ) ) == STATUS_SUCCESS ) {
|
||
//
|
||
// Indicate we have permissions.
|
||
//
|
||
DPHdr.Flags &= ~DPS_NOPERMISSION;
|
||
}
|
||
|
||
//
|
||
// Call Common UI to call do the and call the driver.
|
||
//
|
||
if ( CallCommonPropertySheetUI(hWnd,
|
||
DevicePropertySheets,
|
||
(LPARAM)&DPHdr,
|
||
(LPDWORD)&Result) < 0 ) {
|
||
Result = FALSE;
|
||
|
||
} else {
|
||
|
||
Result = TRUE;
|
||
|
||
}
|
||
|
||
if (pPI2) {
|
||
|
||
LocalFree((HLOCAL)pPI2);
|
||
}
|
||
|
||
return Result;
|
||
}
|
||
|
||
DWORD
|
||
GetPrinterDataW(
|
||
HANDLE hPrinter,
|
||
LPWSTR pValueName,
|
||
LPDWORD pType,
|
||
LPBYTE pData,
|
||
DWORD nSize,
|
||
LPDWORD pcbNeeded
|
||
)
|
||
{
|
||
DWORD ReturnValue = 0;
|
||
DWORD ReturnType = 0;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return ERROR_INVALID_HANDLE;
|
||
}
|
||
|
||
//
|
||
// The user should be able to pass in NULL for buffer, and
|
||
// 0 for size. However, the RPC interface specifies a ref pointer,
|
||
// so we must pass in a valid pointer. Pass in a pointer to
|
||
// ReturnValue (this is just a dummy pointer).
|
||
//
|
||
if( !pData && !nSize ){
|
||
pData = (PBYTE)&ReturnValue;
|
||
}
|
||
|
||
if (!pType) {
|
||
pType = (PDWORD) &ReturnType;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
ReturnValue = RpcGetPrinterData(pSpool->hPrinter, pValueName, pType,
|
||
pData, nSize, pcbNeeded);
|
||
|
||
} RpcExcept(1) {
|
||
|
||
ReturnValue = TranslateExceptionCode(RpcExceptionCode());
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
|
||
DWORD
|
||
EnumPrinterDataW(
|
||
HANDLE hPrinter,
|
||
DWORD dwIndex, // index of value to query
|
||
LPWSTR pValueName, // address of buffer for value string
|
||
DWORD cbValueName, // size of pValueName
|
||
LPDWORD pcbValueName, // address for size of value buffer
|
||
LPDWORD pType, // address of buffer for type code
|
||
LPBYTE pData, // address of buffer for value data
|
||
DWORD cbData, // size of pData
|
||
LPDWORD pcbData // address for size of data buffer
|
||
)
|
||
{
|
||
DWORD ReturnValue = 0;
|
||
DWORD ReturnType = 0;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return ERROR_INVALID_HANDLE;
|
||
}
|
||
|
||
//
|
||
// The user should be able to pass in NULL for buffer, and
|
||
// 0 for size. However, the RPC interface specifies a ref pointer,
|
||
// so we must pass in a valid pointer. Pass in a pointer to
|
||
// a dummy pointer.
|
||
//
|
||
|
||
if (!pValueName && !cbValueName)
|
||
pValueName = (LPWSTR) &ReturnValue;
|
||
|
||
if( !pData && !cbData )
|
||
pData = (PBYTE)&ReturnValue;
|
||
|
||
if (!pType)
|
||
pType = (PDWORD) &ReturnType;
|
||
|
||
|
||
RpcTryExcept {
|
||
|
||
ReturnValue = RpcEnumPrinterData( pSpool->hPrinter,
|
||
dwIndex,
|
||
pValueName,
|
||
cbValueName,
|
||
pcbValueName,
|
||
pType,
|
||
pData,
|
||
cbData,
|
||
pcbData);
|
||
|
||
} RpcExcept(1) {
|
||
|
||
ReturnValue = TranslateExceptionCode(RpcExceptionCode());
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
|
||
DWORD
|
||
DeletePrinterDataW(
|
||
HANDLE hPrinter,
|
||
LPWSTR pValueName
|
||
)
|
||
{
|
||
DWORD ReturnValue = 0;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return ERROR_INVALID_HANDLE;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
ReturnValue = RpcDeletePrinterData(pSpool->hPrinter, pValueName);
|
||
|
||
} RpcExcept(1) {
|
||
|
||
ReturnValue = TranslateExceptionCode(RpcExceptionCode());
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
|
||
DWORD
|
||
SetPrinterDataW(
|
||
HANDLE hPrinter,
|
||
LPWSTR pValueName,
|
||
DWORD Type,
|
||
LPBYTE pData,
|
||
DWORD cbData
|
||
)
|
||
{
|
||
DWORD ReturnValue = 0;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return ERROR_INVALID_HANDLE;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
ReturnValue = RpcSetPrinterData(pSpool->hPrinter, pValueName, Type,
|
||
pData, cbData);
|
||
|
||
} RpcExcept(1) {
|
||
|
||
ReturnValue = TranslateExceptionCode(RpcExceptionCode());
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
|
||
HANDLE
|
||
LoadPrinterDriver(
|
||
HANDLE hPrinter
|
||
)
|
||
{
|
||
PDRIVER_INFO_2 pDriverInfo;
|
||
DWORD cbNeeded;
|
||
HANDLE hModule=FALSE;
|
||
|
||
// Should preallocate MAX_DRIVER_INFO_2
|
||
// So we only call the spooler once
|
||
|
||
if (!GetPrinterDriver(hPrinter, NULL, 2, NULL, 0, &cbNeeded)) {
|
||
|
||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||
|
||
if (pDriverInfo = (PDRIVER_INFO_2)LocalAlloc(LMEM_FIXED,
|
||
cbNeeded)) {
|
||
|
||
if (GetPrinterDriver(hPrinter, NULL, 2, (LPBYTE)pDriverInfo,
|
||
cbNeeded, &cbNeeded))
|
||
|
||
hModule = LoadLibrary(pDriverInfo->pConfigFile);
|
||
|
||
LocalFree(pDriverInfo);
|
||
}
|
||
}
|
||
}
|
||
|
||
return hModule;
|
||
}
|
||
|
||
|
||
LONG
|
||
DocumentPropertiesW(
|
||
HWND hWnd,
|
||
HANDLE hPrinter,
|
||
LPWSTR pDeviceName,
|
||
PDEVMODE pDevModeOutput,
|
||
PDEVMODE pDevModeInput,
|
||
DWORD fMode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
DocumentProperties entry point to call DocumentPropertySheets() depends on
|
||
the DM_PROMPT
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
Author:
|
||
|
||
13-Jun-1996 Thu 15:35:25 created -by- Daniel Chou (danielc)
|
||
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
DOCUMENTPROPERTYHEADER DPHdr;
|
||
PDEVMODE pDM;
|
||
LONG Result = -1;
|
||
HANDLE hTmpPrinter = NULL;
|
||
|
||
//
|
||
// Compatibility with Win95
|
||
// Win95 allows for hPrinter to be NULL
|
||
//
|
||
if (hPrinter == NULL) {
|
||
|
||
//
|
||
// Open th printer for default access.
|
||
//
|
||
if (!OpenPrinter( pDeviceName, &hTmpPrinter, NULL )) {
|
||
|
||
hTmpPrinter = NULL;
|
||
}
|
||
|
||
} else {
|
||
|
||
hTmpPrinter = hPrinter;
|
||
}
|
||
|
||
//
|
||
// Ensure the printer handle is valid
|
||
//
|
||
if (ValidatePrinterHandle(hTmpPrinter)) {
|
||
|
||
//
|
||
// If fMode doesn't specify DM_IN_BUFFER, then zero out
|
||
// pDevModeInput.
|
||
//
|
||
// Old 3.51 (version 1-0) drivers used to ignore the absence of
|
||
// DM_IN_BUFFER and use pDevModeInput if it was not NULL. It
|
||
// probably did this because Printman.exe was broken.
|
||
//
|
||
// If the devmode is invalid, then don't pass one in.
|
||
// This fixes MS Imager32 (which passes dmSize == 0) and
|
||
// Milestones etc. 4.5.
|
||
//
|
||
// Note: this assumes that pDevModeOutput is still the
|
||
// correct size!
|
||
//
|
||
if( !(fMode & DM_IN_BUFFER) || !bValidDevModeW( pDevModeInput )){
|
||
|
||
//
|
||
// If either are not set, make sure both are not set.
|
||
//
|
||
pDevModeInput = NULL;
|
||
fMode &= ~DM_IN_BUFFER;
|
||
}
|
||
|
||
DPHdr.cbSize = sizeof(DPHdr);
|
||
DPHdr.Reserved = 0;
|
||
DPHdr.hPrinter = hTmpPrinter;
|
||
DPHdr.pszPrinterName = pDeviceName;
|
||
|
||
if (pDevModeOutput) {
|
||
|
||
//
|
||
// Get the driver devmode size at here
|
||
//
|
||
|
||
DPHdr.pdmIn = NULL;
|
||
DPHdr.pdmOut = NULL;
|
||
DPHdr.fMode = 0;
|
||
|
||
DPHdr.cbOut = DocumentPropertySheets(NULL, (LPARAM)&DPHdr);
|
||
|
||
} else {
|
||
|
||
DPHdr.cbOut = 0;
|
||
}
|
||
|
||
DPHdr.pdmIn = (PDEVMODE)pDevModeInput;
|
||
DPHdr.pdmOut = (PDEVMODE)pDevModeOutput;
|
||
DPHdr.fMode = fMode;
|
||
|
||
if (fMode & DM_PROMPT) {
|
||
|
||
Result = CPSUI_CANCEL;
|
||
|
||
if ((CallCommonPropertySheetUI(hWnd,
|
||
DocumentPropertySheets,
|
||
(LPARAM)&DPHdr,
|
||
(LPDWORD)&Result)) < 0) {
|
||
|
||
Result = -1;
|
||
|
||
} else {
|
||
|
||
Result = (Result == CPSUI_OK) ? IDOK : IDCANCEL;
|
||
}
|
||
|
||
} else {
|
||
|
||
Result = DocumentPropertySheets(NULL, (LPARAM)&DPHdr);
|
||
}
|
||
}
|
||
|
||
if (hPrinter == NULL) {
|
||
|
||
if( hTmpPrinter ){
|
||
|
||
ClosePrinter(hTmpPrinter);
|
||
|
||
}
|
||
}
|
||
|
||
return(Result);
|
||
}
|
||
|
||
LONG
|
||
AdvancedDocumentPropertiesW(
|
||
HWND hWnd,
|
||
HANDLE hPrinter,
|
||
LPWSTR pDeviceName,
|
||
PDEVMODE pDevModeOutput,
|
||
PDEVMODE pDevModeInput
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
AdvanceDocumentProperties() will call DocumentProperties() with DM_ADVANCED
|
||
flag mode set
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
|
||
Return Value:
|
||
|
||
TRUE/FALSE
|
||
|
||
|
||
Author:
|
||
|
||
13-Jun-1996 Thu 16:00:13 created -by- Daniel Chou (danielc)
|
||
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
return((DocumentPropertiesW(hWnd,
|
||
hPrinter,
|
||
pDeviceName,
|
||
pDevModeOutput,
|
||
pDevModeInput,
|
||
DM_PROMPT |
|
||
DM_MODIFY |
|
||
DM_COPY |
|
||
DM_ADVANCED) == CPSUI_OK) ? 1 : 0);
|
||
|
||
}
|
||
|
||
LONG
|
||
AdvancedSetupDialogW(
|
||
HWND hWnd,
|
||
HANDLE hInst,
|
||
LPDEVMODE pDevModeInput,
|
||
LPDEVMODE pDevModeOutput
|
||
)
|
||
{
|
||
HANDLE hPrinter;
|
||
LONG ReturnValue = -1;
|
||
|
||
if (OpenPrinterW(pDevModeInput->dmDeviceName, &hPrinter, NULL)) {
|
||
ReturnValue = AdvancedDocumentPropertiesW(hWnd, hPrinter,
|
||
pDevModeInput->dmDeviceName,
|
||
pDevModeOutput,
|
||
pDevModeInput);
|
||
ClosePrinter(hPrinter);
|
||
}
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
int
|
||
WINAPI
|
||
DeviceCapabilitiesW(
|
||
LPCWSTR pDevice,
|
||
LPCWSTR pPort,
|
||
WORD fwCapability,
|
||
LPWSTR pOutput,
|
||
CONST DEVMODEW *pDevMode
|
||
)
|
||
{
|
||
HANDLE hPrinter, hModule;
|
||
int ReturnValue=-1;
|
||
INT_FARPROC pfn;
|
||
|
||
//DbgPrint("winspool.drv!DeviceCapabilitiesW(%ws, %ws, %d) called\n", pDevice, pPort, fwCapability);
|
||
|
||
if (OpenPrinter((LPWSTR)pDevice, &hPrinter, NULL)) {
|
||
|
||
if (hModule = LoadPrinterDriver(hPrinter)) {
|
||
|
||
if (pfn = GetProcAddress(hModule, "DrvDeviceCapabilities")) {
|
||
|
||
try {
|
||
|
||
ReturnValue = (*pfn)(hPrinter, pDevice, fwCapability,
|
||
pOutput, pDevMode);
|
||
|
||
} except(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = -1;
|
||
}
|
||
}
|
||
|
||
FreeLibrary(hModule);
|
||
}
|
||
|
||
ClosePrinter(hPrinter);
|
||
}
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
AddFormW(
|
||
HANDLE hPrinter,
|
||
DWORD Level,
|
||
LPBYTE pForm
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
GENERIC_CONTAINER FormContainer;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
switch (Level) {
|
||
|
||
case 1:
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
FormContainer.Level = Level;
|
||
FormContainer.pData = pForm;
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcAddForm(pSpool->hPrinter,
|
||
(PFORM_CONTAINER)&FormContainer)) {
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
DeleteFormW(
|
||
HANDLE hPrinter,
|
||
LPWSTR pFormName
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcDeleteForm(pSpool->hPrinter, pFormName)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
GetFormW(
|
||
HANDLE hPrinter,
|
||
LPWSTR pFormName,
|
||
DWORD Level,
|
||
LPBYTE pForm,
|
||
DWORD cbBuf,
|
||
LPDWORD pcbNeeded
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
DWORD *pOffsets;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
switch (Level) {
|
||
|
||
case 1:
|
||
pOffsets = FormInfo1Offsets;
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (pForm)
|
||
memset(pForm, 0, cbBuf);
|
||
|
||
if (ReturnValue = RpcGetForm(pSpool->hPrinter, pFormName, Level, pForm,
|
||
cbBuf, pcbNeeded)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else {
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
if (pForm) {
|
||
|
||
MarshallUpStructure(pForm, pOffsets);
|
||
}
|
||
|
||
}
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
SetFormW(
|
||
HANDLE hPrinter,
|
||
LPWSTR pFormName,
|
||
DWORD Level,
|
||
LPBYTE pForm
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
GENERIC_CONTAINER FormContainer;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
|
||
switch (Level) {
|
||
|
||
case 1:
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
FormContainer.Level = Level;
|
||
FormContainer.pData = pForm;
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcSetForm(pSpool->hPrinter, pFormName,
|
||
(PFORM_CONTAINER)&FormContainer)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
EnumFormsW(
|
||
HANDLE hPrinter,
|
||
DWORD Level,
|
||
LPBYTE pForm,
|
||
DWORD cbBuf,
|
||
LPDWORD pcbNeeded,
|
||
LPDWORD pcReturned
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
DWORD cbStruct;
|
||
DWORD *pOffsets;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
|
||
switch (Level) {
|
||
|
||
case 1:
|
||
pOffsets = FormInfo1Offsets;
|
||
cbStruct = sizeof(FORM_INFO_1);
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (pForm)
|
||
memset(pForm, 0, cbBuf);
|
||
|
||
if (ReturnValue = RpcEnumForms(pSpool->hPrinter, Level, pForm, cbBuf,
|
||
pcbNeeded, pcReturned)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else {
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
if (pForm) {
|
||
|
||
DWORD i=*pcReturned;
|
||
|
||
while (i--) {
|
||
|
||
MarshallUpStructure(pForm, pOffsets);
|
||
|
||
pForm+=cbStruct;
|
||
}
|
||
}
|
||
}
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
EnumPortsW(
|
||
LPWSTR pName,
|
||
DWORD Level,
|
||
LPBYTE pPort,
|
||
DWORD cbBuf,
|
||
LPDWORD pcbNeeded,
|
||
LPDWORD pcReturned
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
DWORD cbStruct;
|
||
DWORD *pOffsets;
|
||
|
||
switch (Level) {
|
||
|
||
case 1:
|
||
pOffsets = PortInfo1Offsets;
|
||
cbStruct = sizeof(PORT_INFO_1);
|
||
break;
|
||
|
||
case 2:
|
||
pOffsets = PortInfo2Offsets;
|
||
cbStruct = sizeof(PORT_INFO_2);
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (pPort)
|
||
memset(pPort, 0, cbBuf);
|
||
|
||
if (ReturnValue = RpcEnumPorts(pName, Level, pPort, cbBuf,
|
||
pcbNeeded, pcReturned)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else {
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
if (pPort) {
|
||
|
||
DWORD i=*pcReturned;
|
||
|
||
while (i--) {
|
||
|
||
MarshallUpStructure(pPort, pOffsets);
|
||
|
||
pPort+=cbStruct;
|
||
}
|
||
}
|
||
}
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
EnumMonitorsW(
|
||
LPWSTR pName,
|
||
DWORD Level,
|
||
LPBYTE pMonitor,
|
||
DWORD cbBuf,
|
||
LPDWORD pcbNeeded,
|
||
LPDWORD pcReturned
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
DWORD cbStruct;
|
||
DWORD *pOffsets;
|
||
|
||
switch (Level) {
|
||
|
||
case 1:
|
||
pOffsets = MonitorInfo1Offsets;
|
||
cbStruct = sizeof(MONITOR_INFO_1);
|
||
break;
|
||
|
||
case 2:
|
||
pOffsets = MonitorInfo2Offsets;
|
||
cbStruct = sizeof(MONITOR_INFO_2);
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (pMonitor)
|
||
memset(pMonitor, 0, cbBuf);
|
||
|
||
if (ReturnValue = RpcEnumMonitors(pName, Level, pMonitor, cbBuf,
|
||
pcbNeeded, pcReturned)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
if (pMonitor) {
|
||
|
||
DWORD i=*pcReturned;
|
||
|
||
while (i--) {
|
||
|
||
MarshallUpStructure(pMonitor, pOffsets);
|
||
|
||
pMonitor+=cbStruct;
|
||
}
|
||
}
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
typedef struct {
|
||
LPWSTR pName;
|
||
HWND hWnd;
|
||
LPWSTR pPortName;
|
||
HANDLE Complete;
|
||
DWORD ReturnValue;
|
||
DWORD Error;
|
||
INT_FARPROC pfn;
|
||
} CONFIGUREPORT_PARAMETERS;
|
||
|
||
void
|
||
PortThread(
|
||
CONFIGUREPORT_PARAMETERS *pParam
|
||
)
|
||
{
|
||
DWORD ReturnValue;
|
||
|
||
/* It's no use setting errors here, because they're kept on a per-thread
|
||
* basis. Instead we have to pass any error code back to the calling
|
||
* thread and let him set it.
|
||
*/
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = (*pParam->pfn)(pParam->pName, pParam->hWnd,
|
||
pParam->pPortName)) {
|
||
pParam->Error = ReturnValue;
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
pParam->Error = TranslateExceptionCode(RpcExceptionCode());
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
pParam->ReturnValue = ReturnValue;
|
||
|
||
SetEvent(pParam->Complete);
|
||
}
|
||
|
||
BOOL
|
||
KickoffThread(
|
||
LPWSTR pName,
|
||
HWND hWnd,
|
||
LPWSTR pPortName,
|
||
INT_FARPROC pfn
|
||
)
|
||
{
|
||
CONFIGUREPORT_PARAMETERS Parameters;
|
||
HANDLE ThreadHandle;
|
||
MSG msg;
|
||
DWORD ThreadId;
|
||
|
||
EnableWindow(hWnd, FALSE);
|
||
|
||
Parameters.pName = pName;
|
||
Parameters.hWnd = hWnd;
|
||
Parameters.pPortName = pPortName;
|
||
Parameters.Complete = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||
Parameters.pfn = pfn;
|
||
|
||
ThreadHandle = CreateThread(NULL, 4*1024,
|
||
(LPTHREAD_START_ROUTINE)PortThread,
|
||
&Parameters, 0, &ThreadId);
|
||
|
||
CloseHandle(ThreadHandle);
|
||
|
||
while (MsgWaitForMultipleObjects(1, &Parameters.Complete, FALSE, INFINITE,
|
||
QS_ALLEVENTS | QS_SENDMESSAGE) == 1) {
|
||
|
||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||
|
||
TranslateMessage(&msg);
|
||
DispatchMessage(&msg);
|
||
}
|
||
}
|
||
|
||
CloseHandle(Parameters.Complete);
|
||
|
||
EnableWindow(hWnd, TRUE);
|
||
SetForegroundWindow(hWnd);
|
||
|
||
SetFocus(hWnd);
|
||
|
||
if(!Parameters.ReturnValue)
|
||
SetLastError(Parameters.Error);
|
||
|
||
return Parameters.ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
AddPortW(
|
||
LPWSTR pName,
|
||
HWND hWnd,
|
||
LPWSTR pMonitorName
|
||
)
|
||
{
|
||
return KickoffThread(pName, hWnd, pMonitorName, (INT_FARPROC)RpcAddPort);
|
||
}
|
||
|
||
BOOL
|
||
ConfigurePortW(
|
||
LPWSTR pName,
|
||
HWND hWnd,
|
||
LPWSTR pPortName
|
||
)
|
||
{
|
||
return KickoffThread(pName, hWnd, pPortName, (INT_FARPROC)RpcConfigurePort);
|
||
}
|
||
|
||
BOOL
|
||
DeletePortW(
|
||
LPWSTR pName,
|
||
HWND hWnd,
|
||
LPWSTR pPortName
|
||
)
|
||
{
|
||
return KickoffThread(pName, hWnd, pPortName, (INT_FARPROC)RpcDeletePort);
|
||
}
|
||
|
||
HANDLE
|
||
CreatePrinterIC(
|
||
HANDLE hPrinter,
|
||
LPDEVMODEW pDevMode
|
||
)
|
||
{
|
||
HANDLE ReturnValue;
|
||
DWORD Error;
|
||
DEVMODE_CONTAINER DevModeContainer;
|
||
HANDLE hGdi;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
|
||
if( bValidDevModeW( pDevMode )){
|
||
|
||
DevModeContainer.cbBuf = pDevMode->dmSize + pDevMode->dmDriverExtra;
|
||
DevModeContainer.pDevMode = (LPBYTE)pDevMode;
|
||
|
||
} else {
|
||
|
||
DevModeContainer.cbBuf = 0;
|
||
DevModeContainer.pDevMode = (LPBYTE)pDevMode;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (Error = RpcCreatePrinterIC( pSpool->hPrinter,
|
||
&hGdi,
|
||
&DevModeContainer )){
|
||
|
||
SetLastError(Error);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = hGdi;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(RpcExceptionCode());
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
PlayGdiScriptOnPrinterIC(
|
||
HANDLE hPrinterIC,
|
||
LPBYTE pIn,
|
||
DWORD cIn,
|
||
LPBYTE pOut,
|
||
DWORD cOut,
|
||
DWORD ul
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcPlayGdiScriptOnPrinterIC(hPrinterIC, pIn, cIn,
|
||
pOut, cOut, ul)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
DeletePrinterIC(
|
||
HANDLE hPrinterIC
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcDeletePrinterIC(&hPrinterIC)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
|
||
/****************************************************************************
|
||
* INT QueryRemoteFonts( HANDLE, PUNIVERSAL_FONT_ID, ULONG )
|
||
*
|
||
* This is a hacky version of QueryRemoteFonts that doesn't do any
|
||
* caching based on the time stamp returned by QueryFonts. Additionally,
|
||
* it uses the CreatePrinterIC/PlayGdiScriptOnDC mechanism since it was
|
||
* already in place. It may be better to eliminate CreatePrinterIC and use
|
||
* an HPRINTER instead.
|
||
*
|
||
* Note that if the user doesn't pass in a buffer large enough to hold all
|
||
* the fonts we truncate the list and copy only enough fonts for which there
|
||
* is room but will still return success. This is okay because the worst
|
||
* that can happen in this case is that we may download unecessary fonts in
|
||
* the spool stream.
|
||
*
|
||
*
|
||
* History:
|
||
* 5/25/1995 by Gerrit van Wingerden [gerritv]
|
||
* Wrote it.
|
||
*****************************************************************************/
|
||
|
||
|
||
INT QueryRemoteFonts(
|
||
HANDLE hPrinter,
|
||
PUNIVERSAL_FONT_ID pufi,
|
||
ULONG nBufferSize
|
||
)
|
||
{
|
||
HANDLE hPrinterIC;
|
||
PBYTE pBuf;
|
||
DWORD dwDummy,cOut;
|
||
INT iRet = -1;
|
||
|
||
hPrinterIC = CreatePrinterIC( hPrinter, NULL );
|
||
|
||
if( hPrinterIC )
|
||
{
|
||
cOut = (nBufferSize * sizeof(UNIVERSAL_FONT_ID)) + sizeof(INT);
|
||
|
||
pBuf = LocalAlloc( LMEM_FIXED, cOut );
|
||
|
||
if( pBuf )
|
||
{
|
||
// Just call PlayGdiScriptOnPrinterIC for now since the piping is in place.
|
||
// For some reason the RPC stuff doesn't like NULL pointers for pIn so we
|
||
// use &dwDummy instead;
|
||
|
||
|
||
if(PlayGdiScriptOnPrinterIC(hPrinterIC,(PBYTE) &dwDummy,
|
||
sizeof(dwDummy),pBuf,cOut, 0))
|
||
{
|
||
DWORD dwSize = *((DWORD*) pBuf );
|
||
|
||
iRet = (INT) dwSize;
|
||
SPLASSERT( iRet >= 0 );
|
||
|
||
if( dwSize > nBufferSize )
|
||
{
|
||
dwSize = nBufferSize;
|
||
}
|
||
memcpy(pufi,pBuf+sizeof(DWORD),dwSize * sizeof(UNIVERSAL_FONT_ID));
|
||
}
|
||
|
||
LocalFree( pBuf );
|
||
}
|
||
|
||
DeletePrinterIC( hPrinterIC );
|
||
}
|
||
|
||
return(iRet);
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
PrinterMessageBoxW(
|
||
HANDLE hPrinter,
|
||
DWORD Error,
|
||
HWND hWnd,
|
||
LPWSTR pText,
|
||
LPWSTR pCaption,
|
||
DWORD dwType
|
||
)
|
||
{
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
DWORD dw;
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
RpcTryExcept {
|
||
|
||
dw = RpcPrinterMessageBox(pSpool->hPrinter, Error, (DWORD)hWnd, pText,
|
||
pCaption, dwType);
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
dw = 0;
|
||
|
||
} RpcEndExcept
|
||
|
||
return dw;
|
||
}
|
||
|
||
BOOL
|
||
AddMonitorW(
|
||
LPWSTR pName,
|
||
DWORD Level,
|
||
LPBYTE pMonitorInfo
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
MONITOR_CONTAINER MonitorContainer;
|
||
MONITOR_INFO_2 MonitorInfo2;
|
||
|
||
switch (Level) {
|
||
|
||
case 2:
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
if (pMonitorInfo)
|
||
MonitorInfo2 = *(PMONITOR_INFO_2)pMonitorInfo;
|
||
else
|
||
memset(&MonitorInfo2, 0, sizeof(MonitorInfo2));
|
||
|
||
if (!MonitorInfo2.pEnvironment || !*MonitorInfo2.pEnvironment) {
|
||
MonitorInfo2.pEnvironment = szEnvironment;
|
||
}
|
||
|
||
MonitorContainer.Level = Level;
|
||
MonitorContainer.MonitorInfo.pMonitorInfo2 = (MONITOR_INFO_2 *)&MonitorInfo2;
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcAddMonitor(pName, &MonitorContainer)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
DeleteMonitorW(
|
||
LPWSTR pName,
|
||
LPWSTR pEnvironment,
|
||
LPWSTR pMonitorName
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
|
||
if (!pMonitorName || !*pMonitorName) {
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
return (FALSE);
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (!pEnvironment || !*pEnvironment)
|
||
pEnvironment = szEnvironment;
|
||
|
||
if (ReturnValue = RpcDeleteMonitor(pName,
|
||
pEnvironment,
|
||
pMonitorName)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
DeletePrintProcessorW(
|
||
LPWSTR pName,
|
||
LPWSTR pEnvironment,
|
||
LPWSTR pPrintProcessorName
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
|
||
if (!pPrintProcessorName || !*pPrintProcessorName) {
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
return FALSE;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (!pEnvironment || !*pEnvironment)
|
||
pEnvironment = szEnvironment;
|
||
|
||
if (ReturnValue = RpcDeletePrintProcessor(pName,
|
||
pEnvironment,
|
||
pPrintProcessorName)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
AddPrintProvidorW(
|
||
LPWSTR pName,
|
||
DWORD Level,
|
||
LPBYTE pProvidorInfo
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
PROVIDOR_CONTAINER ProvidorContainer;
|
||
|
||
switch (Level) {
|
||
|
||
case 1:
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
ProvidorContainer.Level = Level;
|
||
ProvidorContainer.ProvidorInfo.pProvidorInfo1 = (PROVIDOR_INFO_1 *)pProvidorInfo;
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcAddPrintProvidor(pName, &ProvidorContainer)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
DeletePrintProvidorW(
|
||
LPWSTR pName,
|
||
LPWSTR pEnvironment,
|
||
LPWSTR pPrintProvidorName
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
|
||
RpcTryExcept {
|
||
|
||
if (!pEnvironment || !*pEnvironment)
|
||
pEnvironment = szEnvironment;
|
||
|
||
if (ReturnValue = RpcDeletePrintProvidor(pName,
|
||
pEnvironment,
|
||
pPrintProvidorName)) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
|
||
LPWSTR
|
||
IsaFileName(
|
||
LPWSTR pOutputFile,
|
||
LPWSTR FullPathName
|
||
)
|
||
{
|
||
HANDLE hFile = INVALID_HANDLE_VALUE;
|
||
LPWSTR pFileName=NULL;
|
||
|
||
//
|
||
// Hack for Word20c.Win
|
||
//
|
||
|
||
if (!_wcsicmp(pOutputFile, L"FILE")) {
|
||
return(NULL);
|
||
}
|
||
|
||
if (GetFullPathName(pOutputFile, MAX_PATH, FullPathName, &pFileName)) {
|
||
|
||
DBGMSG(DBG_TRACE, ("Fully qualified filename is %ws\n", FullPathName));
|
||
|
||
hFile = CreateFile(pOutputFile,
|
||
GENERIC_WRITE,
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
NULL,
|
||
OPEN_ALWAYS,
|
||
FILE_ATTRIBUTE_NORMAL,
|
||
NULL);
|
||
|
||
if (hFile != INVALID_HANDLE_VALUE) {
|
||
if (GetFileType(hFile) == FILE_TYPE_DISK) {
|
||
CloseHandle(hFile);
|
||
return(FullPathName);
|
||
} else {
|
||
CloseHandle(hFile);
|
||
}
|
||
}
|
||
}
|
||
return(NULL);
|
||
}
|
||
|
||
BOOL IsaPortName(
|
||
PKEYDATA pKeyData,
|
||
LPWSTR pOutputFile
|
||
)
|
||
{
|
||
DWORD i = 0;
|
||
UINT uStrLen;
|
||
|
||
if (!pKeyData) {
|
||
return(FALSE);
|
||
}
|
||
for (i=0; i < pKeyData->cTokens; i++) {
|
||
if (!lstrcmpi(pKeyData->pTokens[i], szFilePort)) {
|
||
if ((!wcsncmp(pOutputFile, L"Ne", 2)) &&
|
||
(*(pOutputFile + 4) == L':')) {
|
||
return(FALSE);
|
||
} else {
|
||
continue;
|
||
}
|
||
}
|
||
|
||
if (!lstrcmpi(pKeyData->pTokens[i], pOutputFile)) {
|
||
return(TRUE);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Hack for NeXY: ports
|
||
//
|
||
|
||
if (!_wcsnicmp(pOutputFile, L"Ne", 2)) {
|
||
|
||
uStrLen = wcslen( pOutputFile );
|
||
|
||
//
|
||
// Ne00: or Ne00 if app truncates it
|
||
//
|
||
if (( uStrLen == 5 ) || ( uStrLen == 4 ) ) {
|
||
|
||
// Check for two Digits
|
||
|
||
if (( pOutputFile[2] >= L'0' ) && ( pOutputFile[2] <= L'9' ) &&
|
||
( pOutputFile[3] >= L'0' ) && ( pOutputFile[3] <= L'9' )) {
|
||
|
||
//
|
||
// Check for the final : as in Ne01:,
|
||
// note some apps will truncate it.
|
||
//
|
||
if (( uStrLen == 5 ) && (pOutputFile[4] != L':')) {
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
return(FALSE);
|
||
}
|
||
|
||
BOOL HasAFilePort(PKEYDATA pKeyData)
|
||
{
|
||
DWORD i = 0;
|
||
|
||
if (!pKeyData) {
|
||
return(FALSE);
|
||
}
|
||
for (i=0; i < pKeyData->cTokens; i++) {
|
||
if (!lstrcmpi(pKeyData->pTokens[i], szFilePort)) {
|
||
return(TRUE);
|
||
}
|
||
}
|
||
return(FALSE);
|
||
}
|
||
|
||
|
||
|
||
LPWSTR
|
||
StartDocDlgW(
|
||
HANDLE hPrinter,
|
||
DOCINFO *pDocInfo
|
||
)
|
||
{
|
||
DWORD dwError = 0;
|
||
DWORD dwStatus = FALSE;
|
||
LPWSTR lpFileName = NULL;
|
||
DWORD rc = 0;
|
||
PKEYDATA pKeyData = NULL;
|
||
LPWSTR pPortNames = NULL;
|
||
WCHAR FullPathName[MAX_PATH];
|
||
WCHAR CurrentDirectory[MAX_PATH];
|
||
PKEYDATA pOutputList = NULL;
|
||
WCHAR PortNames[MAX_PATH];
|
||
DWORD i = 0;
|
||
|
||
#if DBG
|
||
|
||
|
||
GetCurrentDirectory(MAX_PATH, CurrentDirectory);
|
||
DBGMSG(DBG_TRACE, ("The Current Directory is %ws\n", CurrentDirectory));
|
||
#endif
|
||
|
||
if (pDocInfo) {
|
||
DBGMSG(DBG_TRACE, ("lpOutputFile is %ws\n", pDocInfo->lpszOutput ? pDocInfo->lpszOutput: L""));
|
||
}
|
||
memset(FullPathName, 0, sizeof(WCHAR)*MAX_PATH);
|
||
|
||
pPortNames = GetPrinterPortList(hPrinter);
|
||
pKeyData = CreateTokenList(pPortNames);
|
||
|
||
//
|
||
// Check for the presence of multiple ports in the lpszOutput field
|
||
// the assumed delimiter is the comma. Thus there can be no files with commas
|
||
// BugBug: printing wide, Hpmon can have ports with commas this should be fixed
|
||
//
|
||
|
||
if (pDocInfo && pDocInfo->lpszOutput && pDocInfo->lpszOutput[0]) {
|
||
|
||
//
|
||
// Make a copy of the pDocInfo->lpszOutput because CreateTokenList is destructive
|
||
//
|
||
|
||
wcscpy(PortNames, pDocInfo->lpszOutput);
|
||
pOutputList = CreateTokenList(PortNames);
|
||
if ((pOutputList->cTokens > 1) &&
|
||
!lstrcmpi(pPortNames, pDocInfo->lpszOutput))
|
||
{
|
||
for (i= 0; i < pOutputList->cTokens; i++) {
|
||
if (!lstrcmpi(pOutputList->pTokens[i], szFilePort)) {
|
||
|
||
//
|
||
// !! BUGBUG !!
|
||
//
|
||
// We are about to corrupt some user memory
|
||
// here if lpszOutput is just a few chars long.
|
||
//
|
||
wcscpy((LPWSTR)pDocInfo->lpszOutput, szFilePort);
|
||
break;
|
||
}
|
||
}
|
||
if (i == pOutputList->cTokens) {
|
||
wcscpy((LPWSTR)pDocInfo->lpszOutput, pOutputList->pTokens[0]);
|
||
}
|
||
}
|
||
|
||
FreeSplMem(pOutputList);
|
||
}
|
||
|
||
|
||
if (pDocInfo && pDocInfo->lpszOutput && pDocInfo->lpszOutput[0]) {
|
||
|
||
if (IsaPortName(pKeyData, (LPWSTR)pDocInfo->lpszOutput)) {
|
||
lpFileName = NULL;
|
||
goto StartDocDlgWReturn;
|
||
}
|
||
|
||
if (IsaFileName((LPWSTR)pDocInfo->lpszOutput, FullPathName)) {
|
||
|
||
//
|
||
// Fully Qualify the pathname for Apps like PageMaker and QuatroPro
|
||
//
|
||
if (lpFileName = LocalAlloc(LPTR, (wcslen(FullPathName)+1)*sizeof(WCHAR))) {
|
||
wcscpy(lpFileName, FullPathName);
|
||
}
|
||
goto StartDocDlgWReturn;
|
||
}
|
||
|
||
}
|
||
|
||
if ((HasAFilePort(pKeyData)) ||
|
||
(pDocInfo && pDocInfo->lpszOutput
|
||
&& (!_wcsicmp(pDocInfo->lpszOutput, L"FILE:") ||
|
||
!_wcsicmp(pDocInfo->lpszOutput, L"FILE"))))
|
||
{
|
||
|
||
DBGMSG(DBG_TRACE, ("We returned True from has file\n"));
|
||
rc = DialogBoxParam( hInst,
|
||
MAKEINTRESOURCE( DLG_PRINTTOFILE ),
|
||
NULL, (DLGPROC)PrintToFileDlg,
|
||
(LPARAM)&lpFileName );
|
||
if (rc == -1) {
|
||
DBGMSG(DBG_TRACE, ("Error from DialogBoxParam- %d\n", GetLastError()));
|
||
lpFileName = (LPWSTR)-1;
|
||
goto StartDocDlgWReturn;
|
||
|
||
} else if (rc == 0) {
|
||
DBGMSG(DBG_TRACE, ("User cancelled the dialog\n"));
|
||
lpFileName = (LPWSTR)-2;
|
||
SetLastError( ERROR_CANCELLED );
|
||
goto StartDocDlgWReturn;
|
||
} else {
|
||
DBGMSG(DBG_TRACE, ("The string was successfully returned\n"));
|
||
DBGMSG(DBG_TRACE, ("The string is %ws\n", lpFileName? lpFileName: L"NULL"));
|
||
goto StartDocDlgWReturn;
|
||
}
|
||
} else {
|
||
lpFileName = (LPWSTR)NULL;
|
||
}
|
||
|
||
StartDocDlgWReturn:
|
||
if (pKeyData) {
|
||
FreeSplMem(pKeyData);
|
||
}
|
||
|
||
if (pPortNames) {
|
||
FreeSplStr(pPortNames);
|
||
}
|
||
return(lpFileName);
|
||
|
||
|
||
}
|
||
|
||
BOOL
|
||
AddPortExW(
|
||
LPWSTR pName,
|
||
DWORD Level,
|
||
LPBYTE lpBuffer,
|
||
LPWSTR lpMonitorName
|
||
)
|
||
{
|
||
DWORD ReturnValue;
|
||
PORT_CONTAINER PortContainer;
|
||
PORT_VAR_CONTAINER PortVarContainer;
|
||
PPORT_INFO_FF pPortInfoFF;
|
||
PPORT_INFO_1 pPortInfo1;
|
||
|
||
|
||
if (!lpBuffer) {
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
return(FALSE);
|
||
}
|
||
|
||
switch (Level) {
|
||
case (DWORD)-1:
|
||
pPortInfoFF = (PPORT_INFO_FF)lpBuffer;
|
||
PortContainer.Level = Level;
|
||
PortContainer.PortInfo.pPortInfoFF = (PPORT_INFO_FF)pPortInfoFF;
|
||
PortVarContainer.cbMonitorData = pPortInfoFF->cbMonitorData;
|
||
PortVarContainer.pMonitorData = pPortInfoFF->pMonitorData;
|
||
break;
|
||
|
||
case 1:
|
||
pPortInfo1 = (PPORT_INFO_1)lpBuffer;
|
||
PortContainer.Level = Level;
|
||
PortContainer.PortInfo.pPortInfo1 = (PPORT_INFO_1)pPortInfo1;
|
||
PortVarContainer.cbMonitorData = 0;
|
||
PortVarContainer.pMonitorData = NULL;
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return(FALSE);
|
||
}
|
||
|
||
RpcTryExcept {
|
||
if (ReturnValue = RpcAddPortEx(pName, (LPPORT_CONTAINER)&PortContainer,
|
||
(LPPORT_VAR_CONTAINER)&PortVarContainer,
|
||
lpMonitorName
|
||
)) {
|
||
SetLastError(ReturnValue);
|
||
return(FALSE);
|
||
} else {
|
||
return(TRUE);
|
||
}
|
||
} RpcExcept(1) {
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
DevQueryPrint(
|
||
HANDLE hPrinter,
|
||
LPDEVMODE pDevMode,
|
||
DWORD *pResID
|
||
)
|
||
{
|
||
BOOL Ok = FALSE;
|
||
HANDLE hModule;
|
||
INT_FARPROC pfn;
|
||
|
||
if (hModule = LoadPrinterDriver(hPrinter)) {
|
||
|
||
if (pfn = GetProcAddress(hModule, "DevQueryPrint")) {
|
||
|
||
try {
|
||
|
||
Ok = (*pfn)(hPrinter, pDevMode, pResID);
|
||
|
||
} except(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
Ok = FALSE;
|
||
}
|
||
}
|
||
|
||
FreeLibrary(hModule);
|
||
}
|
||
|
||
return(Ok);
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
DevQueryPrintEx(
|
||
PDEVQUERYPRINT_INFO pDQPInfo
|
||
)
|
||
{
|
||
BOOL Ok = FALSE;
|
||
HANDLE hModule;
|
||
INT_FARPROC pfn;
|
||
|
||
if (hModule = LoadPrinterDriver(pDQPInfo->hPrinter)) {
|
||
|
||
if (pfn = GetProcAddress(hModule, "DevQueryPrintEx")) {
|
||
|
||
try {
|
||
|
||
Ok = (*pfn)(pDQPInfo);
|
||
|
||
} except(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
Ok = FALSE;
|
||
}
|
||
}
|
||
|
||
FreeLibrary(hModule);
|
||
}
|
||
|
||
return(Ok);
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
SpoolerDevQueryPrintW(
|
||
HANDLE hPrinter,
|
||
LPDEVMODE pDevMode,
|
||
DWORD *pResID,
|
||
LPWSTR pszBuffer,
|
||
DWORD cchBuffer
|
||
)
|
||
{
|
||
BOOL Ok = FALSE;
|
||
HANDLE hModule;
|
||
INT_FARPROC pfn;
|
||
|
||
if (hModule = LoadPrinterDriver(hPrinter)) {
|
||
|
||
if (pfn = GetProcAddress(hModule, "DevQueryPrintEx")) {
|
||
|
||
DEVQUERYPRINT_INFO DQPInfo;
|
||
|
||
DQPInfo.cbSize = sizeof(DQPInfo);
|
||
DQPInfo.Level = 1;
|
||
DQPInfo.hPrinter = hPrinter;
|
||
DQPInfo.pDevMode = pDevMode;
|
||
DQPInfo.pszErrorStr = (LPTSTR)pszBuffer;
|
||
DQPInfo.cchErrorStr = (WORD)cchBuffer;
|
||
DQPInfo.cchNeeded = 0;
|
||
|
||
try {
|
||
|
||
*pResID = (Ok = (*pfn)(&DQPInfo)) ? 0 : 0xDCDCDCDC;
|
||
|
||
} except(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
Ok = FALSE;
|
||
}
|
||
|
||
} else if (pfn = GetProcAddress(hModule, "DevQueryPrint")) {
|
||
|
||
try {
|
||
|
||
if ((Ok = (*pfn)(hPrinter, pDevMode, pResID)) &&
|
||
(*pResID)) {
|
||
|
||
UINT cch;
|
||
|
||
*pszBuffer = L'\0';
|
||
SelectFormNameFromDevMode(hPrinter, pDevMode, pszBuffer);
|
||
|
||
if (cch = lstrlen(pszBuffer)) {
|
||
|
||
pszBuffer += cch;
|
||
*pszBuffer++ = L' ';
|
||
*pszBuffer++ = L'-';
|
||
*pszBuffer++ = L' ';
|
||
cchBuffer -= (cch + 3);
|
||
}
|
||
|
||
LoadString(hModule, *pResID, pszBuffer, cchBuffer);
|
||
}
|
||
|
||
} except(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
Ok = FALSE;
|
||
}
|
||
}
|
||
|
||
FreeLibrary(hModule);
|
||
}
|
||
|
||
return(Ok);
|
||
}
|
||
|
||
|
||
|
||
LPWSTR
|
||
SelectFormNameFromDevMode(
|
||
HANDLE hPrinter,
|
||
PDEVMODEW pDevModeW,
|
||
LPWSTR pFormName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function pick the current form associated with current devmode and
|
||
return a form name pointer
|
||
|
||
|
||
Arguments:
|
||
|
||
hPrinter - Handle to the printer object
|
||
|
||
pDevModeW - Pointer to the unicode devmode for this printer
|
||
|
||
FormName - Pointer to the formname to be filled
|
||
|
||
|
||
Return Value:
|
||
|
||
Either a pointer to the FormName passed in if we do found one form,
|
||
otherwise it return NULL to signal a failue
|
||
|
||
|
||
Author:
|
||
|
||
21-Mar-1995 Tue 16:57:51 created -by- Daniel Chou (danielc)
|
||
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD cb;
|
||
DWORD cRet;
|
||
LPFORM_INFO_1 pFIBase;
|
||
LPFORM_INFO_1 pFI;
|
||
|
||
|
||
//
|
||
// 1. If the DM_FORMNAME is turned on, then we want to check this bit first
|
||
// because it only specific to the NT which using form. The form name
|
||
// supposed set by any NT driver but not win31 or Win95.Use the
|
||
// dmFormName only if dmPaperSize, dmPaperLength and dmPaperWidth fields
|
||
// are not set. If any of them is set then we have to find a form using
|
||
// the value in these fields.
|
||
//
|
||
|
||
if ( (pDevModeW->dmFields & DM_FORMNAME)
|
||
&& (!(pDevModeW->dmFields & (DM_PAPERSIZE |
|
||
DM_PAPERLENGTH |
|
||
DM_PAPERWIDTH))) ) {
|
||
|
||
wcscpy(pFormName, pDevModeW->dmFormName);
|
||
return(pFormName);
|
||
}
|
||
|
||
//
|
||
// For all other cases we need to get forms data base first, but we want
|
||
// to set the form name to NULL so that we can check if we found one
|
||
//
|
||
|
||
cb =
|
||
cRet = 0;
|
||
pFIBase =
|
||
pFI = NULL;
|
||
|
||
if ((!EnumForms(hPrinter, 1, NULL, 0, &cb, &cRet)) &&
|
||
(GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
|
||
(pFIBase = (LPFORM_INFO_1)LocalAlloc(LPTR, cb)) &&
|
||
(EnumForms(hPrinter, 1, (LPBYTE)pFIBase, cb, &cb, &cRet))) {
|
||
|
||
//
|
||
// 2. If user specified dmPaperSize then honor it, otherwise, it must
|
||
// be a custom form, and we will check to see if it match one of
|
||
// in the database
|
||
//
|
||
|
||
if ((pDevModeW->dmFields & DM_PAPERSIZE) &&
|
||
(pDevModeW->dmPaperSize >= DMPAPER_FIRST) &&
|
||
(pDevModeW->dmPaperSize <= (SHORT)cRet)) {
|
||
|
||
//
|
||
// We go the valid index now
|
||
//
|
||
|
||
pFI = pFIBase + (pDevModeW->dmPaperSize - DMPAPER_FIRST);
|
||
|
||
} else if ((pDevModeW->dmFields & DM_PAPER_WL) == DM_PAPER_WL) {
|
||
|
||
LPFORM_INFO_1 pFICur = pFIBase;
|
||
|
||
while (cRet--) {
|
||
|
||
if ((DM_MATCH(pDevModeW->dmPaperWidth, pFICur->Size.cx)) &&
|
||
(DM_MATCH(pDevModeW->dmPaperLength, pFICur->Size.cy))) {
|
||
|
||
//
|
||
// We found the match which has discern size differences
|
||
//
|
||
|
||
pFI = pFICur;
|
||
|
||
break;
|
||
}
|
||
|
||
pFICur++;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// If we found the form then copy the name down, otherwise set the
|
||
// formname to be NULL
|
||
//
|
||
|
||
if (pFI) {
|
||
|
||
wcscpy(pFormName, pFI->pName);
|
||
|
||
} else {
|
||
|
||
*pFormName = L'\0';
|
||
pFormName = NULL;
|
||
}
|
||
|
||
if (pFIBase) {
|
||
|
||
LocalFree((HLOCAL)pFIBase);
|
||
}
|
||
|
||
return(pFormName);
|
||
}
|
||
|
||
|
||
BOOL
|
||
SetAllocFailCount(
|
||
HANDLE hPrinter,
|
||
DWORD dwFailCount,
|
||
LPDWORD lpdwAllocCount,
|
||
LPDWORD lpdwFreeCount,
|
||
LPDWORD lpdwFailCountHit
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
PSPOOL pSpool = hPrinter;
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if (ReturnValue = RpcSetAllocFailCount( pSpool->hPrinter,
|
||
dwFailCount,
|
||
lpdwAllocCount,
|
||
lpdwFreeCount,
|
||
lpdwFailCountHit )) {
|
||
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
|
||
} else
|
||
|
||
ReturnValue = TRUE;
|
||
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
WINAPI
|
||
EnumPrinterPropertySheets(
|
||
HANDLE hPrinter,
|
||
HWND hWnd,
|
||
LPVOID lpfnAdd,
|
||
LPARAM lParam
|
||
)
|
||
{
|
||
SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
VOID
|
||
vUpdateTrayIcon(
|
||
IN HANDLE hPrinter,
|
||
IN DWORD JobId
|
||
)
|
||
{
|
||
SHCNF_PRINTJOB_DATA JobData;
|
||
LPPRINTER_INFO_1 pPrinterInfo1;
|
||
FARPROC pfnSHChangeNotify;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
SPLASSERT( JobId );
|
||
|
||
//
|
||
// Avoid sending multiple notifications by setting this flag.
|
||
// When other calls (notably StartDocPrinter) see this,
|
||
// they will avoid sending a notification.
|
||
//
|
||
pSpool->Status |= SPOOL_STATUS_TRAYICON_NOTIFIED;
|
||
|
||
ZeroMemory( &JobData, sizeof( JobData ));
|
||
JobData.JobId = JobId;
|
||
|
||
//
|
||
// Get a copy of the real printer name
|
||
//
|
||
pPrinterInfo1 = (LPPRINTER_INFO_1)AllocSplMem( MAX_PRINTER_INFO1 );
|
||
|
||
if( pPrinterInfo1 ){
|
||
|
||
DWORD dwNeeded;
|
||
|
||
if( GetPrinter( hPrinter,
|
||
1,
|
||
(PBYTE)pPrinterInfo1,
|
||
MAX_PRINTER_INFO1,
|
||
&dwNeeded )){
|
||
|
||
if ( !hShell32 )
|
||
hShell32 = LoadLibrary( TEXT( "shell32.dll" ) );
|
||
|
||
if( hShell32 ) {
|
||
|
||
pfnSHChangeNotify = GetProcAddress( hShell32,
|
||
"SHChangeNotify" );
|
||
|
||
if( pfnSHChangeNotify ){
|
||
|
||
(*pfnSHChangeNotify)(
|
||
SHCNE_CREATE,
|
||
SHCNF_PRINTJOB | SHCNF_FLUSH | SHCNF_FLUSHNOWAIT,
|
||
pPrinterInfo1->pName,
|
||
(DWORD)&JobData );
|
||
}
|
||
}
|
||
}
|
||
FreeSplMem( pPrinterInfo1 );
|
||
}
|
||
}
|
||
|
||
|
||
INT
|
||
DocumentEvent(
|
||
HANDLE hPrinter,
|
||
HDC hdc,
|
||
INT iEsc,
|
||
ULONG cbIn,
|
||
PULONG pulIn,
|
||
ULONG cbOut,
|
||
PULONG pulOut
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Allow the driver UI dll to hook specific print events.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
-1 error, stop printing
|
||
-2 cancel by user
|
||
0 call not supported
|
||
>0 success
|
||
|
||
--*/
|
||
|
||
{
|
||
LPDRIVER_INFO_2 pDriverInfo = NULL;
|
||
DWORD cbNeeded;
|
||
HANDLE hLibrary;
|
||
INT_FARPROC pfn;
|
||
INT ReturnValue=0;
|
||
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
||
if (!ValidatePrinterHandle(hPrinter)) {
|
||
return(FALSE);
|
||
}
|
||
|
||
if( DOCUMENTEVENT_EVENT( iEsc ) == DOCUMENTEVENT_CREATEDCPRE ){
|
||
|
||
//
|
||
// Before every CreateDC, re-enable DocumentEvent.
|
||
// If it fails on the first try, then don't try again
|
||
// until the next CreateDC.
|
||
//
|
||
pSpool->Status |= SPOOL_STATUS_DOCUMENTEVENT_ENABLED;
|
||
}
|
||
|
||
//
|
||
// Call Document event only if it's succeeded previously on
|
||
// CREATEDCPRE.
|
||
//
|
||
if( pSpool->Status & SPOOL_STATUS_DOCUMENTEVENT_ENABLED ){
|
||
|
||
|
||
if ( hLibrary = LoadPrinterDriver( hPrinter )) {
|
||
|
||
if( pfn = GetProcAddress( hLibrary, "DrvDocumentEvent" )){
|
||
|
||
//
|
||
// Disable the call so we don't recurse if the
|
||
// callback calls StartPage, etc.
|
||
//
|
||
pSpool->Status &= ~SPOOL_STATUS_DOCUMENTEVENT_ENABLED;
|
||
|
||
|
||
try {
|
||
|
||
ReturnValue = (*pfn)( hPrinter,
|
||
hdc,
|
||
iEsc,
|
||
cbIn,
|
||
pulIn,
|
||
cbOut,
|
||
pulOut);
|
||
|
||
} except(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
|
||
}
|
||
|
||
//
|
||
// Renable it now that we are done.
|
||
//
|
||
pSpool->Status |= SPOOL_STATUS_DOCUMENTEVENT_ENABLED;
|
||
|
||
}
|
||
|
||
FreeLibrary(hLibrary);
|
||
}
|
||
|
||
//
|
||
// If this is CREATEDCPRE and we failed, then don't retry until
|
||
// the next CreateDC.
|
||
//
|
||
if( DOCUMENTEVENT_EVENT( iEsc ) == DOCUMENTEVENT_CREATEDCPRE &&
|
||
ReturnValue <= 0 ){
|
||
|
||
pSpool->Status &= ~SPOOL_STATUS_DOCUMENTEVENT_ENABLED;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If it's a StartDocPost, a job was just added. Notify the
|
||
// tray icon if we haven't already.
|
||
//
|
||
if( DOCUMENTEVENT_EVENT( iEsc ) == DOCUMENTEVENT_STARTDOCPOST ){
|
||
|
||
if( !( pSpool->Status & SPOOL_STATUS_TRAYICON_NOTIFIED )){
|
||
|
||
//
|
||
// If we have a StartDocPost, then issue a notification so that
|
||
// the user's tray starts polling. pulIn[0] holds the JobId.
|
||
//
|
||
vUpdateTrayIcon( hPrinter, (DWORD)pulIn[0] );
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// If we have sent a notification, then by the next time we get a
|
||
// document event, we have completed any additional AddJobs or
|
||
// StartDocPrinters. Therefore we can reset the TRAYICON_NOTIFIED
|
||
// flag, since any more AddJobs/StartDocPrinters are really new
|
||
// jobs.
|
||
//
|
||
pSpool->Status &= ~SPOOL_STATUS_TRAYICON_NOTIFIED;
|
||
}
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
|
||
/****************************************************************************
|
||
* BOOL QuerySpoolMode( hPrinter, pflSpoolMode, puVersion )
|
||
*
|
||
* This function is called by GDI at StartDoc time when printing to an EMF.
|
||
* It tell GDI whether to embed fonts in the job as well as what version of
|
||
* EMF to generate.
|
||
*
|
||
* For now I am doing something hacky: I'm calling GetPrinterInfo to determine
|
||
* if the target is a remote machine and if so always telling GDI to embed
|
||
* fonts which don't exist on the server into spool file. Eventually this
|
||
* call will be routed to the print processor on the target machine which
|
||
* will use some UI/registry setting to determine what to do with fonts and
|
||
* set the version number correctly.
|
||
*
|
||
* History:
|
||
* 5/13/1995 by Gerrit van Wingerden [gerritv]
|
||
* Wrote it.
|
||
*****************************************************************************/
|
||
|
||
// !!later move this define to the appropriate header file
|
||
|
||
#define QSM_DOWNLOADFONTS 0x00000001
|
||
|
||
BOOL
|
||
QuerySpoolMode(
|
||
HANDLE hPrinter,
|
||
LONG *pflSpoolMode,
|
||
ULONG *puVersion
|
||
)
|
||
{
|
||
DWORD dwPrinterInfoSize = 0;
|
||
PRINTER_INFO_2 *pPrinterInfo2 = NULL;
|
||
BOOL bRet = FALSE;
|
||
|
||
GetPrinter( hPrinter, 2, NULL, 0, &dwPrinterInfoSize );
|
||
|
||
pPrinterInfo2 = (PRINTER_INFO_2*) LocalAlloc(LPTR, dwPrinterInfoSize);
|
||
|
||
if( pPrinterInfo2 == NULL )
|
||
{
|
||
DBGMSG( DBG_WARNING, ( "Unable to alloc %d bytes.\n", dwPrinterInfoSize ));
|
||
return bRet;
|
||
}
|
||
|
||
if( GetPrinter( hPrinter,
|
||
2,
|
||
(LPBYTE) pPrinterInfo2,
|
||
dwPrinterInfoSize,
|
||
&dwPrinterInfoSize ) )
|
||
{
|
||
*puVersion = 0x00010000; // version 1.0
|
||
|
||
//
|
||
// No server means we are printing locally
|
||
//
|
||
*pflSpoolMode = ( pPrinterInfo2->pServerName == NULL ) ?
|
||
0 :
|
||
QSM_DOWNLOADFONTS;
|
||
bRet = TRUE;
|
||
}
|
||
else
|
||
{
|
||
DBGMSG( DBG_WARNING, ( "QuerySpoolMode: GetPrinter failed %d.\n", GetLastError( )));
|
||
}
|
||
|
||
LocalFree( pPrinterInfo2 );
|
||
return bRet;
|
||
|
||
}
|
||
|
||
|
||
BOOL
|
||
SetPortW(
|
||
LPWSTR pszName,
|
||
LPWSTR pszPortName,
|
||
DWORD dwLevel,
|
||
LPBYTE pPortInfo
|
||
)
|
||
{
|
||
BOOL ReturnValue;
|
||
PORT_CONTAINER PortContainer;
|
||
|
||
switch (dwLevel) {
|
||
|
||
case 3:
|
||
if ( !pPortInfo ) {
|
||
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
return FALSE;
|
||
}
|
||
|
||
PortContainer.Level = dwLevel;
|
||
PortContainer.PortInfo.pPortInfo3 = (PPORT_INFO_3)pPortInfo;
|
||
break;
|
||
|
||
default:
|
||
SetLastError(ERROR_INVALID_LEVEL);
|
||
return FALSE;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
if ( ReturnValue = RpcSetPort(pszName, pszPortName, &PortContainer) ) {
|
||
|
||
SetLastError(ReturnValue);
|
||
ReturnValue = FALSE;
|
||
} else {
|
||
|
||
ReturnValue = TRUE;
|
||
}
|
||
} RpcExcept(1) {
|
||
|
||
SetLastError(TranslateExceptionCode(RpcExceptionCode()));
|
||
ReturnValue = FALSE;
|
||
|
||
} RpcEndExcept
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOL
|
||
bValidDevModeW(
|
||
const DEVMODE *pDevMode
|
||
)
|
||
|
||
/*++
|
||
|
||
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( !pDevMode ){
|
||
return FALSE;
|
||
}
|
||
|
||
if( pDevMode->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.
|
||
//
|
||
SPLASSERT( pDevMode->dmSize >= MIN_DEVMODE_SIZEW );
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|