It's bugfixing time!
[reactos.git] / reactos / win32ss / printing / base / winspool / printers.c
1 /*
2 * PROJECT: ReactOS Spooler API
3 * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
4 * PURPOSE: Functions related to Printers and printing
5 * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
6 */
7
8 #include "precomp.h"
9
10 static void
11 _MarshallUpPrinterInfo(PBYTE pPrinterInfo, DWORD Level)
12 {
13 PPRINTER_INFO_1W pPrinterInfo1;
14 PPRINTER_INFO_2W pPrinterInfo2;
15
16 // Replace relative offset addresses in the output by absolute pointers.
17 if (Level == 1)
18 {
19 pPrinterInfo1 = (PPRINTER_INFO_1W)pPrinterInfo;
20
21 pPrinterInfo1->pName = (PWSTR)((ULONG_PTR)pPrinterInfo1->pName + (ULONG_PTR)pPrinterInfo1);
22 pPrinterInfo1->pDescription = (PWSTR)((ULONG_PTR)pPrinterInfo1->pDescription + (ULONG_PTR)pPrinterInfo1);
23 pPrinterInfo1->pComment = (PWSTR)((ULONG_PTR)pPrinterInfo1->pComment + (ULONG_PTR)pPrinterInfo1);
24 }
25 else if (Level == 2)
26 {
27 pPrinterInfo2 = (PPRINTER_INFO_2W)pPrinterInfo;
28
29 pPrinterInfo2->pPrinterName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pPrinterName + (ULONG_PTR)pPrinterInfo2);
30 pPrinterInfo2->pShareName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pShareName + (ULONG_PTR)pPrinterInfo2);
31 pPrinterInfo2->pPortName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pPortName + (ULONG_PTR)pPrinterInfo2);
32 pPrinterInfo2->pDriverName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pDriverName + (ULONG_PTR)pPrinterInfo2);
33 pPrinterInfo2->pComment = (PWSTR)((ULONG_PTR)pPrinterInfo2->pComment + (ULONG_PTR)pPrinterInfo2);
34 pPrinterInfo2->pLocation = (PWSTR)((ULONG_PTR)pPrinterInfo2->pLocation + (ULONG_PTR)pPrinterInfo2);
35 pPrinterInfo2->pDevMode = (PDEVMODEW)((ULONG_PTR)pPrinterInfo2->pDevMode + (ULONG_PTR)pPrinterInfo2);
36 pPrinterInfo2->pSepFile = (PWSTR)((ULONG_PTR)pPrinterInfo2->pSepFile + (ULONG_PTR)pPrinterInfo2);
37 pPrinterInfo2->pPrintProcessor = (PWSTR)((ULONG_PTR)pPrinterInfo2->pPrintProcessor + (ULONG_PTR)pPrinterInfo2);
38 pPrinterInfo2->pDatatype = (PWSTR)((ULONG_PTR)pPrinterInfo2->pDatatype + (ULONG_PTR)pPrinterInfo2);
39 pPrinterInfo2->pParameters = (PWSTR)((ULONG_PTR)pPrinterInfo2->pParameters + (ULONG_PTR)pPrinterInfo2);
40
41 if (pPrinterInfo2->pServerName)
42 pPrinterInfo2->pServerName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pServerName + (ULONG_PTR)pPrinterInfo2);
43
44 if (pPrinterInfo2->pSecurityDescriptor)
45 pPrinterInfo2->pSecurityDescriptor = (PWSTR)((ULONG_PTR)pPrinterInfo2->pSecurityDescriptor + (ULONG_PTR)pPrinterInfo2);
46 }
47 }
48
49 static DWORD
50 _StartDocPrinterSpooled(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1, PADDJOB_INFO_1W pAddJobInfo1)
51 {
52 DWORD cbNeeded;
53 DWORD dwErrorCode;
54 PJOB_INFO_1W pJobInfo1 = NULL;
55
56 // Create the spool file.
57 pHandle->hSPLFile = CreateFileW(pAddJobInfo1->Path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
58 if (pHandle->hSPLFile == INVALID_HANDLE_VALUE)
59 {
60 dwErrorCode = GetLastError();
61 ERR("CreateFileW failed for \"%S\" with error %lu!\n", pAddJobInfo1->Path, dwErrorCode);
62 goto Cleanup;
63 }
64
65 // Get the size of the job information.
66 GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, NULL, 0, &cbNeeded);
67 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
68 {
69 dwErrorCode = GetLastError();
70 ERR("GetJobW failed with error %lu!\n", dwErrorCode);
71 goto Cleanup;
72 }
73
74 // Allocate enough memory for the returned job information.
75 pJobInfo1 = HeapAlloc(hProcessHeap, 0, cbNeeded);
76 if (!pJobInfo1)
77 {
78 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
79 ERR("HeapAlloc failed with error %lu!\n", GetLastError());
80 goto Cleanup;
81 }
82
83 // Get the job information.
84 if (!GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, cbNeeded, &cbNeeded))
85 {
86 dwErrorCode = GetLastError();
87 ERR("GetJobW failed with error %lu!\n", dwErrorCode);
88 goto Cleanup;
89 }
90
91 // Add our document information.
92 if (pDocInfo1->pDatatype)
93 pJobInfo1->pDatatype = pDocInfo1->pDatatype;
94
95 pJobInfo1->pDocument = pDocInfo1->pDocName;
96
97 // Set the new job information.
98 if (!SetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, 0))
99 {
100 dwErrorCode = GetLastError();
101 ERR("SetJobW failed with error %lu!\n", dwErrorCode);
102 goto Cleanup;
103 }
104
105 // We were successful!
106 pHandle->dwJobID = pAddJobInfo1->JobId;
107 dwErrorCode = ERROR_SUCCESS;
108
109 Cleanup:
110 if (pJobInfo1)
111 HeapFree(hProcessHeap, 0, pJobInfo1);
112
113 return dwErrorCode;
114 }
115
116 static DWORD
117 _StartDocPrinterWithRPC(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1)
118 {
119 DWORD dwErrorCode;
120 WINSPOOL_DOC_INFO_CONTAINER DocInfoContainer;
121
122 DocInfoContainer.Level = 1;
123 DocInfoContainer.DocInfo.pDocInfo1 = (WINSPOOL_DOC_INFO_1*)pDocInfo1;
124
125 RpcTryExcept
126 {
127 dwErrorCode = _RpcStartDocPrinter(pHandle->hPrinter, &DocInfoContainer, &pHandle->dwJobID);
128 }
129 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
130 {
131 dwErrorCode = RpcExceptionCode();
132 ERR("_RpcStartDocPrinter failed with exception code %lu!\n", dwErrorCode);
133 }
134 RpcEndExcept;
135
136 return dwErrorCode;
137 }
138
139 BOOL WINAPI
140 ClosePrinter(HANDLE hPrinter)
141 {
142 DWORD dwErrorCode;
143 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
144
145 // Sanity checks.
146 if (!pHandle)
147 {
148 dwErrorCode = ERROR_INVALID_HANDLE;
149 goto Cleanup;
150 }
151
152 // Do the RPC call.
153 RpcTryExcept
154 {
155 dwErrorCode = _RpcClosePrinter(pHandle->hPrinter);
156 }
157 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
158 {
159 dwErrorCode = RpcExceptionCode();
160 ERR("_RpcClosePrinter failed with exception code %lu!\n", dwErrorCode);
161 }
162 RpcEndExcept;
163
164 // Close any open file handle.
165 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
166 CloseHandle(pHandle->hSPLFile);
167
168 // Free the memory for the handle.
169 HeapFree(hProcessHeap, 0, pHandle);
170
171 Cleanup:
172 SetLastError(dwErrorCode);
173 return (dwErrorCode == ERROR_SUCCESS);
174
175 }
176
177 DWORD WINAPI
178 DeviceCapabilitiesA(LPCSTR pDevice, LPCSTR pPort, WORD fwCapability, LPSTR pOutput, const DEVMODEA* pDevMode)
179 {
180 return 0;
181 }
182
183 DWORD WINAPI
184 DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort, WORD fwCapability, LPWSTR pOutput, const DEVMODEW* pDevMode)
185 {
186 return 0;
187 }
188
189 LONG WINAPI
190 DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput, DWORD fMode)
191 {
192 return 0;
193 }
194
195 LONG WINAPI
196 DocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput, DWORD fMode)
197 {
198 return 0;
199 }
200
201 BOOL WINAPI
202 EndDocPrinter(HANDLE hPrinter)
203 {
204 DWORD dwErrorCode;
205 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
206
207 // Sanity checks.
208 if (!pHandle)
209 {
210 dwErrorCode = ERROR_INVALID_HANDLE;
211 goto Cleanup;
212 }
213
214 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
215 {
216 // For spooled jobs, the document is finished by calling _RpcScheduleJob.
217 RpcTryExcept
218 {
219 dwErrorCode = _RpcScheduleJob(pHandle->hPrinter, pHandle->dwJobID);
220 }
221 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
222 {
223 dwErrorCode = RpcExceptionCode();
224 ERR("_RpcScheduleJob failed with exception code %lu!\n", dwErrorCode);
225 }
226 RpcEndExcept;
227
228 // Close the spool file handle.
229 CloseHandle(pHandle->hSPLFile);
230 }
231 else
232 {
233 // In all other cases, just call _RpcEndDocPrinter.
234 RpcTryExcept
235 {
236 dwErrorCode = _RpcEndDocPrinter(pHandle->hPrinter);
237 }
238 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
239 {
240 dwErrorCode = RpcExceptionCode();
241 ERR("_RpcEndDocPrinter failed with exception code %lu!\n", dwErrorCode);
242 }
243 RpcEndExcept;
244 }
245
246 // A new document can now be started again.
247 pHandle->bStartedDoc = FALSE;
248
249 Cleanup:
250 SetLastError(dwErrorCode);
251 return (dwErrorCode == ERROR_SUCCESS);
252 }
253
254 BOOL WINAPI
255 EndPagePrinter(HANDLE hPrinter)
256 {
257 DWORD dwErrorCode;
258 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
259
260 // Sanity checks.
261 if (!pHandle)
262 {
263 dwErrorCode = ERROR_INVALID_HANDLE;
264 goto Cleanup;
265 }
266
267 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
268 {
269 // For spooled jobs, we don't need to do anything.
270 dwErrorCode = ERROR_SUCCESS;
271 }
272 else
273 {
274 // In all other cases, just call _RpcEndPagePrinter.
275 RpcTryExcept
276 {
277 dwErrorCode = _RpcEndPagePrinter(pHandle->hPrinter);
278 }
279 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
280 {
281 dwErrorCode = RpcExceptionCode();
282 ERR("_RpcEndPagePrinter failed with exception code %lu!\n", dwErrorCode);
283 }
284 RpcEndExcept;
285 }
286
287 Cleanup:
288 SetLastError(dwErrorCode);
289 return (dwErrorCode == ERROR_SUCCESS);
290 }
291
292 BOOL WINAPI
293 EnumPrintersA(DWORD Flags, PSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
294 {
295 return FALSE;
296 }
297
298 BOOL WINAPI
299 EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
300 {
301 DWORD dwErrorCode;
302 DWORD i;
303 PBYTE p = pPrinterEnum;
304
305 // Do the RPC call
306 RpcTryExcept
307 {
308 dwErrorCode = _RpcEnumPrinters(Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
309 }
310 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
311 {
312 dwErrorCode = RpcExceptionCode();
313 ERR("_RpcEnumPrinters failed with exception code %lu!\n", dwErrorCode);
314 }
315 RpcEndExcept;
316
317 if (dwErrorCode == ERROR_SUCCESS)
318 {
319 // Replace relative offset addresses in the output by absolute pointers.
320 for (i = 0; i < *pcReturned; i++)
321 {
322 _MarshallUpPrinterInfo(p, Level);
323
324 if (Level == 1)
325 p += sizeof(PRINTER_INFO_1W);
326 else if (Level == 2)
327 p += sizeof(PRINTER_INFO_2W);
328 }
329 }
330
331 SetLastError(dwErrorCode);
332 return (dwErrorCode == ERROR_SUCCESS);
333 }
334
335 BOOL WINAPI
336 GetDefaultPrinterA(LPSTR pszBuffer, LPDWORD pcchBuffer)
337 {
338 return FALSE;
339 }
340
341 BOOL WINAPI
342 GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer)
343 {
344 return FALSE;
345 }
346
347 BOOL WINAPI
348 GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
349 {
350 return FALSE;
351 }
352
353 BOOL WINAPI
354 GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
355 {
356 return FALSE;
357 }
358
359 BOOL WINAPI
360 GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
361 {
362 return FALSE;
363 }
364
365 BOOL WINAPI
366 GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
367 {
368 return FALSE;
369 }
370
371 BOOL WINAPI
372 OpenPrinterA(LPSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSA pDefault)
373 {
374 BOOL bReturnValue = FALSE;
375 PWSTR pwszPrinterName = NULL;
376 PWSTR pwszDatatype = NULL;
377 PRINTER_DEFAULTSW wDefault = { 0 };
378 size_t StringLength;
379
380 if (pPrinterName)
381 {
382 // Convert pPrinterName to a Unicode string pwszPrinterName
383 StringLength = strlen(pPrinterName) + 1;
384
385 pwszPrinterName = HeapAlloc(hProcessHeap, 0, StringLength * sizeof(WCHAR));
386 if (!pwszPrinterName)
387 {
388 ERR("HeapAlloc failed for pwszPrinterName with last error %lu!\n", GetLastError());
389 goto Cleanup;
390 }
391
392 MultiByteToWideChar(CP_ACP, 0, pPrinterName, -1, pwszPrinterName, StringLength);
393 }
394
395 if (pDefault)
396 {
397 wDefault.DesiredAccess = pDefault->DesiredAccess;
398
399 if (pDefault->pDatatype)
400 {
401 // Convert pDefault->pDatatype to a Unicode string pwszDatatype that later becomes wDefault.pDatatype
402 StringLength = strlen(pDefault->pDatatype) + 1;
403
404 pwszDatatype = HeapAlloc(hProcessHeap, 0, StringLength * sizeof(WCHAR));
405 if (!pwszDatatype)
406 {
407 ERR("HeapAlloc failed for pwszDatatype with last error %lu!\n", GetLastError());
408 goto Cleanup;
409 }
410
411 MultiByteToWideChar(CP_ACP, 0, pDefault->pDatatype, -1, pwszDatatype, StringLength);
412 wDefault.pDatatype = pwszDatatype;
413 }
414
415 if (pDefault->pDevMode)
416 wDefault.pDevMode = GdiConvertToDevmodeW(pDefault->pDevMode);
417 }
418
419 bReturnValue = OpenPrinterW(pwszPrinterName, phPrinter, &wDefault);
420
421 Cleanup:
422 if (wDefault.pDevMode)
423 HeapFree(hProcessHeap, 0, wDefault.pDevMode);
424
425 if (pwszPrinterName)
426 HeapFree(hProcessHeap, 0, pwszPrinterName);
427
428 if (pwszDatatype)
429 HeapFree(hProcessHeap, 0, pwszDatatype);
430
431 return bReturnValue;
432 }
433
434 BOOL WINAPI
435 OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault)
436 {
437 DWORD dwErrorCode;
438 HANDLE hPrinter;
439 PSPOOLER_HANDLE pHandle;
440 PWSTR pDatatype = NULL;
441 WINSPOOL_DEVMODE_CONTAINER DevModeContainer = { 0 };
442 ACCESS_MASK AccessRequired = 0;
443
444 // Prepare the additional parameters in the format required by _RpcOpenPrinter
445 if (pDefault)
446 {
447 pDatatype = pDefault->pDatatype;
448 DevModeContainer.cbBuf = sizeof(DEVMODEW);
449 DevModeContainer.pDevMode = (BYTE*)pDefault->pDevMode;
450 AccessRequired = pDefault->DesiredAccess;
451 }
452
453 // Do the RPC call
454 RpcTryExcept
455 {
456 dwErrorCode = _RpcOpenPrinter(pPrinterName, &hPrinter, pDatatype, &DevModeContainer, AccessRequired);
457 }
458 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
459 {
460 dwErrorCode = RpcExceptionCode();
461 ERR("_RpcOpenPrinter failed with exception code %lu!\n", dwErrorCode);
462 }
463 RpcEndExcept;
464
465 if (dwErrorCode == ERROR_SUCCESS)
466 {
467 // Create a new SPOOLER_HANDLE structure.
468 pHandle = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(SPOOLER_HANDLE));
469 if (!pHandle)
470 {
471 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
472 ERR("HeapAlloc failed with error %lu!\n", GetLastError());
473 goto Cleanup;
474 }
475
476 pHandle->hPrinter = hPrinter;
477 pHandle->hSPLFile = INVALID_HANDLE_VALUE;
478
479 // Return it as phPrinter.
480 *phPrinter = (HANDLE)pHandle;
481 }
482
483 Cleanup:
484 SetLastError(dwErrorCode);
485 return (dwErrorCode == ERROR_SUCCESS);
486 }
487
488 BOOL WINAPI
489 ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead)
490 {
491 DWORD dwErrorCode;
492 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
493
494 // Sanity checks.
495 if (!pHandle)
496 {
497 dwErrorCode = ERROR_INVALID_HANDLE;
498 goto Cleanup;
499 }
500
501 // Do the RPC call
502 RpcTryExcept
503 {
504 dwErrorCode = _RpcReadPrinter(pHandle->hPrinter, pBuf, cbBuf, pNoBytesRead);
505 }
506 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
507 {
508 dwErrorCode = RpcExceptionCode();
509 ERR("_RpcReadPrinter failed with exception code %lu!\n", dwErrorCode);
510 }
511 RpcEndExcept;
512
513 Cleanup:
514 SetLastError(dwErrorCode);
515 return (dwErrorCode == ERROR_SUCCESS);
516 }
517
518 DWORD WINAPI
519 StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
520 {
521 DWORD cbAddJobInfo1;
522 DWORD cbNeeded;
523 DWORD dwErrorCode;
524 PADDJOB_INFO_1W pAddJobInfo1 = NULL;
525 PDOC_INFO_1W pDocInfo1 = (PDOC_INFO_1W)pDocInfo;
526 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
527
528 // Sanity checks.
529 if (!pHandle)
530 {
531 dwErrorCode = ERROR_INVALID_HANDLE;
532 goto Cleanup;
533 }
534
535 if (!pDocInfo1)
536 {
537 dwErrorCode = ERROR_INVALID_PARAMETER;
538 goto Cleanup;
539 }
540
541 if (Level != 1)
542 {
543 dwErrorCode = ERROR_INVALID_LEVEL;
544 goto Cleanup;
545 }
546
547 if (pHandle->bStartedDoc)
548 {
549 dwErrorCode = ERROR_INVALID_PRINTER_STATE;
550 goto Cleanup;
551 }
552
553 // Check if we want to redirect output into a file.
554 if (pDocInfo1->pOutputFile)
555 {
556 // Do a StartDocPrinter RPC call in this case.
557 dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
558 }
559 else
560 {
561 // Allocate memory for the ADDJOB_INFO_1W structure and a path.
562 cbAddJobInfo1 = sizeof(ADDJOB_INFO_1W) + MAX_PATH * sizeof(WCHAR);
563 pAddJobInfo1 = HeapAlloc(hProcessHeap, 0, cbAddJobInfo1);
564 if (!pAddJobInfo1)
565 {
566 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
567 ERR("HeapAlloc failed with error %lu!\n", GetLastError());
568 goto Cleanup;
569 }
570
571 // Try to add a new job.
572 // This only succeeds if the printer is set to do spooled printing.
573 if (AddJobW((HANDLE)pHandle, 1, (PBYTE)pAddJobInfo1, cbAddJobInfo1, &cbNeeded))
574 {
575 // Do spooled printing.
576 dwErrorCode = _StartDocPrinterSpooled(pHandle, pDocInfo1, pAddJobInfo1);
577 }
578 else if (GetLastError() == ERROR_INVALID_ACCESS)
579 {
580 // ERROR_INVALID_ACCESS is returned when the printer is set to do direct printing.
581 // In this case, we do a StartDocPrinter RPC call.
582 dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
583 }
584 else
585 {
586 dwErrorCode = GetLastError();
587 ERR("AddJobW failed with error %lu!\n", dwErrorCode);
588 goto Cleanup;
589 }
590 }
591
592 if (dwErrorCode == ERROR_SUCCESS)
593 pHandle->bStartedDoc = TRUE;
594
595 Cleanup:
596 if (pAddJobInfo1)
597 HeapFree(hProcessHeap, 0, pAddJobInfo1);
598
599 SetLastError(dwErrorCode);
600 return pHandle->dwJobID;
601 }
602
603 BOOL WINAPI
604 StartPagePrinter(HANDLE hPrinter)
605 {
606 DWORD dwErrorCode;
607 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
608
609 // Sanity checks.
610 if (!pHandle)
611 {
612 dwErrorCode = ERROR_INVALID_HANDLE;
613 goto Cleanup;
614 }
615
616 // Do the RPC call
617 RpcTryExcept
618 {
619 dwErrorCode = _RpcStartPagePrinter(pHandle->hPrinter);
620 }
621 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
622 {
623 dwErrorCode = RpcExceptionCode();
624 ERR("_RpcStartPagePrinter failed with exception code %lu!\n", dwErrorCode);
625 }
626 RpcEndExcept;
627
628 Cleanup:
629 SetLastError(dwErrorCode);
630 return (dwErrorCode == ERROR_SUCCESS);
631 }
632
633 BOOL WINAPI
634 WritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten)
635 {
636 DWORD dwErrorCode;
637 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
638
639 // Sanity checks.
640 if (!pHandle)
641 {
642 dwErrorCode = ERROR_INVALID_HANDLE;
643 goto Cleanup;
644 }
645
646 if (!pHandle->bStartedDoc)
647 {
648 dwErrorCode = ERROR_SPL_NO_STARTDOC;
649 goto Cleanup;
650 }
651
652 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
653 {
654 // Write to the spool file. This doesn't need an RPC request.
655 if (!WriteFile(pHandle->hSPLFile, pBuf, cbBuf, pcWritten, NULL))
656 {
657 dwErrorCode = GetLastError();
658 ERR("WriteFile failed with error %lu!\n", dwErrorCode);
659 goto Cleanup;
660 }
661
662 dwErrorCode = ERROR_SUCCESS;
663 }
664 else
665 {
666 // TODO: This case (for direct printing or remote printing) has bad performance if multiple small-sized WritePrinter calls are performed.
667 // We may increase performance by writing into a buffer and only doing a single RPC call when the buffer is full.
668
669 // Do the RPC call
670 RpcTryExcept
671 {
672 dwErrorCode = _RpcWritePrinter(pHandle->hPrinter, pBuf, cbBuf, pcWritten);
673 }
674 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
675 {
676 dwErrorCode = RpcExceptionCode();
677 ERR("_RpcWritePrinter failed with exception code %lu!\n", dwErrorCode);
678 }
679 RpcEndExcept;
680 }
681
682 Cleanup:
683 SetLastError(dwErrorCode);
684 return (dwErrorCode == ERROR_SUCCESS);
685 }
686
687 BOOL WINAPI
688 XcvDataW(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded, PDWORD pdwStatus)
689 {
690 return FALSE;
691 }