/*++ Copyright (c) 1990-1994 Microsoft Corporation All rights reserved Module Name: spooler.c Abstract: Author: Environment: User Mode -Win32 Revision History: --*/ #include "precomp.h" #pragma hdrstop #include "winsprlp.h" // // RPC Buffer size 64K // #define BUFFER_SIZE 0x10000 DWORD StartDocPrinterW( HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo) { LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter; if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } return (*pPrintHandle->pProvidor->PrintProvidor.fpStartDocPrinter) (pPrintHandle->hPrinter, Level, pDocInfo); } BOOL StartPagePrinter( HANDLE hPrinter ) { LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter; if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } return (*pPrintHandle->pProvidor->PrintProvidor.fpStartPagePrinter) (pPrintHandle->hPrinter); } BOOL SplCommitSpoolData( HANDLE hPrinter, HANDLE hAppProcess, DWORD cbCommit, DWORD dwLevel, LPBYTE pSpoolFileInfo, DWORD cbBuf, LPDWORD pcbNeeded ) /*++ Function Description: Commits data written into the spool file. creates a new temp file handle for remote printing. Parameters: hPrinter - printer handle hAppProcess - application process handle cbCommit - number of bytes to commit (incremental) dwLevel - spoolfileinfo level pSpoolFileInfo - pointer to buffer cbBuf - buffer size pcbNeeded - pointer to return required buffer size Return Values: TRUE if sucessful; FALSE otherwise --*/ { BOOL bReturn = FALSE; DWORD cbTotalWritten, cbWritten, cbRead, cbToRead; BYTE *Buffer = NULL; HANDLE hFile, hSpoolerProcess = NULL, hFileApp = INVALID_HANDLE_VALUE; PSPOOL_FILE_INFO_1 pSpoolFileInfo1; LPPRINTHANDLE pPrintHandle = (LPPRINTHANDLE)hPrinter; // Check Handle validity if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) { SetLastError(ERROR_INVALID_HANDLE); return bReturn; } // Check for valid level and sufficient buffer switch (dwLevel) { case 1: if (cbBuf < sizeof(SPOOL_FILE_INFO_1)) { SetLastError(ERROR_INSUFFICIENT_BUFFER); *pcbNeeded = sizeof(SPOOL_FILE_INFO_1); goto CleanUp; } pSpoolFileInfo1 = (PSPOOL_FILE_INFO_1)pSpoolFileInfo; break; default: SetLastError(ERROR_INVALID_LEVEL); goto CleanUp; } // Initialize spoolfileinfo1 struct pSpoolFileInfo1->dwVersion = 1; pSpoolFileInfo1->hSpoolFile = INVALID_HANDLE_VALUE; pSpoolFileInfo1->dwAttributes = SPOOL_FILE_PERSISTENT; if (pPrintHandle->pProvidor == pLocalProvidor) { bReturn = (pLocalProvidor->PrintProvidor.fpCommitSpoolData)(pPrintHandle->hPrinter, cbCommit); return bReturn; } // For remote printing send the temp file across the wire using WritePrinter if (pPrintHandle->hFileSpooler == INVALID_HANDLE_VALUE) { SetLastError(ERROR_INVALID_HANDLE); return bReturn; } hFile = pPrintHandle->hFileSpooler; if (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == 0xffffffff) { goto CleanUp; } // // Use a Buffer to send Data over RPC. // Buffer = AllocSplMem(BUFFER_SIZE); if ( !Buffer ) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto CleanUp; } while ((cbToRead = min(cbCommit, BUFFER_SIZE)) && ReadFile(hFile, Buffer, cbToRead, &cbRead, NULL)) { cbCommit -= cbRead; for (cbTotalWritten = 0; cbTotalWritten < cbRead; cbTotalWritten += cbWritten) { if (!(*pPrintHandle->pProvidor->PrintProvidor.fpWritePrinter) (pPrintHandle->hPrinter, (LPBYTE)Buffer + cbTotalWritten, cbRead - cbTotalWritten, &cbWritten)) { goto CleanUp; } } } if (Buffer) { FreeSplMem(Buffer); Buffer = NULL; } if ((cbToRead != 0) || (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == 0xffffffff)) { goto CleanUp; } if ((hSpoolerProcess = GetCurrentProcess()) && DuplicateHandle(hSpoolerProcess, pPrintHandle->hFileSpooler, hAppProcess, &hFileApp, 0, TRUE, DUPLICATE_SAME_ACCESS)) { pSpoolFileInfo1->dwVersion = 1; pSpoolFileInfo1->hSpoolFile = hFileApp; pSpoolFileInfo1->dwAttributes = SPOOL_FILE_TEMPORARY; bReturn = TRUE; } CleanUp: if (Buffer) { FreeSplMem(Buffer); } if (hSpoolerProcess) { CloseHandle(hSpoolerProcess); } return bReturn; } BOOL SplCloseSpoolFileHandle( HANDLE hPrinter ) /*++ Function Description: Closes the remote spool file handle for remote printing. Parameters: hPrinter - printer handle Return Values: TRUE if sucessful; FALSE otherwise --*/ { LPPRINTHANDLE pPrintHandle = (LPPRINTHANDLE)hPrinter; // Check Handle validity if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } if (pPrintHandle->pProvidor == pLocalProvidor) { return (pLocalProvidor->PrintProvidor.fpCloseSpoolFileHandle)(pPrintHandle->hPrinter); } else if ((pPrintHandle->hFileSpooler != INVALID_HANDLE_VALUE)) { // close temp files for remote printing CloseHandle(pPrintHandle->hFileSpooler); pPrintHandle->hFileSpooler = INVALID_HANDLE_VALUE; if (pPrintHandle->szTempSpoolFile) { HANDLE hToken = RevertToPrinterSelf(); if (!DeleteFile(pPrintHandle->szTempSpoolFile)) { MoveFileEx(pPrintHandle->szTempSpoolFile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); } if (hToken) { ImpersonatePrinterClient(hToken); } FreeSplMem(pPrintHandle->szTempSpoolFile); pPrintHandle->szTempSpoolFile = NULL; } } return TRUE; } BOOL SplGetSpoolFileInfo( HANDLE hPrinter, HANDLE hAppProcess, DWORD dwLevel, LPBYTE pSpoolFileInfo, DWORD cbBuf, LPDWORD pcbNeeded ) /*++ Function Description: Get spool file info for the job in hPrinter. For local jobs localspl returns the hFile. For remote jobs a temp file is created by the router. The file handle is dupped into the application. Parameters: hPrinter - printer handle hAppProcess - application process handle dwLevel - spool file info level pSpoolFileInfo - pointer to buffer cbBuf - buffer size pcbNeeded - pointer to return required buffer size Return Values: TRUE if sucessful; FALSE otherwise --*/ { HANDLE hFileSpooler = NULL, hFileApp = NULL; HANDLE hSpoolerProcess = NULL; BOOL bReturn = FALSE; DWORD dwSpoolerProcessID; LPWSTR pSpoolDir = NULL; PSPOOL_FILE_INFO_1 pSpoolFileInfo1; LPPRINTHANDLE pPrintHandle = (LPPRINTHANDLE)hPrinter; // Check Handle validity if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) { SetLastError(ERROR_INVALID_HANDLE); goto CleanUp; } // Check for valid level and sufficient buffer switch (dwLevel) { case 1: if (cbBuf < sizeof(SPOOL_FILE_INFO_1)) { SetLastError(ERROR_INSUFFICIENT_BUFFER); *pcbNeeded = sizeof(SPOOL_FILE_INFO_1); goto CleanUp; } pSpoolFileInfo1 = (PSPOOL_FILE_INFO_1)pSpoolFileInfo; break; default: SetLastError(ERROR_INVALID_LEVEL); goto CleanUp; } if (!(hSpoolerProcess = GetCurrentProcess())) { // Cant get a pseudo handle to the spooler goto CleanUp; } if ((pPrintHandle->pProvidor != pLocalProvidor) && (pPrintHandle->hFileSpooler != INVALID_HANDLE_VALUE)) { // Return cached temp file handle. bReturn = DuplicateHandle(hSpoolerProcess, pPrintHandle->hFileSpooler, hAppProcess, &hFileApp, 0, TRUE, DUPLICATE_SAME_ACCESS); if (bReturn) { pSpoolFileInfo1->dwVersion = 1; pSpoolFileInfo1->hSpoolFile = hFileApp; pSpoolFileInfo1->dwAttributes = SPOOL_FILE_TEMPORARY; } goto CleanUp; } if (pPrintHandle->pProvidor == pLocalProvidor) { bReturn = (pLocalProvidor->PrintProvidor.fpGetSpoolFileInfo)(pPrintHandle->hPrinter, NULL, &hFileApp, hSpoolerProcess, hAppProcess); if (bReturn) { pSpoolFileInfo1->dwVersion = 1; pSpoolFileInfo1->hSpoolFile = hFileApp; pSpoolFileInfo1->dwAttributes = SPOOL_FILE_PERSISTENT; } goto CleanUp; } else { bReturn = (pLocalProvidor->PrintProvidor.fpGetSpoolFileInfo)(NULL, &pSpoolDir, NULL, NULL, NULL); } // Remote Printing, create a temp file in the spool directory if (bReturn) { HANDLE hToken; // // Revert to system context to ensure that we can open the file. // hToken = RevertToPrinterSelf(); if ((pPrintHandle->szTempSpoolFile = AllocSplMem(MAX_PATH * sizeof(WCHAR))) && GetTempFileName(pSpoolDir, L"SPL", 0, pPrintHandle->szTempSpoolFile) && ((pPrintHandle->hFileSpooler = CreateFile(pPrintHandle->szTempSpoolFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL)) != INVALID_HANDLE_VALUE) && DuplicateHandle(hSpoolerProcess, pPrintHandle->hFileSpooler, hAppProcess, &hFileApp, 0, TRUE, DUPLICATE_SAME_ACCESS)) { pSpoolFileInfo1->dwVersion = 1; pSpoolFileInfo1->hSpoolFile = hFileApp; pSpoolFileInfo1->dwAttributes = SPOOL_FILE_TEMPORARY; } else { bReturn = FALSE; } if (hToken) { ImpersonatePrinterClient(hToken); } } CleanUp: if (hSpoolerProcess) { CloseHandle(hSpoolerProcess); } if (pSpoolDir) { FreeSplMem(pSpoolDir); } return bReturn; } BOOL WritePrinter( HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten ) { LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter; if (!pPrintHandle || (pPrintHandle->signature != PRINTHANDLE_SIGNATURE) || (pPrintHandle->hFileSpooler != INVALID_HANDLE_VALUE)) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } return (*pPrintHandle->pProvidor->PrintProvidor.fpWritePrinter) (pPrintHandle->hPrinter, pBuf, cbBuf, pcWritten); } BOOL SeekPrinter( HANDLE hPrinter, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER pliNewPointer, DWORD dwMoveMethod, BOOL bWritePrinter ) { LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter; LARGE_INTEGER liNewPointer; if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } // // Allow a NULL pliNewPointer to be passed in. // if( !pliNewPointer ){ pliNewPointer = &liNewPointer; } return (*pPrintHandle->pProvidor->PrintProvidor.fpSeekPrinter) ( pPrintHandle->hPrinter, liDistanceToMove, pliNewPointer, dwMoveMethod, bWritePrinter ); } BOOL FlushPrinter( HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten, DWORD cSleep ) /*++ Function Description: FlushPrinter is typically used by the driver to send a burst of zeros to the printer and introduce a delay in the i/o line to the printer. The spooler does not schedule any job for cSleep milliseconds. Parameters: hPrinter - printer handle pBuf - buffer to be sent to the printer cbBuf - size of the buffer pcWritten - pointer to return the number of bytes written cSleep - sleep time in milliseconds. Return Values: TRUE if successful; FALSE otherwise --*/ { LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter; // // Check for valid printer handle // if (!pPrintHandle || (pPrintHandle->signature != PRINTHANDLE_SIGNATURE) || (pPrintHandle->hFileSpooler != INVALID_HANDLE_VALUE)) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } return (*pPrintHandle->pProvidor->PrintProvidor.fpFlushPrinter) (pPrintHandle->hPrinter, pBuf, cbBuf, pcWritten, cSleep); } BOOL EndPagePrinter( HANDLE hPrinter ) { LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter; if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } return (*pPrintHandle->pProvidor->PrintProvidor.fpEndPagePrinter) (pPrintHandle->hPrinter); } BOOL AbortPrinter( HANDLE hPrinter ) { LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter; if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } return (*pPrintHandle->pProvidor->PrintProvidor.fpAbortPrinter) (pPrintHandle->hPrinter); } BOOL ReadPrinter( HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pRead ) { LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter; if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } return (*pPrintHandle->pProvidor->PrintProvidor.fpReadPrinter) (pPrintHandle->hPrinter, pBuf, cbBuf, pRead); } BOOL SplReadPrinter( HANDLE hPrinter, LPBYTE *pBuf, DWORD cbBuf ) { LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter; if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } return (*pPrintHandle->pProvidor->PrintProvidor.fpSplReadPrinter) (pPrintHandle->hPrinter, pBuf, cbBuf); } BOOL EndDocPrinter( HANDLE hPrinter ) { LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter; if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } return (*pPrintHandle->pProvidor->PrintProvidor.fpEndDocPrinter) (pPrintHandle->hPrinter); } HANDLE CreatePrinterIC( HANDLE hPrinter, LPDEVMODEW pDevMode ) { LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter; HANDLE ReturnValue; PGDIHANDLE pGdiHandle; if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } pGdiHandle = AllocSplMem(sizeof(GDIHANDLE)); if (!pGdiHandle) { DBGMSG(DBG_WARN, ("Failed to alloc GDI handle.")); return FALSE; } ReturnValue = (HANDLE)(*pPrintHandle->pProvidor->PrintProvidor.fpCreatePrinterIC) (pPrintHandle->hPrinter, pDevMode); if (ReturnValue) { pGdiHandle->signature = GDIHANDLE_SIGNATURE; pGdiHandle->pProvidor = pPrintHandle->pProvidor; pGdiHandle->hGdi = ReturnValue; return pGdiHandle; } FreeSplMem(pGdiHandle); return FALSE; } BOOL PlayGdiScriptOnPrinterIC( HANDLE hPrinterIC, LPBYTE pIn, DWORD cIn, LPBYTE pOut, DWORD cOut, DWORD ul ) { PGDIHANDLE pGdiHandle=(PGDIHANDLE)hPrinterIC; if (!pGdiHandle || pGdiHandle->signature != GDIHANDLE_SIGNATURE) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } return (*pGdiHandle->pProvidor->PrintProvidor.fpPlayGdiScriptOnPrinterIC) (pGdiHandle->hGdi, pIn, cIn, pOut, cOut, ul); } BOOL DeletePrinterIC( HANDLE hPrinterIC ) { LPGDIHANDLE pGdiHandle=(LPGDIHANDLE)hPrinterIC; if (!pGdiHandle || pGdiHandle->signature != GDIHANDLE_SIGNATURE) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } if ((*pGdiHandle->pProvidor->PrintProvidor.fpDeletePrinterIC) (pGdiHandle->hGdi)) { FreeSplMem(pGdiHandle); return TRUE; } return FALSE; } DWORD PrinterMessageBox( HANDLE hPrinter, DWORD Error, HWND hWnd, LPWSTR pText, LPWSTR pCaption, DWORD dwType ) { LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter; if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } return (*pPrintHandle->pProvidor->PrintProvidor.fpPrinterMessageBox) (hPrinter, Error, hWnd, pText, pCaption, dwType); } DWORD SendRecvBidiData( IN HANDLE hPrinter, IN LPCTSTR pAction, IN PBIDI_REQUEST_CONTAINER pReqData, OUT PBIDI_RESPONSE_CONTAINER* ppResData ) { DWORD dwRet = ERROR_SUCCESS; LPPRINTHANDLE pPrintHandle = (LPPRINTHANDLE)hPrinter; // // Check for valid printer handle // if (!pPrintHandle || (pPrintHandle->signature != PRINTHANDLE_SIGNATURE) || (pPrintHandle->hFileSpooler != INVALID_HANDLE_VALUE)) { dwRet = ERROR_INVALID_HANDLE; } else { dwRet = (*pPrintHandle->pProvidor->PrintProvidor.fpSendRecvBidiData)(pPrintHandle->hPrinter, pAction, pReqData, ppResData); } return (dwRet); } /*++ Routine Name: SplPromptUIInUsersSession Routine Description: Pops message boxes in the user's session. For Whistler this function shows only message boxes in Spoolsv.exe. Arguments: hPrinter -- printer handle JobId -- job ID pUIParams -- UI parameters pResponse -- user's response Return Value: TRUE if succeeded Last Error: Win32 error --*/ BOOL SplPromptUIInUsersSession( IN HANDLE hPrinter, IN DWORD JobId, IN PSHOWUIPARAMS pUIParams, OUT DWORD *pResponse ) { typedef BOOL (*FPPROMPT_UI)(HANDLE, DWORD, PSHOWUIPARAMS, DWORD*); FPPROMPT_UI fpPromptUIPerSessionUser; BOOL bRetValue = FALSE; PPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter; if (pPrintHandle && pPrintHandle->signature == PRINTHANDLE_SIGNATURE) { if (pPrintHandle->pProvidor == pLocalProvidor && (fpPromptUIPerSessionUser = (FPPROMPT_UI)GetProcAddress(pLocalProvidor->hModule, "LclPromptUIPerSessionUser"))) { bRetValue = (*fpPromptUIPerSessionUser)(pPrintHandle->hPrinter, JobId, pUIParams, pResponse); } else { SetLastError(ERROR_NOT_SUPPORTED); } } else { SetLastError(ERROR_INVALID_HANDLE); } return bRetValue; } /*++ Routine Name: SplIsSessionZero Routine Description: Determine is user that submitted a certain job runs in Session 0. It is used by Canon monitor to determine when to show resource template base UI versus calling SplPromptUIInUsersSession. Arguments: hPrinter -- printer handle JobId -- job ID pIsSessionZero -- TRUE if user runs in Session 0 Return Value: Win32 last error Last Error: --*/ DWORD SplIsSessionZero( IN HANDLE hPrinter, IN DWORD JobId, OUT BOOL *pIsSessionZero ) { typedef DWORD (*FPISSESSIONZERO)(HANDLE, DWORD, BOOL*); FPISSESSIONZERO fpIsSessionZero; DWORD dwRetValue = ERROR_SUCCESS; PPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter; if (pPrintHandle && pPrintHandle->signature == PRINTHANDLE_SIGNATURE) { if (pPrintHandle->pProvidor == pLocalProvidor && (fpIsSessionZero = (FPISSESSIONZERO)GetProcAddress(pLocalProvidor->hModule, "LclIsSessionZero"))) { dwRetValue = (*fpIsSessionZero)(pPrintHandle->hPrinter, JobId, pIsSessionZero); } else { dwRetValue = ERROR_NOT_SUPPORTED; } } else { dwRetValue = ERROR_INVALID_HANDLE; } return dwRetValue; }