[LOCALSPL]
authorColin Finck <colin@reactos.org>
Sun, 28 Jun 2015 15:51:32 +0000 (15:51 +0000)
committerColin Finck <colin@reactos.org>
Sun, 28 Jun 2015 15:51:32 +0000 (15:51 +0000)
- 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

15 files changed:
reactos/win32ss/printing/base/spoolss/jobs.c
reactos/win32ss/printing/base/spoolss/printers.c
reactos/win32ss/printing/base/spoolss/spoolss.spec
reactos/win32ss/printing/base/spoolsv/jobs.c
reactos/win32ss/printing/base/winspool/jobs.c
reactos/win32ss/printing/base/winspool/printers.c
reactos/win32ss/printing/base/winspool/winspool.spec
reactos/win32ss/printing/processors/winprint/CMakeLists.txt
reactos/win32ss/printing/processors/winprint/main.c
reactos/win32ss/printing/processors/winprint/precomp.h
reactos/win32ss/printing/processors/winprint/raw.c [new file with mode: 0644]
reactos/win32ss/printing/processors/winprint/winprint.spec
reactos/win32ss/printing/providers/localspl/jobs.c
reactos/win32ss/printing/providers/localspl/main.c
reactos/win32ss/printing/providers/localspl/precomp.h

index 2ecaba1..5d85a69 100644 (file)
@@ -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)
 {
index 2fa8651..f080912 100644 (file)
@@ -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)
 {
index e453921..352ff69 100644 (file)
 @ 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
 @ stub RouterFreePrinterNotifyInfo
 @ stub RouterRefreshPrinterChangeNotification
 @ stub RouterReplyPrinter
-@ stub ScheduleJob
+@ stdcall ScheduleJob(long long)
 @ stub SeekPrinter
 @ stub SendRecvBidiData
 @ stub SetAllocFailCount
index 29d3692..e9c2bf0 100644 (file)
@@ -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
index 890bab9..f5931ef 100644 (file)
@@ -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)
 {
index dd3e271..11a1cf7 100644 (file)
@@ -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)
 {
index 09cb690..9f056aa 100644 (file)
 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
index 199e7f9..713a5a9 100644 (file)
@@ -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)
index bb45bfa..bfba281 100644 (file)
@@ -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);
+}
index 9ae0ecb..f4f57e0 100644 (file)
 #include <wine/debug.h>
 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 (file)
index 0000000..3be598b
--- /dev/null
@@ -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 <colin@reactos.org>
+ */
+
+#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;
+}
index 947cf94..36ed976 100644 (file)
@@ -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)
index 1ffe281..773c610 100644 (file)
@@ -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);
index f7bba03..c9b3e73 100644 (file)
@@ -60,7 +60,7 @@ static const PRINTPROVIDOR _PrintProviderFunctions = {
     NULL,                                       // fpReadPrinter
     LocalEndDocPrinter,                         // fpEndDocPrinter
     LocalAddJob,                                // fpAddJob
-    NULL,                                       // fpScheduleJob
+    LocalScheduleJob,                           // fpScheduleJob
     NULL,                                       // fpGetPrinterData
     NULL,                                       // fpSetPrinterData
     NULL,                                       // fpWaitForPrinterChange
index a7f45db..82d567d 100644 (file)
@@ -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);