[SPOOLSV, WINSPOOL]
[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(pHandle->hPrinter, 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(pHandle->hPrinter, 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 pJobInfo1->pDatatype = pDocInfo1->pDatatype;
93 pJobInfo1->pDocument = pDocInfo1->pDocName;
94
95 // Set the new job information.
96 if (!SetJobW(pHandle->hPrinter, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, 0))
97 {
98 dwErrorCode = GetLastError();
99 ERR("SetJobW failed with error %lu!\n", dwErrorCode);
100 goto Cleanup;
101 }
102
103 // We were successful!
104 pHandle->dwJobID = pAddJobInfo1->JobId;
105 dwErrorCode = ERROR_SUCCESS;
106
107 Cleanup:
108 if (pJobInfo1)
109 HeapFree(hProcessHeap, 0, pJobInfo1);
110
111 return dwErrorCode;
112 }
113
114 static DWORD
115 _StartDocPrinterWithRPC(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1)
116 {
117 DWORD dwErrorCode;
118 WINSPOOL_DOC_INFO_CONTAINER DocInfoContainer;
119
120 DocInfoContainer.Level = 1;
121 DocInfoContainer.DocInfo.pDocInfo1 = (WINSPOOL_DOC_INFO_1*)pDocInfo1;
122
123 RpcTryExcept
124 {
125 dwErrorCode = _RpcStartDocPrinter(pHandle->hPrinter, &DocInfoContainer, &pHandle->dwJobID);
126 }
127 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
128 {
129 dwErrorCode = RpcExceptionCode();
130 ERR("_RpcStartDocPrinter failed with exception code %lu!\n", dwErrorCode);
131 }
132 RpcEndExcept;
133
134 return dwErrorCode;
135 }
136
137 BOOL WINAPI
138 ClosePrinter(HANDLE hPrinter)
139 {
140 DWORD dwErrorCode;
141 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
142
143 // Sanity checks.
144 if (!pHandle)
145 {
146 dwErrorCode = ERROR_INVALID_HANDLE;
147 goto Cleanup;
148 }
149
150 // Do the RPC call.
151 RpcTryExcept
152 {
153 dwErrorCode = _RpcClosePrinter(pHandle->hPrinter);
154 }
155 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
156 {
157 dwErrorCode = RpcExceptionCode();
158 ERR("_RpcClosePrinter failed with exception code %lu!\n", dwErrorCode);
159 }
160 RpcEndExcept;
161
162 // Close any open file handle.
163 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
164 CloseHandle(pHandle->hSPLFile);
165
166 // Free the memory for the handle.
167 HeapFree(hProcessHeap, 0, pHandle);
168
169 Cleanup:
170 SetLastError(dwErrorCode);
171 return (dwErrorCode == ERROR_SUCCESS);
172
173 }
174
175 DWORD WINAPI
176 DeviceCapabilitiesA(LPCSTR pDevice, LPCSTR pPort, WORD fwCapability, LPSTR pOutput, const DEVMODEA* pDevMode)
177 {
178 return 0;
179 }
180
181 DWORD WINAPI
182 DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort, WORD fwCapability, LPWSTR pOutput, const DEVMODEW* pDevMode)
183 {
184 return 0;
185 }
186
187 LONG WINAPI
188 DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput, DWORD fMode)
189 {
190 return 0;
191 }
192
193 LONG WINAPI
194 DocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput, DWORD fMode)
195 {
196 return 0;
197 }
198
199 BOOL WINAPI
200 EndDocPrinter(HANDLE hPrinter)
201 {
202 DWORD dwErrorCode;
203 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
204
205 // Sanity checks.
206 if (!pHandle)
207 {
208 dwErrorCode = ERROR_INVALID_HANDLE;
209 goto Cleanup;
210 }
211
212 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
213 {
214 // For spooled jobs, the document is finished by calling _RpcScheduleJob.
215 RpcTryExcept
216 {
217 dwErrorCode = _RpcScheduleJob(pHandle->hPrinter, pHandle->dwJobID);
218 }
219 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
220 {
221 dwErrorCode = RpcExceptionCode();
222 ERR("_RpcScheduleJob failed with exception code %lu!\n", dwErrorCode);
223 }
224 RpcEndExcept;
225
226 // Close the spool file handle.
227 CloseHandle(pHandle->hSPLFile);
228 }
229 else
230 {
231 // In all other cases, just call _RpcEndDocPrinter.
232 RpcTryExcept
233 {
234 dwErrorCode = _RpcEndDocPrinter(pHandle->hPrinter);
235 }
236 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
237 {
238 dwErrorCode = RpcExceptionCode();
239 ERR("_RpcEndDocPrinter failed with exception code %lu!\n", dwErrorCode);
240 }
241 RpcEndExcept;
242 }
243
244 // A new document can now be started again.
245 pHandle->bStartedDoc = FALSE;
246
247 Cleanup:
248 SetLastError(dwErrorCode);
249 return (dwErrorCode == ERROR_SUCCESS);
250 }
251
252 BOOL WINAPI
253 EndPagePrinter(HANDLE hPrinter)
254 {
255 DWORD dwErrorCode;
256 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
257
258 // Sanity checks.
259 if (!pHandle)
260 {
261 dwErrorCode = ERROR_INVALID_HANDLE;
262 goto Cleanup;
263 }
264
265 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
266 {
267 // For spooled jobs, we don't need to do anything.
268 dwErrorCode = ERROR_SUCCESS;
269 }
270 else
271 {
272 // In all other cases, just call _RpcEndPagePrinter.
273 RpcTryExcept
274 {
275 dwErrorCode = _RpcEndPagePrinter(pHandle->hPrinter);
276 }
277 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
278 {
279 dwErrorCode = RpcExceptionCode();
280 ERR("_RpcEndPagePrinter failed with exception code %lu!\n", dwErrorCode);
281 }
282 RpcEndExcept;
283 }
284
285 Cleanup:
286 SetLastError(dwErrorCode);
287 return (dwErrorCode == ERROR_SUCCESS);
288 }
289
290 BOOL WINAPI
291 EnumPrintersA(DWORD Flags, PSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
292 {
293 return FALSE;
294 }
295
296 BOOL WINAPI
297 EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
298 {
299 DWORD dwErrorCode;
300 DWORD i;
301 PBYTE p = pPrinterEnum;
302
303 // Do the RPC call
304 RpcTryExcept
305 {
306 dwErrorCode = _RpcEnumPrinters(Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
307 }
308 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
309 {
310 dwErrorCode = RpcExceptionCode();
311 ERR("_RpcEnumPrinters failed with exception code %lu!\n", dwErrorCode);
312 }
313 RpcEndExcept;
314
315 if (dwErrorCode == ERROR_SUCCESS)
316 {
317 // Replace relative offset addresses in the output by absolute pointers.
318 for (i = 0; i < *pcReturned; i++)
319 {
320 _MarshallUpPrinterInfo(p, Level);
321
322 if (Level == 1)
323 p += sizeof(PRINTER_INFO_1W);
324 else if (Level == 2)
325 p += sizeof(PRINTER_INFO_2W);
326 }
327 }
328
329 SetLastError(dwErrorCode);
330 return (dwErrorCode == ERROR_SUCCESS);
331 }
332
333 BOOL WINAPI
334 GetDefaultPrinterA(LPSTR pszBuffer, LPDWORD pcchBuffer)
335 {
336 return FALSE;
337 }
338
339 BOOL WINAPI
340 GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer)
341 {
342 return FALSE;
343 }
344
345 BOOL WINAPI
346 GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
347 {
348 return FALSE;
349 }
350
351 BOOL WINAPI
352 GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
353 {
354 return FALSE;
355 }
356
357 BOOL WINAPI
358 GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
359 {
360 return FALSE;
361 }
362
363 BOOL WINAPI
364 GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
365 {
366 return FALSE;
367 }
368
369 BOOL WINAPI
370 OpenPrinterA(LPSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSA pDefault)
371 {
372 BOOL bReturnValue = FALSE;
373 PWSTR pwszPrinterName = NULL;
374 PWSTR pwszDatatype = NULL;
375 PRINTER_DEFAULTSW wDefault = { 0 };
376 size_t StringLength;
377
378 if (pPrinterName)
379 {
380 // Convert pPrinterName to a Unicode string pwszPrinterName
381 StringLength = strlen(pPrinterName) + 1;
382
383 pwszPrinterName = HeapAlloc(hProcessHeap, 0, StringLength * sizeof(WCHAR));
384 if (!pwszPrinterName)
385 {
386 ERR("HeapAlloc failed for pwszPrinterName with last error %lu!\n", GetLastError());
387 goto Cleanup;
388 }
389
390 MultiByteToWideChar(CP_ACP, 0, pPrinterName, -1, pwszPrinterName, StringLength);
391 }
392
393 if (pDefault)
394 {
395 wDefault.DesiredAccess = pDefault->DesiredAccess;
396
397 if (pDefault->pDatatype)
398 {
399 // Convert pDefault->pDatatype to a Unicode string pwszDatatype that later becomes wDefault.pDatatype
400 StringLength = strlen(pDefault->pDatatype) + 1;
401
402 pwszDatatype = HeapAlloc(hProcessHeap, 0, StringLength * sizeof(WCHAR));
403 if (!pwszDatatype)
404 {
405 ERR("HeapAlloc failed for pwszDatatype with last error %lu!\n", GetLastError());
406 goto Cleanup;
407 }
408
409 MultiByteToWideChar(CP_ACP, 0, pDefault->pDatatype, -1, pwszDatatype, StringLength);
410 wDefault.pDatatype = pwszDatatype;
411 }
412
413 if (pDefault->pDevMode)
414 wDefault.pDevMode = GdiConvertToDevmodeW(pDefault->pDevMode);
415 }
416
417 bReturnValue = OpenPrinterW(pwszPrinterName, phPrinter, &wDefault);
418
419 Cleanup:
420 if (wDefault.pDevMode)
421 HeapFree(hProcessHeap, 0, wDefault.pDevMode);
422
423 if (pwszPrinterName)
424 HeapFree(hProcessHeap, 0, pwszPrinterName);
425
426 if (pwszDatatype)
427 HeapFree(hProcessHeap, 0, pwszDatatype);
428
429 return bReturnValue;
430 }
431
432 BOOL WINAPI
433 OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault)
434 {
435 DWORD dwErrorCode;
436 HANDLE hPrinter;
437 PSPOOLER_HANDLE pHandle;
438 PWSTR pDatatype = NULL;
439 WINSPOOL_DEVMODE_CONTAINER DevModeContainer;
440 WINSPOOL_DEVMODE_CONTAINER* pDevModeContainer = NULL;
441 ACCESS_MASK AccessRequired = 0;
442
443 // Prepare the additional parameters in the format required by _RpcOpenPrinter
444 if (pDefault)
445 {
446 pDatatype = pDefault->pDatatype;
447 DevModeContainer.cbBuf = sizeof(DEVMODEW);
448 DevModeContainer.pDevMode = (BYTE*)pDefault->pDevMode;
449 pDevModeContainer = &DevModeContainer;
450 AccessRequired = pDefault->DesiredAccess;
451 }
452
453 // Do the RPC call
454 RpcTryExcept
455 {
456 dwErrorCode = _RpcOpenPrinter(pPrinterName, &hPrinter, pDatatype, pDevModeContainer, 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(pHandle->hPrinter, 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 }