From 14711237a177391ac2ef87c2c80b402215380a47 Mon Sep 17 00:00:00 2001 From: Colin Finck Date: Sun, 28 Jun 2015 15:51:32 +0000 Subject: [PATCH] [LOCALSPL] - Partly implement LocalScheduleJob. - Set the default status to JOB_STATUS_SPOOLING in LocalAddJob. - Fix file sharing flags in ReadJobShadowFile and WriteJobShadowFile. [SPOOLSS, SPOOLSV, WINSPOOL] - Forward the newly implemented ScheduleJob call all the way down to localspl.dll. - Stub ReadPrinter. [WINPRINT] Implement a very simple RAW Print Processor that just takes the input and forwards it to the Print Monitor. This one doesn't even do pausing or multiple copies yet. The implementation includes: - Implemented ClosePrintProcessor, OpenPrintProcessor and PrintDocumentOnPrintProcessor (apart from the previously implemented EnumPrintProcessorDatatypesW). - Stubbed ControlPrintProcessor and GetPrintProcessorCapabilities. svn path=/branches/colins-printing-for-freedom/; revision=68304 --- reactos/win32ss/printing/base/spoolss/jobs.c | 6 + .../win32ss/printing/base/spoolss/printers.c | 6 + .../printing/base/spoolss/spoolss.spec | 4 +- reactos/win32ss/printing/base/spoolsv/jobs.c | 16 +- reactos/win32ss/printing/base/winspool/jobs.c | 21 +++ .../win32ss/printing/base/winspool/printers.c | 6 + .../printing/base/winspool/winspool.spec | 4 +- .../processors/winprint/CMakeLists.txt | 2 +- .../printing/processors/winprint/main.c | 177 +++++++++++++++++- .../printing/processors/winprint/precomp.h | 15 ++ .../printing/processors/winprint/raw.c | 100 ++++++++++ .../processors/winprint/winprint.spec | 10 +- .../printing/providers/localspl/jobs.c | 66 ++++++- .../printing/providers/localspl/main.c | 2 +- .../printing/providers/localspl/precomp.h | 5 +- 15 files changed, 418 insertions(+), 22 deletions(-) create mode 100644 reactos/win32ss/printing/processors/winprint/raw.c diff --git a/reactos/win32ss/printing/base/spoolss/jobs.c b/reactos/win32ss/printing/base/spoolss/jobs.c index 2ecaba1d159..5d85a69e4aa 100644 --- a/reactos/win32ss/printing/base/spoolss/jobs.c +++ b/reactos/win32ss/printing/base/spoolss/jobs.c @@ -25,6 +25,12 @@ GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob, DWORD cbBuf, LPD return LocalSplFuncs.fpGetJob(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded); } +BOOL WINAPI +ScheduleJob(HANDLE hPrinter, DWORD dwJobID) +{ + return LocalSplFuncs.fpScheduleJob(hPrinter, dwJobID); +} + BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Command) { diff --git a/reactos/win32ss/printing/base/spoolss/printers.c b/reactos/win32ss/printing/base/spoolss/printers.c index 2fa86513587..f080912b1b7 100644 --- a/reactos/win32ss/printing/base/spoolss/printers.c +++ b/reactos/win32ss/printing/base/spoolss/printers.c @@ -50,6 +50,12 @@ OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefau return LocalSplFuncs.fpOpenPrinter(pPrinterName, phPrinter, pDefault); } +BOOL WINAPI +ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead) +{ + return FALSE; +} + DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo) { diff --git a/reactos/win32ss/printing/base/spoolss/spoolss.spec b/reactos/win32ss/printing/base/spoolss/spoolss.spec index e4539213717..352ff6915d3 100644 --- a/reactos/win32ss/printing/base/spoolss/spoolss.spec +++ b/reactos/win32ss/printing/base/spoolss/spoolss.spec @@ -114,7 +114,7 @@ @ stub ProvidorFindClosePrinterChangeNotification @ stub ProvidorFindFirstPrinterChangeNotification @ stub pszDbgAllocMsgA -@ stub ReadPrinter +@ stdcall ReadPrinter(long ptr long ptr) @ stdcall ReallocSplMem(ptr long long) @ stdcall ReallocSplStr(ptr ptr) @ stub RemoteFindFirstPrinterChangeNotification @@ -132,7 +132,7 @@ @ stub RouterFreePrinterNotifyInfo @ stub RouterRefreshPrinterChangeNotification @ stub RouterReplyPrinter -@ stub ScheduleJob +@ stdcall ScheduleJob(long long) @ stub SeekPrinter @ stub SendRecvBidiData @ stub SetAllocFailCount diff --git a/reactos/win32ss/printing/base/spoolsv/jobs.c b/reactos/win32ss/printing/base/spoolsv/jobs.c index 29d36927f64..e9c2bf027fb 100644 --- a/reactos/win32ss/printing/base/spoolsv/jobs.c +++ b/reactos/win32ss/printing/base/spoolsv/jobs.c @@ -139,8 +139,20 @@ _RpcGetJob(WINSPOOL_PRINTER_HANDLE hPrinter, DWORD JobId, DWORD Level, BYTE* pJo DWORD _RpcScheduleJob(WINSPOOL_PRINTER_HANDLE hPrinter, DWORD JobId) { - UNIMPLEMENTED; - return ERROR_INVALID_FUNCTION; + DWORD dwErrorCode; + + dwErrorCode = RpcImpersonateClient(NULL); + if (dwErrorCode != ERROR_SUCCESS) + { + ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode); + return dwErrorCode; + } + + ScheduleJob(hPrinter, JobId); + dwErrorCode = GetLastError(); + + RpcRevertToSelf(); + return dwErrorCode; } DWORD diff --git a/reactos/win32ss/printing/base/winspool/jobs.c b/reactos/win32ss/printing/base/winspool/jobs.c index 890bab9481c..f5931ef9d88 100644 --- a/reactos/win32ss/printing/base/winspool/jobs.c +++ b/reactos/win32ss/printing/base/winspool/jobs.c @@ -163,6 +163,27 @@ GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWO return (dwErrorCode == ERROR_SUCCESS); } +BOOL WINAPI +ScheduleJob(HANDLE hPrinter, DWORD dwJobID) +{ + DWORD dwErrorCode; + + // Do the RPC call + RpcTryExcept + { + dwErrorCode = _RpcScheduleJob(hPrinter, dwJobID); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcSetJob failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); +} + BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Command) { diff --git a/reactos/win32ss/printing/base/winspool/printers.c b/reactos/win32ss/printing/base/winspool/printers.c index dd3e271fc26..11a1cf7fd7b 100644 --- a/reactos/win32ss/printing/base/winspool/printers.c +++ b/reactos/win32ss/printing/base/winspool/printers.c @@ -212,6 +212,12 @@ OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefau return bReturnValue; } +BOOL WINAPI +ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead) +{ + return FALSE; +} + DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo) { diff --git a/reactos/win32ss/printing/base/winspool/winspool.spec b/reactos/win32ss/printing/base/winspool/winspool.spec index 09cb690d9a1..9f056aae311 100644 --- a/reactos/win32ss/printing/base/winspool/winspool.spec +++ b/reactos/win32ss/printing/base/winspool/winspool.spec @@ -168,10 +168,10 @@ 267 stub QueryColorProfile 268 stub QueryRemoteFonts 269 stub QuerySpoolMode -270 stub ReadPrinter +270 stdcall ReadPrinter(long ptr long ptr) 271 stub ResetPrinterA 272 stub ResetPrinterW -273 stub ScheduleJob +273 stdcall ScheduleJob(long long) 274 stub SeekPrinter 275 stub SetAllocFailCount 276 stub SetFormA diff --git a/reactos/win32ss/printing/processors/winprint/CMakeLists.txt b/reactos/win32ss/printing/processors/winprint/CMakeLists.txt index 199e7f9bb96..713a5a91db7 100644 --- a/reactos/win32ss/printing/processors/winprint/CMakeLists.txt +++ b/reactos/win32ss/printing/processors/winprint/CMakeLists.txt @@ -3,12 +3,12 @@ spec2def(winprint.dll winprint.spec ADD_IMPORTLIB) list(APPEND SOURCE main.c + raw.c precomp.h) add_library(winprint SHARED ${SOURCE} winprint.rc - ${CMAKE_CURRENT_BINARY_DIR}/winprint_stubs.c ${CMAKE_CURRENT_BINARY_DIR}/winprint.def) set_module_type(winprint win32dll UNICODE) diff --git a/reactos/win32ss/printing/processors/winprint/main.c b/reactos/win32ss/printing/processors/winprint/main.c index bb45bfa1589..bfba2812184 100644 --- a/reactos/win32ss/printing/processors/winprint/main.c +++ b/reactos/win32ss/printing/processors/winprint/main.c @@ -7,11 +7,69 @@ #include "precomp.h" -PCWSTR pwszDatatypes[] = { +// Local Constants +static PCWSTR _pwszDatatypes[] = { L"RAW", 0 }; + +/** + * @name ClosePrintProcessor + * + * Closes a Print Processor Handle that has previously been opened through OpenPrintProcessor. + * + * @param hPrintProcessor + * The return value of a previous successful OpenPrintProcessor call. + * + * @return + * TRUE if the Print Processor Handle was successfully closed, FALSE otherwise. + * A more specific error code can be obtained through GetLastError. + */ +BOOL WINAPI +ClosePrintProcessor(HANDLE hPrintProcessor) +{ + DWORD dwErrorCode; + PWINPRINT_HANDLE pHandle; + + // Sanity checks + if (!hPrintProcessor) + { + dwErrorCode = ERROR_INVALID_HANDLE; + goto Cleanup; + } + + pHandle = (PWINPRINT_HANDLE)hPrintProcessor; + + // Free all structure fields for which memory has been allocated. + if (pHandle->pwszDatatype) + DllFreeSplStr(pHandle->pwszDatatype); + + if (pHandle->pwszDocumentName) + DllFreeSplStr(pHandle->pwszDocumentName); + + if (pHandle->pwszOutputFile) + DllFreeSplStr(pHandle->pwszOutputFile); + + if (pHandle->pwszPrinterPort) + DllFreeSplStr(pHandle->pwszPrinterPort); + + // Finally free the WINSPOOL_HANDLE structure itself. + DllFreeSplMem(pHandle); + dwErrorCode = ERROR_SUCCESS; + +Cleanup: + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); +} + +BOOL WINAPI +ControlPrintProcessor(HANDLE hPrintProcessor, DWORD Command) +{ + UNIMPLEMENTED; + return FALSE; +} + /** * @name EnumPrintProcessorDatatypesW * @@ -50,7 +108,7 @@ EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName, DWORD Lev { DWORD cbDatatype; DWORD dwErrorCode; - DWORD dwOffsets[_countof(pwszDatatypes)]; + DWORD dwOffsets[_countof(_pwszDatatypes)]; PCWSTR* pCurrentDatatype; PDWORD pCurrentOffset = dwOffsets; @@ -65,7 +123,7 @@ EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName, DWORD Lev *pcbNeeded = 0; *pcReturned = 0; - for (pCurrentDatatype = pwszDatatypes; *pCurrentDatatype; pCurrentDatatype++) + for (pCurrentDatatype = _pwszDatatypes; *pCurrentDatatype; pCurrentDatatype++) { cbDatatype = (wcslen(*pCurrentDatatype) + 1) * sizeof(WCHAR); *pcbNeeded += sizeof(DATATYPES_INFO_1W) + cbDatatype; @@ -93,7 +151,7 @@ EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName, DWORD Lev // Copy over all datatypes. *pCurrentOffset = MAXDWORD; - PackStrings(pwszDatatypes, pDatatypes, dwOffsets, &pDatatypes[*pcbNeeded]); + PackStrings(_pwszDatatypes, pDatatypes, dwOffsets, &pDatatypes[*pcbNeeded]); dwErrorCode = ERROR_SUCCESS; @@ -101,3 +159,114 @@ Cleanup: SetLastError(dwErrorCode); return (dwErrorCode == ERROR_SUCCESS); } + + +DWORD WINAPI +GetPrintProcessorCapabilities(PWSTR pValueName, DWORD dwAttributes, PBYTE pData, DWORD nSize, PDWORD pcbNeeded) +{ + UNIMPLEMENTED; + return 0; +} + +/** + * @name OpenPrintProcessor + * + * Prepares this Print Processor for processing a document. + * + * @param pPrinterName + * String in the format "\\COMPUTERNAME\Port:, Port" that is passed to OpenPrinterW for writing to the Print Monitor on the specified port. + * + * @param pPrintProcessorOpenData + * Pointer to a PRINTPROCESSOROPENDATA structure containing details about the print job to be processed. + * + * @return + * A Print Processor handle on success or NULL in case of a failure. This handle has to be passed to PrintDocumentOnPrintProcessor to do the actual processing. + * A more specific error code can be obtained through GetLastError. + */ +HANDLE WINAPI +OpenPrintProcessor(PWSTR pPrinterName, PPRINTPROCESSOROPENDATA pPrintProcessorOpenData) +{ + DWORD dwErrorCode; + HANDLE hReturnValue = NULL; + PWINPRINT_HANDLE pHandle = NULL; + + // Sanity checks + // This time a datatype needs to be given. We can't fall back to a default here. + if (!pPrintProcessorOpenData || !pPrintProcessorOpenData->pDatatype || !*pPrintProcessorOpenData->pDatatype) + { + dwErrorCode = ERROR_INVALID_PARAMETER; + goto Cleanup; + } + + // Create a new WINPRINT_HANDLE structure. and fill the relevant fields. + pHandle = DllAllocSplMem(sizeof(WINPRINT_HANDLE)); + + // Check what datatype was given. + if (wcsicmp(pPrintProcessorOpenData->pDatatype, L"RAW") == 0) + { + pHandle->Datatype = RAW; + } + else + { + dwErrorCode = ERROR_INVALID_DATATYPE; + goto Cleanup; + } + + // Fill the relevant fields. + pHandle->dwJobID = pPrintProcessorOpenData->JobId; + pHandle->pwszDatatype = AllocSplStr(pPrintProcessorOpenData->pDatatype); + pHandle->pwszDocumentName = AllocSplStr(pPrintProcessorOpenData->pDocumentName); + pHandle->pwszOutputFile = AllocSplStr(pPrintProcessorOpenData->pOutputFile); + pHandle->pwszPrinterPort = AllocSplStr(pPrintProcessorOpenData->pPrinterName); + + // We were successful! Return the handle and don't let the cleanup routine free it. + dwErrorCode = ERROR_SUCCESS; + hReturnValue = pHandle; + pHandle = NULL; + +Cleanup: + if (pHandle) + DllFreeSplMem(pHandle); + + SetLastError(dwErrorCode); + return hReturnValue; +} + +/** + * @name PrintDocumentOnPrintProcessor + * + * Prints a document on this Print Processor after a handle for the document has been opened through OpenPrintProcessor. + * + * @param hPrintProcessor + * The return value of a previous successful OpenPrintProcessor call. + * + * @param pDocumentName + * String in the format "Printer, Job N" describing the spooled job that is to be processed. + * + * @return + * TRUE if the document was successfully processed by this Print Processor, FALSE otherwise. + * A more specific error code can be obtained through GetLastError. + */ +BOOL WINAPI +PrintDocumentOnPrintProcessor(HANDLE hPrintProcessor, PWSTR pDocumentName) +{ + DWORD dwErrorCode; + PWINPRINT_HANDLE pHandle; + + // Sanity checks + if (!hPrintProcessor) + { + dwErrorCode = ERROR_INVALID_HANDLE; + goto Cleanup; + } + + pHandle = (PWINPRINT_HANDLE)hPrintProcessor; + + // Call the corresponding Print function for the datatype. + if (pHandle->Datatype == RAW) + dwErrorCode = PrintRawJob(pHandle, pDocumentName); + +Cleanup: + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); +} diff --git a/reactos/win32ss/printing/processors/winprint/precomp.h b/reactos/win32ss/printing/processors/winprint/precomp.h index 9ae0ecb3f80..f4f57e00569 100644 --- a/reactos/win32ss/printing/processors/winprint/precomp.h +++ b/reactos/win32ss/printing/processors/winprint/precomp.h @@ -22,4 +22,19 @@ #include WINE_DEFAULT_DEBUG_CHANNEL(winprint); +// Structures +typedef struct _WINPRINT_HANDLE +{ + enum { RAW } Datatype; + DWORD dwJobID; + PWSTR pwszDatatype; + PWSTR pwszDocumentName; + PWSTR pwszOutputFile; + PWSTR pwszPrinterPort; +} +WINPRINT_HANDLE, *PWINPRINT_HANDLE; + +// raw.c +DWORD PrintRawJob(PWINPRINT_HANDLE pHandle, PWSTR pwszPrinterAndJob); + #endif diff --git a/reactos/win32ss/printing/processors/winprint/raw.c b/reactos/win32ss/printing/processors/winprint/raw.c new file mode 100644 index 00000000000..3be598b957b --- /dev/null +++ b/reactos/win32ss/printing/processors/winprint/raw.c @@ -0,0 +1,100 @@ +/* + * PROJECT: ReactOS Standard Print Processor + * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation + * PURPOSE: Printing a job with RAW datatype + * COPYRIGHT: Copyright 2015 Colin Finck + */ + +#include "precomp.h" + +/** + * @name PrintRawJob + * + * @param pHandle + * Pointer to a WINPRINT_HANDLE structure containing information about this job. + * + * @param pwszPrinterAndJob + * String in the format "Printer, Job N" that is passed to OpenPrinterW to read from the spooled print job. + * + * @return + * An error code indicating success or failure. + */ +DWORD +PrintRawJob(PWINPRINT_HANDLE pHandle, PWSTR pwszPrinterAndJob) +{ + // Use a read buffer of 256 KB size like Windows does. + const DWORD cbReadBuffer = 262144; + + BOOL bStartedDoc = FALSE; + DOC_INFO_1W DocInfo1; + DWORD cbRead; + DWORD cbWritten; + DWORD dwErrorCode; + HANDLE hPrintJob; + HANDLE hPrintMonitor; + PBYTE pBuffer = NULL; + + // Open the spooled job to read from it. + if (!OpenPrinterW(pwszPrinterAndJob, &hPrintJob, NULL)) + { + dwErrorCode = GetLastError(); + ERR("OpenPrinterW failed for \"%S\" with error %lu!\n", pwszPrinterAndJob, GetLastError()); + goto Cleanup; + } + + // Open a Print Monitor handle to write to it. + if (!OpenPrinterW(pHandle->pwszPrinterPort, &hPrintMonitor, NULL)) + { + dwErrorCode = GetLastError(); + ERR("OpenPrinterW failed for \"%S\" with error %lu!\n", pHandle->pwszPrinterPort, GetLastError()); + goto Cleanup; + } + + // Fill the Document Information. + DocInfo1.pDatatype = pHandle->pwszDatatype; + DocInfo1.pDocName = pHandle->pwszDocumentName; + DocInfo1.pOutputFile = pHandle->pwszOutputFile; + + // Tell the Print Monitor that we're starting a new document. + if (!StartDocPrinterW(hPrintMonitor, 1, (PBYTE)&DocInfo1)) + { + dwErrorCode = GetLastError(); + ERR("StartDocPrinterW failed with error %lu!\n", GetLastError()); + goto Cleanup; + } + + bStartedDoc = TRUE; + + // Allocate a read buffer on the heap. This would easily exceed the stack size. + pBuffer = DllAllocSplMem(cbReadBuffer); + if (!pBuffer) + { + dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; + ERR("DllAllocSplMem failed with error %lu!\n", GetLastError()); + goto Cleanup; + } + + // Loop as long as data is available. + while (ReadPrinter(hPrintJob, pBuffer, cbReadBuffer, &cbRead) && cbRead) + { + // Write it to the Print Monitor. + WritePrinter(hPrintMonitor, pBuffer, cbRead, &cbWritten); + } + + dwErrorCode = ERROR_SUCCESS; + +Cleanup: + if (pBuffer) + DllFreeSplMem(pBuffer); + + if (bStartedDoc) + EndDocPrinter(hPrintMonitor); + + if (hPrintMonitor) + ClosePrinter(hPrintMonitor); + + if (hPrintJob) + ClosePrinter(hPrintJob); + + return dwErrorCode; +} diff --git a/reactos/win32ss/printing/processors/winprint/winprint.spec b/reactos/win32ss/printing/processors/winprint/winprint.spec index 947cf947a5a..36ed9760e0e 100644 --- a/reactos/win32ss/printing/processors/winprint/winprint.spec +++ b/reactos/win32ss/printing/processors/winprint/winprint.spec @@ -1,6 +1,6 @@ -@ stub ClosePrintProcessor -@ stub ControlPrintProcessor +@ stdcall ClosePrintProcessor(long) +@ stdcall ControlPrintProcessor(long long) @ stdcall EnumPrintProcessorDatatypesW(ptr ptr long ptr long ptr ptr) -@ stub GetPrintProcessorCapabilities -@ stub OpenPrintProcessor -@ stub PrintDocumentOnPrintProcessor +@ stdcall GetPrintProcessorCapabilities(wstr long ptr long ptr) +@ stdcall OpenPrintProcessor(wstr ptr) +@ stdcall PrintDocumentOnPrintProcessor(long wstr) diff --git a/reactos/win32ss/printing/providers/localspl/jobs.c b/reactos/win32ss/printing/providers/localspl/jobs.c index 1ffe281ffbb..773c610bd34 100644 --- a/reactos/win32ss/printing/providers/localspl/jobs.c +++ b/reactos/win32ss/printing/providers/localspl/jobs.c @@ -267,6 +267,7 @@ LocalAddJob(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcb pJob->pPrinter = pPrinterHandle->pPrinter; pJob->pPrintProcessor = pPrinterHandle->pPrinter->pPrintProcessor; pJob->dwPriority = DEF_PRIORITY; + pJob->dwStatus = JOB_STATUS_SPOOLING; pJob->pwszDatatype = AllocSplStr(pPrinterHandle->pwszDatatype); pJob->pwszDocumentName = AllocSplStr(wszDefaultDocumentName); CopyMemory(&pJob->DevMode, &pPrinterHandle->DevMode, sizeof(DEVMODEW)); @@ -986,6 +987,65 @@ Cleanup: return (dwErrorCode == ERROR_SUCCESS); } +BOOL WINAPI +LocalScheduleJob(HANDLE hPrinter, DWORD dwJobID) +{ + const WCHAR wszFolder[] = L"\\PRINTERS\\"; + const DWORD cchFolder = _countof(wszFolder) - 1; + + DWORD dwAttributes; + DWORD dwErrorCode; + PLOCAL_HANDLE pHandle; + PLOCAL_JOB pJob; + PLOCAL_PRINTER_HANDLE pPrinterHandle; + WCHAR wszFullPath[MAX_PATH]; + + // Check if this is a printer handle. + pHandle = (PLOCAL_HANDLE)hPrinter; + if (pHandle->HandleType != Printer) + { + dwErrorCode = ERROR_INVALID_HANDLE; + goto Cleanup; + } + + pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle; + + // Check if the Job ID is valid. + pJob = LookupElementSkiplist(&GlobalJobList, &dwJobID, NULL); + if (!pJob || pJob->pPrinter != pPrinterHandle->pPrinter) + { + dwErrorCode = ERROR_INVALID_PARAMETER; + goto Cleanup; + } + + // Construct the full path to the spool file. + CopyMemory(wszFullPath, wszSpoolDirectory, cchSpoolDirectory * sizeof(WCHAR)); + CopyMemory(&wszFullPath[cchSpoolDirectory], wszFolder, cchFolder * sizeof(WCHAR)); + swprintf(&wszFullPath[cchSpoolDirectory + cchFolder], L"%05lu.SPL", dwJobID); + + // Check if it exists. + dwAttributes = GetFileAttributesW(wszFullPath); + if (dwAttributes == INVALID_FILE_ATTRIBUTES || dwAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + dwErrorCode = ERROR_SPOOL_FILE_NOT_FOUND; + goto Cleanup; + } + + // Switch from spooling to printing. + pJob->dwStatus &= ~JOB_STATUS_SPOOLING; + pJob->dwStatus |= JOB_STATUS_PRINTING; + + // Write the job data into the shadow file. + wcscpy(wcsrchr(wszFullPath, L'.'), L".SHD"); + WriteJobShadowFile(wszFullPath, pJob); + + dwErrorCode = ERROR_SUCCESS; + +Cleanup: + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); +} + PLOCAL_JOB ReadJobShadowFile(PCWSTR pwszFilePath) { @@ -1001,7 +1061,7 @@ ReadJobShadowFile(PCWSTR pwszFilePath) PWSTR pwszPrintProcessor; // Try to open the file. - hFile = CreateFileW(pwszFilePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + hFile = CreateFileW(pwszFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (hFile == INVALID_HANDLE_VALUE) { ERR("CreateFileW failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath); @@ -1013,7 +1073,7 @@ ReadJobShadowFile(PCWSTR pwszFilePath) pShadowFile = DllAllocSplMem(cbFileSize); if (!pShadowFile) { - ERR("DllAllocSplMem failed with error %lufor file \"%S\"!\n", GetLastError(), pwszFilePath); + ERR("DllAllocSplMem failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath); goto Cleanup; } @@ -1110,7 +1170,7 @@ WriteJobShadowFile(PWSTR pwszFilePath, const PLOCAL_JOB pJob) PSHD_HEADER pShadowFile = NULL; // Try to open the SHD file. - hSHDFile = CreateFileW(pwszFilePath, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL); + hSHDFile = CreateFileW(pwszFilePath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); if (hSHDFile == INVALID_HANDLE_VALUE) { ERR("CreateFileW failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath); diff --git a/reactos/win32ss/printing/providers/localspl/main.c b/reactos/win32ss/printing/providers/localspl/main.c index f7bba030d92..c9b3e73db33 100644 --- a/reactos/win32ss/printing/providers/localspl/main.c +++ b/reactos/win32ss/printing/providers/localspl/main.c @@ -60,7 +60,7 @@ static const PRINTPROVIDOR _PrintProviderFunctions = { NULL, // fpReadPrinter LocalEndDocPrinter, // fpEndDocPrinter LocalAddJob, // fpAddJob - NULL, // fpScheduleJob + LocalScheduleJob, // fpScheduleJob NULL, // fpGetPrinterData NULL, // fpSetPrinterData NULL, // fpWaitForPrinterChange diff --git a/reactos/win32ss/printing/providers/localspl/precomp.h b/reactos/win32ss/printing/providers/localspl/precomp.h index a7f45db7f03..82d567dcb0c 100644 --- a/reactos/win32ss/printing/providers/localspl/precomp.h +++ b/reactos/win32ss/printing/providers/localspl/precomp.h @@ -48,8 +48,8 @@ typedef BOOL (WINAPI *PPrintDocumentOnPrintProcessor)(HANDLE, LPWSTR); // Structures /** -* Describes a Print Processor. -*/ + * Describes a Print Processor. + */ typedef struct _LOCAL_PRINT_PROCESSOR { LIST_ENTRY Entry; @@ -189,6 +189,7 @@ void InitializePrinterJobList(PLOCAL_PRINTER pPrinter); BOOL WINAPI LocalAddJob(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded); BOOL WINAPI LocalEnumJobs(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, PBYTE pStart, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned); BOOL WINAPI LocalGetJob(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pStart, DWORD cbBuf, LPDWORD pcbNeeded); +BOOL WINAPI LocalScheduleJob(HANDLE hPrinter, DWORD dwJobID); BOOL WINAPI LocalSetJob(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Command); PLOCAL_JOB ReadJobShadowFile(PCWSTR pwszFilePath); BOOL WriteJobShadowFile(PWSTR pwszFilePath, const PLOCAL_JOB pJob); -- 2.17.1