1 /*
2  * PROJECT:     ReactOS Local Spooler
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Implementation of the Thread that actually performs the printing process
5  * COPYRIGHT:   Copyright 2015-2017 Colin Finck (colin@reactos.org)
6  */
7 
8 #include "precomp.h"
9 
10 DWORD WINAPI
PrintingThreadProc(PLOCAL_JOB pJob)11 PrintingThreadProc(PLOCAL_JOB pJob)
12 {
13     const DWORD cchMaxJobIdDigits = 5;              // Job ID is limited to 5 decimal digits, see IS_VALID_JOB_ID
14     const WCHAR wszJobAppendix[] = L", Job ";
15     const DWORD cchJobAppendix = _countof(wszJobAppendix) - 1;
16     const WCHAR wszPortAppendix[] = L", Port";
17 
18     DWORD cchPortName;
19     DWORD cchPrinterName;
20     DWORD dwErrorCode;
21     HANDLE hPrintProcessor = NULL;
22     PLOCAL_PRINT_PROCESSOR pPrintProcessor = pJob->pPrintProcessor;
23     PRINTPROCESSOROPENDATA OpenData;
24     PWSTR pwszPrinterAndJob = NULL;
25     PWSTR pwszPrinterPort = NULL;
26     PWSTR pwszSPLFile = NULL;
27 
28     TRACE("PrintingThreadProc(%p)\n", pJob);
29 
30     // Prepare the pPrinterName parameter.
31     // This is the string for LocalOpenPrinter to open a port (e.g. "LPT1:, Port").
32     cchPortName = wcslen(pJob->pPrinter->pPort->pwszName);
33     pwszPrinterPort = DllAllocSplMem(cchPortName * sizeof(WCHAR) + sizeof(wszPortAppendix));
34     if (!pwszPrinterPort)
35     {
36         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
37         ERR("DllAllocSplMem failed!\n");
38         goto Cleanup;
39     }
40 
41     CopyMemory(pwszPrinterPort, pJob->pPrinter->pPort->pwszName, cchPortName * sizeof(WCHAR));
42     CopyMemory(&pwszPrinterPort[cchPortName], wszPortAppendix, sizeof(wszPortAppendix));
43 
44     // Prepare the pPrintProcessorOpenData parameter.
45     OpenData.JobId = pJob->dwJobID;
46     OpenData.pDatatype = pJob->pwszDatatype;
47     OpenData.pDevMode = pJob->pDevMode;
48     OpenData.pDocumentName = pJob->pwszDocumentName;
49     OpenData.pOutputFile = NULL;
50     OpenData.pParameters = pJob->pwszPrintProcessorParameters;
51     OpenData.pPrinterName = pJob->pPrinter->pwszPrinterName;
52 
53     // Associate our job to the port. The next port handle created through LocalOpenPrinter will pick this up.
54     // LocalStartDocPrinter needs this information to call StartDocPort of the Print Monitor, but as the parameters
55     // for LocalOpenPrinter and LocalStartDocPrinter are fixed, we can only pass over the information this way.
56     pJob->pPrinter->pPort->pNextJobToProcess = pJob;
57 
58     // Open a handle to the Print Processor.
59     hPrintProcessor = pPrintProcessor->pfnOpenPrintProcessor(pwszPrinterPort, &OpenData);
60     if (!hPrintProcessor)
61     {
62         dwErrorCode = GetLastError();
63         ERR("OpenPrintProcessor failed with error %lu!\n", dwErrorCode);
64         goto Cleanup;
65     }
66 
67     // Let other functions use the Print Processor as well while it's opened.
68     pJob->hPrintProcessor = hPrintProcessor;
69 
70     // Prepare the pDocumentName parameter.
71     cchPrinterName = wcslen(OpenData.pPrinterName);
72     pwszPrinterAndJob = DllAllocSplMem((cchPrinterName + cchJobAppendix + cchMaxJobIdDigits + 1) * sizeof(WCHAR));
73     if (!pwszPrinterAndJob)
74     {
75         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
76         ERR("DllAllocSplMem failed!\n");
77         goto Cleanup;
78     }
79 
80     CopyMemory(pwszPrinterAndJob, OpenData.pPrinterName, cchPrinterName * sizeof(WCHAR));
81     CopyMemory(&pwszPrinterAndJob[cchPrinterName], wszJobAppendix, cchJobAppendix * sizeof(WCHAR));
82     _ultow(OpenData.JobId, &pwszPrinterAndJob[cchPrinterName + cchJobAppendix], 10);
83 
84     // Printing starts here.
85     pJob->dwStatus |= JOB_STATUS_PRINTING;
86 
87     // Print the document.
88     // Note that pJob is freed after this function, so we may not access it anymore.
89     if (!pPrintProcessor->pfnPrintDocumentOnPrintProcessor(hPrintProcessor, pwszPrinterAndJob))
90     {
91         dwErrorCode = GetLastError();
92         ERR("PrintDocumentOnPrintProcessor failed with error %lu!\n", dwErrorCode);
93         goto Cleanup;
94     }
95 
96     // Close the Print Processor.
97     pPrintProcessor->pfnClosePrintProcessor(hPrintProcessor);
98     hPrintProcessor = NULL;
99 
100     // Delete the spool file.
101     pwszSPLFile = DllAllocSplMem(GetJobFilePath(L"SPL", 0, NULL));
102     if (!pwszSPLFile)
103     {
104         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
105         ERR("DllAllocSplMem failed!\n");
106         goto Cleanup;
107     }
108 
109     GetJobFilePath(L"SPL", OpenData.JobId, pwszSPLFile);
110     DeleteFileW(pwszSPLFile);
111 
112     // We were successful!
113     dwErrorCode = ERROR_SUCCESS;
114 
115 Cleanup:
116     if (hPrintProcessor)
117         pPrintProcessor->pfnClosePrintProcessor(hPrintProcessor);
118 
119     if (pwszPrinterPort)
120         DllFreeSplMem(pwszPrinterPort);
121 
122     if (pwszPrinterAndJob)
123         DllFreeSplMem(pwszPrinterAndJob);
124 
125     if (pwszSPLFile)
126         DllFreeSplMem(pwszSPLFile);
127 
128     return dwErrorCode;
129 }
130