/*++ 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 #include #include #include #include #include #include #include #include "winspl.h" #include #include #include "client.h" #include #include #include #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; }