Merge r68232 to get Windows' rpcrt4.dll to work under ReactOS.
[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 pJobInfo1->pDatatype = pDocInfo1->pDatatype;
93 pJobInfo1->pDocument = pDocInfo1->pDocName;
94
95 // Set the new job information.
96 if (!SetJobW((HANDLE)pHandle, 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 = { 0 };
440 ACCESS_MASK AccessRequired = 0;
441
442 // Prepare the additional parameters in the format required by _RpcOpenPrinter
443 if (pDefault)
444 {
445 pDatatype = pDefault->pDatatype;
446 DevModeContainer.cbBuf = sizeof(DEVMODEW);
447 DevModeContainer.pDevMode = (BYTE*)pDefault->pDevMode;
448 AccessRequired = pDefault->DesiredAccess;
449 }
450
451 // Do the RPC call
452 RpcTryExcept
453 {
454 dwErrorCode = _RpcOpenPrinter(pPrinterName, &hPrinter, pDatatype, &DevModeContainer, AccessRequired);
455 }
456 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
457 {
458 dwErrorCode = RpcExceptionCode();
459 ERR("_RpcOpenPrinter failed with exception code %lu!\n", dwErrorCode);
460 }
461 RpcEndExcept;
462
463 if (dwErrorCode == ERROR_SUCCESS)
464 {
465 // Create a new SPOOLER_HANDLE structure.
466 pHandle = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(SPOOLER_HANDLE));
467 if (!pHandle)
468 {
469 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
470 ERR("HeapAlloc failed with error %lu!\n", GetLastError());
471 goto Cleanup;
472 }
473
474 pHandle->hPrinter = hPrinter;
475 pHandle->hSPLFile = INVALID_HANDLE_VALUE;
476
477 // Return it as phPrinter.
478 *phPrinter = (HANDLE)pHandle;
479 }
480
481 Cleanup:
482 SetLastError(dwErrorCode);
483 return (dwErrorCode == ERROR_SUCCESS);
484 }
485
486 BOOL WINAPI
487 ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead)
488 {
489 DWORD dwErrorCode;
490 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
491
492 // Sanity checks.
493 if (!pHandle)
494 {
495 dwErrorCode = ERROR_INVALID_HANDLE;
496 goto Cleanup;
497 }
498
499 // Do the RPC call
500 RpcTryExcept
501 {
502 dwErrorCode = _RpcReadPrinter(pHandle->hPrinter, pBuf, cbBuf, pNoBytesRead);
503 }
504 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
505 {
506 dwErrorCode = RpcExceptionCode();
507 ERR("_RpcReadPrinter failed with exception code %lu!\n", dwErrorCode);
508 }
509 RpcEndExcept;
510
511 Cleanup:
512 SetLastError(dwErrorCode);
513 return (dwErrorCode == ERROR_SUCCESS);
514 }
515
516 DWORD WINAPI
517 StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
518 {
519 DWORD cbAddJobInfo1;
520 DWORD cbNeeded;
521 DWORD dwErrorCode;
522 PADDJOB_INFO_1W pAddJobInfo1 = NULL;
523 PDOC_INFO_1W pDocInfo1 = (PDOC_INFO_1W)pDocInfo;
524 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
525
526 // Sanity checks.
527 if (!pHandle)
528 {
529 dwErrorCode = ERROR_INVALID_HANDLE;
530 goto Cleanup;
531 }
532
533 if (!pDocInfo1)
534 {
535 dwErrorCode = ERROR_INVALID_PARAMETER;
536 goto Cleanup;
537 }
538
539 if (Level != 1)
540 {
541 dwErrorCode = ERROR_INVALID_LEVEL;
542 goto Cleanup;
543 }
544
545 if (pHandle->bStartedDoc)
546 {
547 dwErrorCode = ERROR_INVALID_PRINTER_STATE;
548 goto Cleanup;
549 }
550
551 // Check if we want to redirect output into a file.
552 if (pDocInfo1->pOutputFile)
553 {
554 // Do a StartDocPrinter RPC call in this case.
555 dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
556 }
557 else
558 {
559 // Allocate memory for the ADDJOB_INFO_1W structure and a path.
560 cbAddJobInfo1 = sizeof(ADDJOB_INFO_1W) + MAX_PATH * sizeof(WCHAR);
561 pAddJobInfo1 = HeapAlloc(hProcessHeap, 0, cbAddJobInfo1);
562 if (!pAddJobInfo1)
563 {
564 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
565 ERR("HeapAlloc failed with error %lu!\n", GetLastError());
566 goto Cleanup;
567 }
568
569 // Try to add a new job.
570 // This only succeeds if the printer is set to do spooled printing.
571 if (AddJobW((HANDLE)pHandle, 1, (PBYTE)pAddJobInfo1, cbAddJobInfo1, &cbNeeded))
572 {
573 // Do spooled printing.
574 dwErrorCode = _StartDocPrinterSpooled(pHandle, pDocInfo1, pAddJobInfo1);
575 }
576 else if (GetLastError() == ERROR_INVALID_ACCESS)
577 {
578 // ERROR_INVALID_ACCESS is returned when the printer is set to do direct printing.
579 // In this case, we do a StartDocPrinter RPC call.
580 dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
581 }
582 else
583 {
584 dwErrorCode = GetLastError();
585 ERR("AddJobW failed with error %lu!\n", dwErrorCode);
586 goto Cleanup;
587 }
588 }
589
590 if (dwErrorCode == ERROR_SUCCESS)
591 pHandle->bStartedDoc = TRUE;
592
593 Cleanup:
594 if (pAddJobInfo1)
595 HeapFree(hProcessHeap, 0, pAddJobInfo1);
596
597 SetLastError(dwErrorCode);
598 return pHandle->dwJobID;
599 }
600
601 BOOL WINAPI
602 StartPagePrinter(HANDLE hPrinter)
603 {
604 DWORD dwErrorCode;
605 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
606
607 // Sanity checks.
608 if (!pHandle)
609 {
610 dwErrorCode = ERROR_INVALID_HANDLE;
611 goto Cleanup;
612 }
613
614 // Do the RPC call
615 RpcTryExcept
616 {
617 dwErrorCode = _RpcStartPagePrinter(pHandle->hPrinter);
618 }
619 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
620 {
621 dwErrorCode = RpcExceptionCode();
622 ERR("_RpcStartPagePrinter failed with exception code %lu!\n", dwErrorCode);
623 }
624 RpcEndExcept;
625
626 Cleanup:
627 SetLastError(dwErrorCode);
628 return (dwErrorCode == ERROR_SUCCESS);
629 }
630
631 BOOL WINAPI
632 WritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten)
633 {
634 DWORD dwErrorCode;
635 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
636
637 // Sanity checks.
638 if (!pHandle)
639 {
640 dwErrorCode = ERROR_INVALID_HANDLE;
641 goto Cleanup;
642 }
643
644 if (!pHandle->bStartedDoc)
645 {
646 dwErrorCode = ERROR_SPL_NO_STARTDOC;
647 goto Cleanup;
648 }
649
650 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
651 {
652 // Write to the spool file. This doesn't need an RPC request.
653 if (!WriteFile(pHandle->hSPLFile, pBuf, cbBuf, pcWritten, NULL))
654 {
655 dwErrorCode = GetLastError();
656 ERR("WriteFile failed with error %lu!\n", dwErrorCode);
657 goto Cleanup;
658 }
659
660 dwErrorCode = ERROR_SUCCESS;
661 }
662 else
663 {
664 // TODO: This case (for direct printing or remote printing) has bad performance if multiple small-sized WritePrinter calls are performed.
665 // We may increase performance by writing into a buffer and only doing a single RPC call when the buffer is full.
666
667 // Do the RPC call
668 RpcTryExcept
669 {
670 dwErrorCode = _RpcWritePrinter(pHandle->hPrinter, pBuf, cbBuf, pcWritten);
671 }
672 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
673 {
674 dwErrorCode = RpcExceptionCode();
675 ERR("_RpcWritePrinter failed with exception code %lu!\n", dwErrorCode);
676 }
677 RpcEndExcept;
678 }
679
680 Cleanup:
681 SetLastError(dwErrorCode);
682 return (dwErrorCode == ERROR_SUCCESS);
683 }
684
685 BOOL WINAPI
686 XcvDataW(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded, PDWORD pdwStatus)
687 {
688 return FALSE;
689 }