1 /*
2  * PROJECT:     ReactOS Standard Print Processor
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Main functions
5  * COPYRIGHT:   Copyright 2015-2017 Colin Finck (colin@reactos.org)
6  */
7 
8 #include "precomp.h"
9 
10 // Local Constants
11 static PCWSTR _pwszDatatypes[] = {
12     L"RAW",
13     0
14 };
15 
16 
17 /**
18  * @name ClosePrintProcessor
19  *
20  * Closes a Print Processor Handle that has previously been opened through OpenPrintProcessor.
21  *
22  * @param hPrintProcessor
23  * The return value of a previous successful OpenPrintProcessor call.
24  *
25  * @return
26  * TRUE if the Print Processor Handle was successfully closed, FALSE otherwise.
27  * A more specific error code can be obtained through GetLastError.
28  */
29 BOOL WINAPI
30 ClosePrintProcessor(HANDLE hPrintProcessor)
31 {
32     DWORD dwErrorCode;
33     PWINPRINT_HANDLE pHandle;
34 
35     TRACE("ClosePrintProcessor(%p)\n", hPrintProcessor);
36 
37     // Sanity checks
38     if (!hPrintProcessor)
39     {
40         dwErrorCode = ERROR_INVALID_HANDLE;
41         goto Cleanup;
42     }
43 
44     pHandle = (PWINPRINT_HANDLE)hPrintProcessor;
45 
46     // Free all structure fields for which memory has been allocated.
47     if (pHandle->pwszDatatype)
48         DllFreeSplStr(pHandle->pwszDatatype);
49 
50     if (pHandle->pwszDocumentName)
51         DllFreeSplStr(pHandle->pwszDocumentName);
52 
53     if (pHandle->pwszOutputFile)
54         DllFreeSplStr(pHandle->pwszOutputFile);
55 
56     if (pHandle->pwszPrinterPort)
57         DllFreeSplStr(pHandle->pwszPrinterPort);
58 
59     // Finally free the WINSPOOL_HANDLE structure itself.
60     DllFreeSplMem(pHandle);
61     dwErrorCode = ERROR_SUCCESS;
62 
63 Cleanup:
64     SetLastError(dwErrorCode);
65     return (dwErrorCode == ERROR_SUCCESS);
66 }
67 
68 BOOL WINAPI
69 ControlPrintProcessor(HANDLE hPrintProcessor, DWORD Command)
70 {
71     TRACE("ControlPrintProcessor(%p, %lu)\n", hPrintProcessor, Command);
72 
73     UNIMPLEMENTED;
74     return FALSE;
75 }
76 
77 /**
78  * @name EnumPrintProcessorDatatypesW
79  *
80  * Obtains an array of all datatypes supported by this Print Processor.
81  *
82  * @param pName
83  * Server Name. Ignored here, because every caller of EnumPrintProcessorDatatypesW is interested in this Print Processor's information.
84  *
85  * @param pPrintProcessorName
86  * Print Processor Name. Ignored here, because every caller of EnumPrintProcessorDatatypesW is interested in this Print Processor's information.
87  *
88  * @param Level
89  * The level of the structure supplied through pDatatypes. This must be 1.
90  *
91  * @param pDatatypes
92  * Pointer to the buffer that receives an array of DATATYPES_INFO_1W structures.
93  * Can be NULL if you just want to know the required size of the buffer.
94  *
95  * @param cbBuf
96  * Size of the buffer you supplied for pDatatypes, in bytes.
97  *
98  * @param pcbNeeded
99  * Pointer to a variable that receives the required size of the buffer for pDatatypes, in bytes.
100  * This parameter mustn't be NULL!
101  *
102  * @param pcReturned
103  * Pointer to a variable that receives the number of elements of the DATATYPES_INFO_1W array.
104  * This parameter mustn't be NULL!
105  *
106  * @return
107  * TRUE if we successfully copied the array into pDatatypes, FALSE otherwise.
108  * A more specific error code can be obtained through GetLastError.
109  */
110 BOOL WINAPI
111 EnumPrintProcessorDatatypesW(PWSTR pName, PWSTR pPrintProcessorName, DWORD Level, PBYTE pDatatypes, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
112 {
113     DWORD cbDatatype;
114     DWORD dwDatatypeCount = 0;
115     DWORD dwOffsets[_countof(_pwszDatatypes)];
116     PCWSTR* pCurrentDatatype;
117     PDWORD pCurrentOffset = dwOffsets;
118 
119     TRACE("EnumPrintProcessorDatatypesW(%S, %S, %lu, %p, %lu, %p, %p)\n", pName, pPrintProcessorName, Level, pDatatypes, cbBuf, pcbNeeded, pcReturned);
120 
121     // Sanity checks
122     if (Level != 1 || !pcbNeeded || !pcReturned)
123         return FALSE;
124 
125     // Count the required buffer size and the number of datatypes.
126     *pcbNeeded = 0;
127     *pcReturned = 0;
128 
129     for (pCurrentDatatype = _pwszDatatypes; *pCurrentDatatype; pCurrentDatatype++)
130     {
131         cbDatatype = (wcslen(*pCurrentDatatype) + 1) * sizeof(WCHAR);
132         *pcbNeeded += sizeof(DATATYPES_INFO_1W) + cbDatatype;
133 
134         // Also calculate the offset in the output buffer of the pointer to this datatype string.
135         *pCurrentOffset = dwDatatypeCount * sizeof(DATATYPES_INFO_1W) + FIELD_OFFSET(DATATYPES_INFO_1W, pName);
136 
137         dwDatatypeCount++;
138         pCurrentOffset++;
139     }
140 
141     // Check if the supplied buffer is large enough.
142     if (cbBuf < *pcbNeeded)
143     {
144         SetLastError(ERROR_INSUFFICIENT_BUFFER);
145         return FALSE;
146     }
147 
148     // Check if a buffer was supplied at all.
149     if (!pDatatypes)
150     {
151         SetLastError(ERROR_INVALID_PARAMETER);
152         return FALSE;
153     }
154 
155     // Copy over all datatypes.
156     *pCurrentOffset = MAXDWORD;
157     PackStrings(_pwszDatatypes, pDatatypes, dwOffsets, &pDatatypes[*pcbNeeded]);
158 
159     *pcReturned = dwDatatypeCount;
160     return TRUE;
161 }
162 
163 
164 DWORD WINAPI
165 GetPrintProcessorCapabilities(PWSTR pValueName, DWORD dwAttributes, PBYTE pData, DWORD nSize, PDWORD pcbNeeded)
166 {
167     TRACE("GetPrintProcessorCapabilities(%S, %lu, %p, %lu, %p)\n", pValueName, dwAttributes, pData, nSize, pcbNeeded);
168 
169     UNIMPLEMENTED;
170     return 0;
171 }
172 
173 /**
174  * @name OpenPrintProcessor
175  *
176  * Prepares this Print Processor for processing a document.
177  *
178  * @param pPrinterName
179  * String in the format "\\COMPUTERNAME\Port:, Port" that is passed to OpenPrinterW for writing to the Print Monitor on the specified port.
180  *
181  * @param pPrintProcessorOpenData
182  * Pointer to a PRINTPROCESSOROPENDATA structure containing details about the print job to be processed.
183  *
184  * @return
185  * 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.
186  * A more specific error code can be obtained through GetLastError.
187  */
188 HANDLE WINAPI
189 OpenPrintProcessor(PWSTR pPrinterName, PPRINTPROCESSOROPENDATA pPrintProcessorOpenData)
190 {
191     DWORD dwErrorCode;
192     HANDLE hReturnValue = NULL;
193     PWINPRINT_HANDLE pHandle = NULL;
194 
195     TRACE("OpenPrintProcessor(%S, %p)\n", pPrinterName, pPrintProcessorOpenData);
196 
197     // Sanity checks
198     // This time a datatype needs to be given. We can't fall back to a default here.
199     if (!pPrintProcessorOpenData || !pPrintProcessorOpenData->pDatatype || !*pPrintProcessorOpenData->pDatatype)
200     {
201         dwErrorCode = ERROR_INVALID_PARAMETER;
202         goto Cleanup;
203     }
204 
205     // Create a new WINPRINT_HANDLE structure and fill the relevant fields.
206     pHandle = DllAllocSplMem(sizeof(WINPRINT_HANDLE));
207 
208     // Check what datatype was given.
209     if (_wcsicmp(pPrintProcessorOpenData->pDatatype, L"RAW") == 0)
210     {
211         pHandle->Datatype = RAW;
212     }
213     else
214     {
215         dwErrorCode = ERROR_INVALID_DATATYPE;
216         goto Cleanup;
217     }
218 
219     // Fill the relevant fields.
220     pHandle->dwJobID = pPrintProcessorOpenData->JobId;
221     pHandle->pwszDatatype = AllocSplStr(pPrintProcessorOpenData->pDatatype);
222     pHandle->pwszDocumentName = AllocSplStr(pPrintProcessorOpenData->pDocumentName);
223     pHandle->pwszOutputFile = AllocSplStr(pPrintProcessorOpenData->pOutputFile);
224     pHandle->pwszPrinterPort = AllocSplStr(pPrinterName);
225 
226     // We were successful! Return the handle and don't let the cleanup routine free it.
227     dwErrorCode = ERROR_SUCCESS;
228     hReturnValue = pHandle;
229     pHandle = NULL;
230 
231 Cleanup:
232     if (pHandle)
233         DllFreeSplMem(pHandle);
234 
235     SetLastError(dwErrorCode);
236     return hReturnValue;
237 }
238 
239 /**
240  * @name PrintDocumentOnPrintProcessor
241  *
242  * Prints a document on this Print Processor after a handle for the document has been opened through OpenPrintProcessor.
243  *
244  * @param hPrintProcessor
245  * The return value of a previous successful OpenPrintProcessor call.
246  *
247  * @param pDocumentName
248  * String in the format "Printer, Job N" describing the spooled job that is to be processed.
249  *
250  * @return
251  * TRUE if the document was successfully processed by this Print Processor, FALSE otherwise.
252  * A more specific error code can be obtained through GetLastError.
253  */
254 BOOL WINAPI
255 PrintDocumentOnPrintProcessor(HANDLE hPrintProcessor, PWSTR pDocumentName)
256 {
257     DWORD dwErrorCode;
258     PWINPRINT_HANDLE pHandle;
259 
260     TRACE("PrintDocumentOnPrintProcessor(%p, %S)\n", hPrintProcessor, pDocumentName);
261 
262     // Sanity checks
263     if (!hPrintProcessor)
264     {
265         dwErrorCode = ERROR_INVALID_HANDLE;
266         goto Cleanup;
267     }
268 
269     pHandle = (PWINPRINT_HANDLE)hPrintProcessor;
270 
271     // Call the corresponding Print function for the datatype.
272     if (pHandle->Datatype == RAW)
273         dwErrorCode = PrintRawJob(pHandle, pDocumentName);
274 
275 Cleanup:
276     SetLastError(dwErrorCode);
277     return (dwErrorCode == ERROR_SUCCESS);
278 }
279