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