xref: /reactos/win32ss/printing/base/winspool/jobs.c (revision 41805926)
1 /*
2  * PROJECT:     ReactOS Spooler API
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Functions for managing print jobs
5  * COPYRIGHT:   Copyright 2015-2018 Colin Finck (colin@reactos.org)
6  */
7 
8 #include "precomp.h"
9 #include <marshalling/jobs.h>
10 
11 BOOL WINAPI
12 AddJobA(HANDLE hPrinter, DWORD Level, PBYTE pData, DWORD cbBuf, PDWORD pcbNeeded)
13 {
14     BOOL ret;
15 
16     FIXME("AddJobA(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
17 
18     if (Level != 1)
19     {
20         ERR("Level = %d, unsupported!\n", Level);
21         SetLastError(ERROR_INVALID_LEVEL);
22         return FALSE;
23     }
24 
25     ret = AddJobW(hPrinter, Level, pData, cbBuf, pcbNeeded);
26 
27     if (ret)
28     {
29         DWORD dwErrorCode;
30         ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)pData;
31         dwErrorCode = UnicodeToAnsiInPlace(addjobW->Path);
32         if (dwErrorCode != ERROR_SUCCESS)
33         {
34            ret = FALSE;
35         }
36     }
37     return ret;
38 }
39 
40 BOOL WINAPI
41 AddJobW(HANDLE hPrinter, DWORD Level, PBYTE pData, DWORD cbBuf, PDWORD pcbNeeded)
42 {
43     DWORD dwErrorCode;
44     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
45 
46     FIXME("AddJobW(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
47 
48     if (!pHandle)
49     {
50         dwErrorCode = ERROR_INVALID_HANDLE;
51         goto Cleanup;
52     }
53 
54     // Do the RPC call
55     RpcTryExcept
56     {
57         dwErrorCode = _RpcAddJob(pHandle->hPrinter, Level, pData, cbBuf, pcbNeeded);
58     }
59     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
60     {
61         dwErrorCode = RpcExceptionCode();
62         ERR("_RpcAddJob failed with exception code %lu!\n", dwErrorCode);
63     }
64     RpcEndExcept;
65 
66     if (dwErrorCode == ERROR_SUCCESS)
67     {
68         // Replace relative offset addresses in the output by absolute pointers.
69         MarshallUpStructure(cbBuf, pData, AddJobInfo1Marshalling.pInfo, AddJobInfo1Marshalling.cbStructureSize, TRUE);
70         pHandle->bJob = TRUE;
71         FIXME("Notify Tray Icon\n");
72     }
73 
74 Cleanup:
75     SetLastError(dwErrorCode);
76     return (dwErrorCode == ERROR_SUCCESS);
77 }
78 
79 BOOL WINAPI
80 EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
81 {
82     DWORD dwErrorCode, i;
83     JOB_INFO_1W* pji1w = (JOB_INFO_1W*)pJob;
84     JOB_INFO_2A* pji2a = (JOB_INFO_2A*)pJob;
85     JOB_INFO_2W* pji2w = (JOB_INFO_2W*)pJob;
86 
87     TRACE("EnumJobsA(%p, %lu, %lu, %lu, %p, %lu, %p, %p)\n", hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned);
88 
89     if ( Level == 3 )
90         return EnumJobsW( hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned );
91 
92     if ( EnumJobsW( hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned ) )
93     {
94         switch ( Level )
95         {
96             case 1:
97             {
98                 for ( i = 0; i < *pcReturned; i++ )
99                 {
100                     dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pPrinterName);
101                     if (dwErrorCode != ERROR_SUCCESS)
102                     {
103                         goto Cleanup;
104                     }
105                     dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pMachineName);
106                     if (dwErrorCode != ERROR_SUCCESS)
107                     {
108                         goto Cleanup;
109                     }
110                     dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pUserName);
111                     if (dwErrorCode != ERROR_SUCCESS)
112                     {
113                         goto Cleanup;
114                     }
115                     dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pDocument);
116                     if (dwErrorCode != ERROR_SUCCESS)
117                     {
118                         goto Cleanup;
119                     }
120                     dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pDatatype);
121                     if (dwErrorCode != ERROR_SUCCESS)
122                     {
123                         goto Cleanup;
124                     }
125                     dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pStatus);
126                     if (dwErrorCode != ERROR_SUCCESS)
127                     {
128                         goto Cleanup;
129                     }
130                 }
131             }
132                 break;
133 
134             case 2:
135             {
136                 for ( i = 0; i < *pcReturned; i++ )
137                 {
138                     dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pPrinterName);
139                     if (dwErrorCode != ERROR_SUCCESS)
140                     {
141                         goto Cleanup;
142                     }
143                     dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pMachineName);
144                     if (dwErrorCode != ERROR_SUCCESS)
145                     {
146                         goto Cleanup;
147                     }
148                     dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pUserName);
149                     if (dwErrorCode != ERROR_SUCCESS)
150                     {
151                         goto Cleanup;
152                     }
153                     dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pDocument);
154                     if (dwErrorCode != ERROR_SUCCESS)
155                     {
156                         goto Cleanup;
157                     }
158                     dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pNotifyName);
159                     if (dwErrorCode != ERROR_SUCCESS)
160                     {
161                         goto Cleanup;
162                     }
163                     dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pDatatype);
164                     if (dwErrorCode != ERROR_SUCCESS)
165                     {
166                         goto Cleanup;
167                     }
168                     dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pPrintProcessor);
169                     if (dwErrorCode != ERROR_SUCCESS)
170                     {
171                         goto Cleanup;
172                     }
173                     dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pParameters);
174                     if (dwErrorCode != ERROR_SUCCESS)
175                     {
176                         goto Cleanup;
177                     }
178                     dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pStatus);
179                     if (dwErrorCode != ERROR_SUCCESS)
180                     {
181                         goto Cleanup;
182                     }
183                     if ( pji2w[i].pDevMode )
184                     {
185                         RosConvertUnicodeDevModeToAnsiDevmode( pji2w[i].pDevMode, pji2a[i].pDevMode );
186                     }
187                 }
188             }
189                 break;
190         }
191         return TRUE;
192     }
193 Cleanup:
194     return FALSE;
195 }
196 
197 BOOL WINAPI
198 EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
199 {
200     DWORD dwErrorCode;
201     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
202 
203     TRACE("EnumJobsW(%p, %lu, %lu, %lu, %p, %lu, %p, %p)\n", hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned);
204 
205     if (!pHandle)
206     {
207         dwErrorCode = ERROR_INVALID_HANDLE;
208         goto Cleanup;
209     }
210 
211     // Do the RPC call
212     RpcTryExcept
213     {
214         dwErrorCode = _RpcEnumJobs(pHandle->hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned);
215     }
216     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
217     {
218         dwErrorCode = RpcExceptionCode();
219         ERR("_RpcEnumJobs failed with exception code %lu!\n", dwErrorCode);
220     }
221     RpcEndExcept;
222 
223     if (dwErrorCode == ERROR_SUCCESS)
224     {
225         // Replace relative offset addresses in the output by absolute pointers for JOB_INFO_1W and JOB_INFO_2W.
226         if (Level <= 2)
227         {
228             ASSERT(Level >= 1);
229             MarshallUpStructuresArray(cbBuf, pJob, *pcReturned, pJobInfoMarshalling[Level]->pInfo, pJobInfoMarshalling[Level]->cbStructureSize, TRUE);
230         }
231     }
232 
233 Cleanup:
234     SetLastError(dwErrorCode);
235     return (dwErrorCode == ERROR_SUCCESS);
236 }
237 
238 BOOL WINAPI
239 GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD pcbNeeded)
240 {
241     DWORD dwErrorCode;
242     JOB_INFO_1W* pji1w = (JOB_INFO_1W*)pJob;
243     JOB_INFO_2A* pji2a = (JOB_INFO_2A*)pJob;
244     JOB_INFO_2W* pji2w = (JOB_INFO_2W*)pJob;
245 
246     FIXME("GetJobA(%p, %lu, %lu, %p, %lu, %p)\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
247 
248     if ( Level == 3 )
249         return GetJobW( hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded );
250 
251     if ( GetJobW( hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded ) )
252     {
253         switch ( Level )
254         {
255             case 1:
256                 dwErrorCode = UnicodeToAnsiInPlace(pji1w->pPrinterName);
257                 if (dwErrorCode != ERROR_SUCCESS)
258                 {
259                     goto Cleanup;
260                 }
261                 dwErrorCode = UnicodeToAnsiInPlace(pji1w->pMachineName);
262                 if (dwErrorCode != ERROR_SUCCESS)
263                 {
264                     goto Cleanup;
265                 }
266                 dwErrorCode = UnicodeToAnsiInPlace(pji1w->pUserName);
267                 if (dwErrorCode != ERROR_SUCCESS)
268                 {
269                     goto Cleanup;
270                 }
271                 dwErrorCode = UnicodeToAnsiInPlace(pji1w->pDocument);
272                 if (dwErrorCode != ERROR_SUCCESS)
273                 {
274                     goto Cleanup;
275                 }
276                 dwErrorCode = UnicodeToAnsiInPlace(pji1w->pDatatype);
277                 if (dwErrorCode != ERROR_SUCCESS)
278                 {
279                     goto Cleanup;
280                 }
281                 dwErrorCode = UnicodeToAnsiInPlace(pji1w->pStatus);
282                 if (dwErrorCode != ERROR_SUCCESS)
283                 {
284                     goto Cleanup;
285                 }
286                 break;
287 
288             case 2:
289                 dwErrorCode = UnicodeToAnsiInPlace(pji2w->pPrinterName);
290                 if (dwErrorCode != ERROR_SUCCESS)
291                 {
292                     goto Cleanup;
293                 }
294                 dwErrorCode = UnicodeToAnsiInPlace(pji2w->pMachineName);
295                 if (dwErrorCode != ERROR_SUCCESS)
296                 {
297                     goto Cleanup;
298                 }
299                 dwErrorCode = UnicodeToAnsiInPlace(pji2w->pUserName);
300                 if (dwErrorCode != ERROR_SUCCESS)
301                 {
302                     goto Cleanup;
303                 }
304                 dwErrorCode = UnicodeToAnsiInPlace(pji2w->pDocument);
305                 if (dwErrorCode != ERROR_SUCCESS)
306                 {
307                     goto Cleanup;
308                 }
309                 dwErrorCode = UnicodeToAnsiInPlace(pji2w->pNotifyName);
310                 if (dwErrorCode != ERROR_SUCCESS)
311                 {
312                     goto Cleanup;
313                 }
314                 dwErrorCode = UnicodeToAnsiInPlace(pji2w->pDatatype);
315                 if (dwErrorCode != ERROR_SUCCESS)
316                 {
317                     goto Cleanup;
318                 }
319                 dwErrorCode = UnicodeToAnsiInPlace(pji2w->pPrintProcessor);
320                 if (dwErrorCode != ERROR_SUCCESS)
321                 {
322                     goto Cleanup;
323                 }
324                 dwErrorCode = UnicodeToAnsiInPlace(pji2w->pParameters);
325                 if (dwErrorCode != ERROR_SUCCESS)
326                 {
327                     goto Cleanup;
328                 }
329                 dwErrorCode = UnicodeToAnsiInPlace(pji2w->pStatus);
330                 if (dwErrorCode != ERROR_SUCCESS)
331                 {
332                     goto Cleanup;
333                 }
334                 if ( pji2w->pDevMode )
335                 {
336                     RosConvertUnicodeDevModeToAnsiDevmode( pji2w->pDevMode, pji2a->pDevMode );
337                 }
338                 break;
339         }
340         return TRUE;
341     }
342 Cleanup:
343     return FALSE;
344 }
345 
346 BOOL WINAPI
347 GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD pcbNeeded)
348 {
349     DWORD dwErrorCode;
350     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
351 
352     FIXME("GetJobW(%p, %lu, %lu, %p, %lu, %p)\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
353 
354     if (!pHandle)
355     {
356         dwErrorCode = ERROR_INVALID_HANDLE;
357         goto Cleanup;
358     }
359 
360     // Do the RPC call
361     RpcTryExcept
362     {
363         dwErrorCode = _RpcGetJob(pHandle->hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
364     }
365     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
366     {
367         dwErrorCode = RpcExceptionCode();
368         ERR("_RpcGetJob failed with exception code %lu!\n", dwErrorCode);
369     }
370     RpcEndExcept;
371 
372     if (dwErrorCode == ERROR_SUCCESS)
373     {
374         // Replace relative offset addresses in the output by absolute pointers.
375         ASSERT(Level >= 1 && Level <= 2);
376         MarshallUpStructure(cbBuf, pJob, pJobInfoMarshalling[Level]->pInfo, pJobInfoMarshalling[Level]->cbStructureSize, TRUE);
377     }
378 
379 Cleanup:
380     SetLastError(dwErrorCode);
381     return (dwErrorCode == ERROR_SUCCESS);
382 }
383 
384 BOOL WINAPI
385 ScheduleJob(HANDLE hPrinter, DWORD dwJobID)
386 {
387     DWORD dwErrorCode;
388     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
389 
390     TRACE("ScheduleJob(%p, %lu)\n", hPrinter, dwJobID);
391 
392     if (!pHandle)
393     {
394         dwErrorCode = ERROR_INVALID_HANDLE;
395         goto Cleanup;
396     }
397 
398     // Do the RPC call
399     RpcTryExcept
400     {
401         dwErrorCode = _RpcScheduleJob(pHandle->hPrinter, dwJobID);
402     }
403     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
404     {
405         dwErrorCode = RpcExceptionCode();
406         ERR("_RpcScheduleJob failed with exception code %lu!\n", dwErrorCode);
407     }
408     RpcEndExcept;
409 
410     if ( dwErrorCode == ERROR_SUCCESS )
411         pHandle->bJob = FALSE;
412 
413 Cleanup:
414     SetLastError(dwErrorCode);
415     return (dwErrorCode == ERROR_SUCCESS);
416 }
417 
418 BOOL WINAPI
419 SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Command)
420 {
421     BOOL ret;
422     LPBYTE JobW;
423     UNICODE_STRING usBuffer;
424 
425     TRACE("SetJobA(%p, %lu, %lu, %p, %lu)\n", hPrinter, JobId, Level, pJobInfo, Command);
426 
427     /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
428        are all ignored by SetJob, so we don't bother copying them */
429     switch(Level)
430     {
431     case 0:
432         JobW = NULL;
433         break;
434     case 1:
435       {
436         JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
437         ZeroMemory( info1W, sizeof(JOB_INFO_1W) );
438         JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJobInfo;
439 
440         JobW = (LPBYTE)info1W;
441         info1W->pUserName = AsciiToUnicode(&usBuffer, info1A->pUserName);
442         info1W->pDocument = AsciiToUnicode(&usBuffer, info1A->pDocument);
443         info1W->pDatatype = AsciiToUnicode(&usBuffer, info1A->pDatatype);
444         info1W->pStatus = AsciiToUnicode(&usBuffer, info1A->pStatus);
445         info1W->Status = info1A->Status;
446         info1W->Priority = info1A->Priority;
447         info1W->Position = info1A->Position;
448         info1W->PagesPrinted = info1A->PagesPrinted;
449         break;
450       }
451     case 2:
452       {
453         JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
454         ZeroMemory( info2W, sizeof(JOB_INFO_2W) );
455         JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJobInfo;
456 
457         JobW = (LPBYTE)info2W;
458         info2W->pUserName = AsciiToUnicode(&usBuffer, info2A->pUserName);
459         info2W->pDocument = AsciiToUnicode(&usBuffer, info2A->pDocument);
460         info2W->pNotifyName = AsciiToUnicode(&usBuffer, info2A->pNotifyName);
461         info2W->pDatatype = AsciiToUnicode(&usBuffer, info2A->pDatatype);
462         info2W->pPrintProcessor = AsciiToUnicode(&usBuffer, info2A->pPrintProcessor);
463         info2W->pParameters = AsciiToUnicode(&usBuffer, info2A->pParameters);
464         info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
465         info2W->pStatus = AsciiToUnicode(&usBuffer, info2A->pStatus);
466         info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
467         info2W->Status = info2A->Status;
468         info2W->Priority = info2A->Priority;
469         info2W->Position = info2A->Position;
470         info2W->StartTime = info2A->StartTime;
471         info2W->UntilTime = info2A->UntilTime;
472         info2W->PagesPrinted = info2A->PagesPrinted;
473         break;
474       }
475     case 3:
476         JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
477         memcpy(JobW, pJobInfo, sizeof(JOB_INFO_3));
478         break;
479     default:
480         ERR("Level = %d, unsupported!\n", Level);
481         SetLastError(ERROR_INVALID_LEVEL);
482         return FALSE;
483     }
484 
485     ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
486 
487     switch(Level)
488     {
489     case 1:
490       {
491         JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
492         HeapFree(GetProcessHeap(), 0, info1W->pUserName);
493         HeapFree(GetProcessHeap(), 0, info1W->pDocument);
494         HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
495         HeapFree(GetProcessHeap(), 0, info1W->pStatus);
496         break;
497       }
498     case 2:
499       {
500         JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
501         HeapFree(GetProcessHeap(), 0, info2W->pUserName);
502         HeapFree(GetProcessHeap(), 0, info2W->pDocument);
503         HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
504         HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
505         HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
506         HeapFree(GetProcessHeap(), 0, info2W->pParameters);
507         HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
508         HeapFree(GetProcessHeap(), 0, info2W->pStatus);
509         break;
510       }
511     }
512     HeapFree(GetProcessHeap(), 0, JobW);
513 
514     return ret;
515 }
516 
517 BOOL WINAPI
518 SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Command)
519 {
520     DWORD dwErrorCode;
521     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
522     WINSPOOL_JOB_CONTAINER JobContainer;
523 
524     TRACE("SetJobW(%p, %lu, %lu, %p, %lu)\n", hPrinter, JobId, Level, pJobInfo, Command);
525 
526     if (!pHandle)
527     {
528         dwErrorCode = ERROR_INVALID_HANDLE;
529         goto Cleanup;
530     }
531 
532     // pJobContainer->JobInfo is a union of pointers, so we can just set any element to our BYTE pointer.
533     JobContainer.Level = Level;
534     JobContainer.JobInfo.Level1 = (WINSPOOL_JOB_INFO_1*)pJobInfo;
535 
536     // Do the RPC call
537     RpcTryExcept
538     {
539         dwErrorCode = _RpcSetJob(pHandle->hPrinter, JobId, &JobContainer, Command);
540     }
541     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
542     {
543         dwErrorCode = RpcExceptionCode();
544         ERR("_RpcSetJob failed with exception code %lu!\n", dwErrorCode);
545     }
546     RpcEndExcept;
547 
548 Cleanup:
549     SetLastError(dwErrorCode);
550     return (dwErrorCode == ERROR_SUCCESS);
551 }
552