ec1c18b845168d5d2232fda554b56820da95f215
[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 HANDLE WINAPI
140 AddPrinterW(PWSTR pName, DWORD Level, PBYTE pPrinter)
141 {
142 UNIMPLEMENTED;
143 return NULL;
144 }
145
146 BOOL WINAPI
147 ClosePrinter(HANDLE hPrinter)
148 {
149 DWORD dwErrorCode;
150 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
151
152 // Sanity checks.
153 if (!pHandle)
154 {
155 dwErrorCode = ERROR_INVALID_HANDLE;
156 goto Cleanup;
157 }
158
159 // Do the RPC call.
160 RpcTryExcept
161 {
162 dwErrorCode = _RpcClosePrinter(pHandle->hPrinter);
163 }
164 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
165 {
166 dwErrorCode = RpcExceptionCode();
167 ERR("_RpcClosePrinter failed with exception code %lu!\n", dwErrorCode);
168 }
169 RpcEndExcept;
170
171 // Close any open file handle.
172 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
173 CloseHandle(pHandle->hSPLFile);
174
175 // Free the memory for the handle.
176 HeapFree(hProcessHeap, 0, pHandle);
177
178 Cleanup:
179 SetLastError(dwErrorCode);
180 return (dwErrorCode == ERROR_SUCCESS);
181
182 }
183
184 DWORD WINAPI
185 DeviceCapabilitiesA(LPCSTR pDevice, LPCSTR pPort, WORD fwCapability, LPSTR pOutput, const DEVMODEA* pDevMode)
186 {
187 return 0;
188 }
189
190 DWORD WINAPI
191 DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort, WORD fwCapability, LPWSTR pOutput, const DEVMODEW* pDevMode)
192 {
193 return 0;
194 }
195
196 LONG WINAPI
197 DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput, DWORD fMode)
198 {
199 return 0;
200 }
201
202 LONG WINAPI
203 DocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput, DWORD fMode)
204 {
205 return 0;
206 }
207
208 BOOL WINAPI
209 EndDocPrinter(HANDLE hPrinter)
210 {
211 DWORD dwErrorCode;
212 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
213
214 // Sanity checks.
215 if (!pHandle)
216 {
217 dwErrorCode = ERROR_INVALID_HANDLE;
218 goto Cleanup;
219 }
220
221 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
222 {
223 // For spooled jobs, the document is finished by calling _RpcScheduleJob.
224 RpcTryExcept
225 {
226 dwErrorCode = _RpcScheduleJob(pHandle->hPrinter, pHandle->dwJobID);
227 }
228 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
229 {
230 dwErrorCode = RpcExceptionCode();
231 ERR("_RpcScheduleJob failed with exception code %lu!\n", dwErrorCode);
232 }
233 RpcEndExcept;
234
235 // Close the spool file handle.
236 CloseHandle(pHandle->hSPLFile);
237 }
238 else
239 {
240 // In all other cases, just call _RpcEndDocPrinter.
241 RpcTryExcept
242 {
243 dwErrorCode = _RpcEndDocPrinter(pHandle->hPrinter);
244 }
245 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
246 {
247 dwErrorCode = RpcExceptionCode();
248 ERR("_RpcEndDocPrinter failed with exception code %lu!\n", dwErrorCode);
249 }
250 RpcEndExcept;
251 }
252
253 // A new document can now be started again.
254 pHandle->bStartedDoc = FALSE;
255
256 Cleanup:
257 SetLastError(dwErrorCode);
258 return (dwErrorCode == ERROR_SUCCESS);
259 }
260
261 BOOL WINAPI
262 EndPagePrinter(HANDLE hPrinter)
263 {
264 DWORD dwErrorCode;
265 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
266
267 // Sanity checks.
268 if (!pHandle)
269 {
270 dwErrorCode = ERROR_INVALID_HANDLE;
271 goto Cleanup;
272 }
273
274 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
275 {
276 // For spooled jobs, we don't need to do anything.
277 dwErrorCode = ERROR_SUCCESS;
278 }
279 else
280 {
281 // In all other cases, just call _RpcEndPagePrinter.
282 RpcTryExcept
283 {
284 dwErrorCode = _RpcEndPagePrinter(pHandle->hPrinter);
285 }
286 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
287 {
288 dwErrorCode = RpcExceptionCode();
289 ERR("_RpcEndPagePrinter failed with exception code %lu!\n", dwErrorCode);
290 }
291 RpcEndExcept;
292 }
293
294 Cleanup:
295 SetLastError(dwErrorCode);
296 return (dwErrorCode == ERROR_SUCCESS);
297 }
298
299 BOOL WINAPI
300 EnumPrintersA(DWORD Flags, PSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
301 {
302 return FALSE;
303 }
304
305 BOOL WINAPI
306 EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
307 {
308 DWORD dwErrorCode;
309 DWORD i;
310 PBYTE p = pPrinterEnum;
311
312 // Do the RPC call
313 RpcTryExcept
314 {
315 dwErrorCode = _RpcEnumPrinters(Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
316 }
317 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
318 {
319 dwErrorCode = RpcExceptionCode();
320 ERR("_RpcEnumPrinters failed with exception code %lu!\n", dwErrorCode);
321 }
322 RpcEndExcept;
323
324 if (dwErrorCode == ERROR_SUCCESS)
325 {
326 // Replace relative offset addresses in the output by absolute pointers.
327 for (i = 0; i < *pcReturned; i++)
328 {
329 _MarshallUpPrinterInfo(p, Level);
330
331 if (Level == 1)
332 p += sizeof(PRINTER_INFO_1W);
333 else if (Level == 2)
334 p += sizeof(PRINTER_INFO_2W);
335 }
336 }
337
338 SetLastError(dwErrorCode);
339 return (dwErrorCode == ERROR_SUCCESS);
340 }
341
342 BOOL WINAPI
343 GetDefaultPrinterA(LPSTR pszBuffer, LPDWORD pcchBuffer)
344 {
345 return FALSE;
346 }
347
348 BOOL WINAPI
349 GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer)
350 {
351 return FALSE;
352 }
353
354 BOOL WINAPI
355 GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
356 {
357 return FALSE;
358 }
359
360 BOOL WINAPI
361 GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
362 {
363 return FALSE;
364 }
365
366 BOOL WINAPI
367 GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
368 {
369 return FALSE;
370 }
371
372 BOOL WINAPI
373 GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
374 {
375 return FALSE;
376 }
377
378 BOOL WINAPI
379 OpenPrinterA(LPSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSA pDefault)
380 {
381 BOOL bReturnValue = FALSE;
382 PWSTR pwszPrinterName = NULL;
383 PWSTR pwszDatatype = NULL;
384 PRINTER_DEFAULTSW wDefault = { 0 };
385 size_t StringLength;
386
387 if (pPrinterName)
388 {
389 // Convert pPrinterName to a Unicode string pwszPrinterName
390 StringLength = strlen(pPrinterName) + 1;
391
392 pwszPrinterName = HeapAlloc(hProcessHeap, 0, StringLength * sizeof(WCHAR));
393 if (!pwszPrinterName)
394 {
395 ERR("HeapAlloc failed for pwszPrinterName with last error %lu!\n", GetLastError());
396 goto Cleanup;
397 }
398
399 MultiByteToWideChar(CP_ACP, 0, pPrinterName, -1, pwszPrinterName, StringLength);
400 }
401
402 if (pDefault)
403 {
404 wDefault.DesiredAccess = pDefault->DesiredAccess;
405
406 if (pDefault->pDatatype)
407 {
408 // Convert pDefault->pDatatype to a Unicode string pwszDatatype that later becomes wDefault.pDatatype
409 StringLength = strlen(pDefault->pDatatype) + 1;
410
411 pwszDatatype = HeapAlloc(hProcessHeap, 0, StringLength * sizeof(WCHAR));
412 if (!pwszDatatype)
413 {
414 ERR("HeapAlloc failed for pwszDatatype with last error %lu!\n", GetLastError());
415 goto Cleanup;
416 }
417
418 MultiByteToWideChar(CP_ACP, 0, pDefault->pDatatype, -1, pwszDatatype, StringLength);
419 wDefault.pDatatype = pwszDatatype;
420 }
421
422 if (pDefault->pDevMode)
423 wDefault.pDevMode = GdiConvertToDevmodeW(pDefault->pDevMode);
424 }
425
426 bReturnValue = OpenPrinterW(pwszPrinterName, phPrinter, &wDefault);
427
428 Cleanup:
429 if (wDefault.pDevMode)
430 HeapFree(hProcessHeap, 0, wDefault.pDevMode);
431
432 if (pwszPrinterName)
433 HeapFree(hProcessHeap, 0, pwszPrinterName);
434
435 if (pwszDatatype)
436 HeapFree(hProcessHeap, 0, pwszDatatype);
437
438 return bReturnValue;
439 }
440
441 BOOL WINAPI
442 OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault)
443 {
444 DWORD dwErrorCode;
445 HANDLE hPrinter;
446 PSPOOLER_HANDLE pHandle;
447 PWSTR pDatatype = NULL;
448 WINSPOOL_DEVMODE_CONTAINER DevModeContainer = { 0 };
449 ACCESS_MASK AccessRequired = 0;
450
451 // Prepare the additional parameters in the format required by _RpcOpenPrinter
452 if (pDefault)
453 {
454 pDatatype = pDefault->pDatatype;
455 DevModeContainer.cbBuf = sizeof(DEVMODEW);
456 DevModeContainer.pDevMode = (BYTE*)pDefault->pDevMode;
457 AccessRequired = pDefault->DesiredAccess;
458 }
459
460 // Do the RPC call
461 RpcTryExcept
462 {
463 dwErrorCode = _RpcOpenPrinter(pPrinterName, &hPrinter, pDatatype, &DevModeContainer, AccessRequired);
464 }
465 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
466 {
467 dwErrorCode = RpcExceptionCode();
468 ERR("_RpcOpenPrinter failed with exception code %lu!\n", dwErrorCode);
469 }
470 RpcEndExcept;
471
472 if (dwErrorCode == ERROR_SUCCESS)
473 {
474 // Create a new SPOOLER_HANDLE structure.
475 pHandle = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(SPOOLER_HANDLE));
476 if (!pHandle)
477 {
478 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
479 ERR("HeapAlloc failed with error %lu!\n", GetLastError());
480 goto Cleanup;
481 }
482
483 pHandle->hPrinter = hPrinter;
484 pHandle->hSPLFile = INVALID_HANDLE_VALUE;
485
486 // Return it as phPrinter.
487 *phPrinter = (HANDLE)pHandle;
488 }
489
490 Cleanup:
491 SetLastError(dwErrorCode);
492 return (dwErrorCode == ERROR_SUCCESS);
493 }
494
495 BOOL WINAPI
496 ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead)
497 {
498 DWORD dwErrorCode;
499 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
500
501 // Sanity checks.
502 if (!pHandle)
503 {
504 dwErrorCode = ERROR_INVALID_HANDLE;
505 goto Cleanup;
506 }
507
508 // Do the RPC call
509 RpcTryExcept
510 {
511 dwErrorCode = _RpcReadPrinter(pHandle->hPrinter, pBuf, cbBuf, pNoBytesRead);
512 }
513 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
514 {
515 dwErrorCode = RpcExceptionCode();
516 ERR("_RpcReadPrinter failed with exception code %lu!\n", dwErrorCode);
517 }
518 RpcEndExcept;
519
520 Cleanup:
521 SetLastError(dwErrorCode);
522 return (dwErrorCode == ERROR_SUCCESS);
523 }
524
525 BOOL WINAPI
526 ResetPrinterW(HANDLE hPrinter, PPRINTER_DEFAULTSW pDefault)
527 {
528 UNIMPLEMENTED;
529 return FALSE;
530 }
531
532 BOOL WINAPI
533 SetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command)
534 {
535 UNIMPLEMENTED;
536 return FALSE;
537 }
538
539 DWORD WINAPI
540 StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
541 {
542 DWORD cbAddJobInfo1;
543 DWORD cbNeeded;
544 DWORD dwErrorCode;
545 PADDJOB_INFO_1W pAddJobInfo1 = NULL;
546 PDOC_INFO_1W pDocInfo1 = (PDOC_INFO_1W)pDocInfo;
547 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
548
549 // Sanity checks.
550 if (!pHandle)
551 {
552 dwErrorCode = ERROR_INVALID_HANDLE;
553 goto Cleanup;
554 }
555
556 if (!pDocInfo1)
557 {
558 dwErrorCode = ERROR_INVALID_PARAMETER;
559 goto Cleanup;
560 }
561
562 if (Level != 1)
563 {
564 dwErrorCode = ERROR_INVALID_LEVEL;
565 goto Cleanup;
566 }
567
568 if (pHandle->bStartedDoc)
569 {
570 dwErrorCode = ERROR_INVALID_PRINTER_STATE;
571 goto Cleanup;
572 }
573
574 // Check if we want to redirect output into a file.
575 if (pDocInfo1->pOutputFile)
576 {
577 // Do a StartDocPrinter RPC call in this case.
578 dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
579 }
580 else
581 {
582 // Allocate memory for the ADDJOB_INFO_1W structure and a path.
583 cbAddJobInfo1 = sizeof(ADDJOB_INFO_1W) + MAX_PATH * sizeof(WCHAR);
584 pAddJobInfo1 = HeapAlloc(hProcessHeap, 0, cbAddJobInfo1);
585 if (!pAddJobInfo1)
586 {
587 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
588 ERR("HeapAlloc failed with error %lu!\n", GetLastError());
589 goto Cleanup;
590 }
591
592 // Try to add a new job.
593 // This only succeeds if the printer is set to do spooled printing.
594 if (AddJobW((HANDLE)pHandle, 1, (PBYTE)pAddJobInfo1, cbAddJobInfo1, &cbNeeded))
595 {
596 // Do spooled printing.
597 dwErrorCode = _StartDocPrinterSpooled(pHandle, pDocInfo1, pAddJobInfo1);
598 }
599 else if (GetLastError() == ERROR_INVALID_ACCESS)
600 {
601 // ERROR_INVALID_ACCESS is returned when the printer is set to do direct printing.
602 // In this case, we do a StartDocPrinter RPC call.
603 dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
604 }
605 else
606 {
607 dwErrorCode = GetLastError();
608 ERR("AddJobW failed with error %lu!\n", dwErrorCode);
609 goto Cleanup;
610 }
611 }
612
613 if (dwErrorCode == ERROR_SUCCESS)
614 pHandle->bStartedDoc = TRUE;
615
616 Cleanup:
617 if (pAddJobInfo1)
618 HeapFree(hProcessHeap, 0, pAddJobInfo1);
619
620 SetLastError(dwErrorCode);
621 return pHandle->dwJobID;
622 }
623
624 BOOL WINAPI
625 StartPagePrinter(HANDLE hPrinter)
626 {
627 DWORD dwErrorCode;
628 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
629
630 // Sanity checks.
631 if (!pHandle)
632 {
633 dwErrorCode = ERROR_INVALID_HANDLE;
634 goto Cleanup;
635 }
636
637 // Do the RPC call
638 RpcTryExcept
639 {
640 dwErrorCode = _RpcStartPagePrinter(pHandle->hPrinter);
641 }
642 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
643 {
644 dwErrorCode = RpcExceptionCode();
645 ERR("_RpcStartPagePrinter failed with exception code %lu!\n", dwErrorCode);
646 }
647 RpcEndExcept;
648
649 Cleanup:
650 SetLastError(dwErrorCode);
651 return (dwErrorCode == ERROR_SUCCESS);
652 }
653
654 BOOL WINAPI
655 WritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten)
656 {
657 DWORD dwErrorCode;
658 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
659
660 // Sanity checks.
661 if (!pHandle)
662 {
663 dwErrorCode = ERROR_INVALID_HANDLE;
664 goto Cleanup;
665 }
666
667 if (!pHandle->bStartedDoc)
668 {
669 dwErrorCode = ERROR_SPL_NO_STARTDOC;
670 goto Cleanup;
671 }
672
673 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
674 {
675 // Write to the spool file. This doesn't need an RPC request.
676 if (!WriteFile(pHandle->hSPLFile, pBuf, cbBuf, pcWritten, NULL))
677 {
678 dwErrorCode = GetLastError();
679 ERR("WriteFile failed with error %lu!\n", dwErrorCode);
680 goto Cleanup;
681 }
682
683 dwErrorCode = ERROR_SUCCESS;
684 }
685 else
686 {
687 // TODO: This case (for direct printing or remote printing) has bad performance if multiple small-sized WritePrinter calls are performed.
688 // We may increase performance by writing into a buffer and only doing a single RPC call when the buffer is full.
689
690 // Do the RPC call
691 RpcTryExcept
692 {
693 dwErrorCode = _RpcWritePrinter(pHandle->hPrinter, pBuf, cbBuf, pcWritten);
694 }
695 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
696 {
697 dwErrorCode = RpcExceptionCode();
698 ERR("_RpcWritePrinter failed with exception code %lu!\n", dwErrorCode);
699 }
700 RpcEndExcept;
701 }
702
703 Cleanup:
704 SetLastError(dwErrorCode);
705 return (dwErrorCode == ERROR_SUCCESS);
706 }
707
708 BOOL WINAPI
709 XcvDataW(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded, PDWORD pdwStatus)
710 {
711 return FALSE;
712 }