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>
11 _MarshallUpPrinterInfo(PBYTE pPrinterInfo
, DWORD Level
)
13 PPRINTER_INFO_1W pPrinterInfo1
;
14 PPRINTER_INFO_2W pPrinterInfo2
;
16 // Replace relative offset addresses in the output by absolute pointers.
19 pPrinterInfo1
= (PPRINTER_INFO_1W
)pPrinterInfo
;
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
);
27 pPrinterInfo2
= (PPRINTER_INFO_2W
)pPrinterInfo
;
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
);
41 if (pPrinterInfo2
->pServerName
)
42 pPrinterInfo2
->pServerName
= (PWSTR
)((ULONG_PTR
)pPrinterInfo2
->pServerName
+ (ULONG_PTR
)pPrinterInfo2
);
44 if (pPrinterInfo2
->pSecurityDescriptor
)
45 pPrinterInfo2
->pSecurityDescriptor
= (PWSTR
)((ULONG_PTR
)pPrinterInfo2
->pSecurityDescriptor
+ (ULONG_PTR
)pPrinterInfo2
);
50 _StartDocPrinterSpooled(PSPOOLER_HANDLE pHandle
, PDOC_INFO_1W pDocInfo1
, PADDJOB_INFO_1W pAddJobInfo1
)
54 PJOB_INFO_1W pJobInfo1
= NULL
;
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
)
60 dwErrorCode
= GetLastError();
61 ERR("CreateFileW failed for \"%S\" with error %lu!\n", pAddJobInfo1
->Path
, dwErrorCode
);
65 // Get the size of the job information.
66 GetJobW((HANDLE
)pHandle
, pAddJobInfo1
->JobId
, 1, NULL
, 0, &cbNeeded
);
67 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
69 dwErrorCode
= GetLastError();
70 ERR("GetJobW failed with error %lu!\n", dwErrorCode
);
74 // Allocate enough memory for the returned job information.
75 pJobInfo1
= HeapAlloc(hProcessHeap
, 0, cbNeeded
);
78 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
79 ERR("HeapAlloc failed with error %lu!\n", GetLastError());
83 // Get the job information.
84 if (!GetJobW((HANDLE
)pHandle
, pAddJobInfo1
->JobId
, 1, (PBYTE
)pJobInfo1
, cbNeeded
, &cbNeeded
))
86 dwErrorCode
= GetLastError();
87 ERR("GetJobW failed with error %lu!\n", dwErrorCode
);
91 // Add our document information.
92 if (pDocInfo1
->pDatatype
)
93 pJobInfo1
->pDatatype
= pDocInfo1
->pDatatype
;
95 pJobInfo1
->pDocument
= pDocInfo1
->pDocName
;
97 // Set the new job information.
98 if (!SetJobW((HANDLE
)pHandle
, pAddJobInfo1
->JobId
, 1, (PBYTE
)pJobInfo1
, 0))
100 dwErrorCode
= GetLastError();
101 ERR("SetJobW failed with error %lu!\n", dwErrorCode
);
105 // We were successful!
106 pHandle
->dwJobID
= pAddJobInfo1
->JobId
;
107 dwErrorCode
= ERROR_SUCCESS
;
111 HeapFree(hProcessHeap
, 0, pJobInfo1
);
117 _StartDocPrinterWithRPC(PSPOOLER_HANDLE pHandle
, PDOC_INFO_1W pDocInfo1
)
120 WINSPOOL_DOC_INFO_CONTAINER DocInfoContainer
;
122 DocInfoContainer
.Level
= 1;
123 DocInfoContainer
.DocInfo
.pDocInfo1
= (WINSPOOL_DOC_INFO_1
*)pDocInfo1
;
127 dwErrorCode
= _RpcStartDocPrinter(pHandle
->hPrinter
, &DocInfoContainer
, &pHandle
->dwJobID
);
129 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
131 dwErrorCode
= RpcExceptionCode();
132 ERR("_RpcStartDocPrinter failed with exception code %lu!\n", dwErrorCode
);
140 AddPrinterW(PWSTR pName
, DWORD Level
, PBYTE pPrinter
)
147 ClosePrinter(HANDLE hPrinter
)
150 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
155 dwErrorCode
= ERROR_INVALID_HANDLE
;
162 dwErrorCode
= _RpcClosePrinter(pHandle
->hPrinter
);
164 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
166 dwErrorCode
= RpcExceptionCode();
167 ERR("_RpcClosePrinter failed with exception code %lu!\n", dwErrorCode
);
171 // Close any open file handle.
172 if (pHandle
->hSPLFile
!= INVALID_HANDLE_VALUE
)
173 CloseHandle(pHandle
->hSPLFile
);
175 // Free the memory for the handle.
176 HeapFree(hProcessHeap
, 0, pHandle
);
179 SetLastError(dwErrorCode
);
180 return (dwErrorCode
== ERROR_SUCCESS
);
185 DeviceCapabilitiesA(LPCSTR pDevice
, LPCSTR pPort
, WORD fwCapability
, LPSTR pOutput
, const DEVMODEA
* pDevMode
)
191 DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
, WORD fwCapability
, LPWSTR pOutput
, const DEVMODEW
* pDevMode
)
197 DocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
, PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
, DWORD fMode
)
203 DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
, PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
, DWORD fMode
)
209 EndDocPrinter(HANDLE hPrinter
)
212 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
217 dwErrorCode
= ERROR_INVALID_HANDLE
;
221 if (pHandle
->hSPLFile
!= INVALID_HANDLE_VALUE
)
223 // For spooled jobs, the document is finished by calling _RpcScheduleJob.
226 dwErrorCode
= _RpcScheduleJob(pHandle
->hPrinter
, pHandle
->dwJobID
);
228 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
230 dwErrorCode
= RpcExceptionCode();
231 ERR("_RpcScheduleJob failed with exception code %lu!\n", dwErrorCode
);
235 // Close the spool file handle.
236 CloseHandle(pHandle
->hSPLFile
);
240 // In all other cases, just call _RpcEndDocPrinter.
243 dwErrorCode
= _RpcEndDocPrinter(pHandle
->hPrinter
);
245 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
247 dwErrorCode
= RpcExceptionCode();
248 ERR("_RpcEndDocPrinter failed with exception code %lu!\n", dwErrorCode
);
253 // A new document can now be started again.
254 pHandle
->bStartedDoc
= FALSE
;
257 SetLastError(dwErrorCode
);
258 return (dwErrorCode
== ERROR_SUCCESS
);
262 EndPagePrinter(HANDLE hPrinter
)
265 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
270 dwErrorCode
= ERROR_INVALID_HANDLE
;
274 if (pHandle
->hSPLFile
!= INVALID_HANDLE_VALUE
)
276 // For spooled jobs, we don't need to do anything.
277 dwErrorCode
= ERROR_SUCCESS
;
281 // In all other cases, just call _RpcEndPagePrinter.
284 dwErrorCode
= _RpcEndPagePrinter(pHandle
->hPrinter
);
286 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
288 dwErrorCode
= RpcExceptionCode();
289 ERR("_RpcEndPagePrinter failed with exception code %lu!\n", dwErrorCode
);
295 SetLastError(dwErrorCode
);
296 return (dwErrorCode
== ERROR_SUCCESS
);
300 EnumPrintersA(DWORD Flags
, PSTR Name
, DWORD Level
, PBYTE pPrinterEnum
, DWORD cbBuf
, PDWORD pcbNeeded
, PDWORD pcReturned
)
306 EnumPrintersW(DWORD Flags
, PWSTR Name
, DWORD Level
, PBYTE pPrinterEnum
, DWORD cbBuf
, PDWORD pcbNeeded
, PDWORD pcReturned
)
310 PBYTE p
= pPrinterEnum
;
315 dwErrorCode
= _RpcEnumPrinters(Flags
, Name
, Level
, pPrinterEnum
, cbBuf
, pcbNeeded
, pcReturned
);
317 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
319 dwErrorCode
= RpcExceptionCode();
320 ERR("_RpcEnumPrinters failed with exception code %lu!\n", dwErrorCode
);
324 if (dwErrorCode
== ERROR_SUCCESS
)
326 // Replace relative offset addresses in the output by absolute pointers.
327 for (i
= 0; i
< *pcReturned
; i
++)
329 _MarshallUpPrinterInfo(p
, Level
);
332 p
+= sizeof(PRINTER_INFO_1W
);
334 p
+= sizeof(PRINTER_INFO_2W
);
338 SetLastError(dwErrorCode
);
339 return (dwErrorCode
== ERROR_SUCCESS
);
343 GetDefaultPrinterA(LPSTR pszBuffer
, LPDWORD pcchBuffer
)
349 GetDefaultPrinterW(LPWSTR pszBuffer
, LPDWORD pcchBuffer
)
355 GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD cbBuf
, LPDWORD pcbNeeded
)
361 GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
, DWORD Level
, LPBYTE pDriverInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
)
367 GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
, DWORD Level
, LPBYTE pDriverInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
)
373 GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD cbBuf
, LPDWORD pcbNeeded
)
379 OpenPrinterA(LPSTR pPrinterName
, LPHANDLE phPrinter
, LPPRINTER_DEFAULTSA pDefault
)
381 BOOL bReturnValue
= FALSE
;
383 PWSTR pwszPrinterName
= NULL
;
384 PRINTER_DEFAULTSW wDefault
= { 0 };
388 // Convert pPrinterName to a Unicode string pwszPrinterName
389 cch
= strlen(pPrinterName
);
391 pwszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
392 if (!pwszPrinterName
)
394 ERR("HeapAlloc failed for pwszPrinterName with last error %lu!\n", GetLastError());
398 MultiByteToWideChar(CP_ACP
, 0, pPrinterName
, -1, pwszPrinterName
, cch
+ 1);
403 wDefault
.DesiredAccess
= pDefault
->DesiredAccess
;
405 if (pDefault
->pDatatype
)
407 // Convert pDefault->pDatatype to a Unicode string wDefault.pDatatype
408 cch
= strlen(pDefault
->pDatatype
);
410 wDefault
.pDatatype
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
411 if (!wDefault
.pDatatype
)
413 ERR("HeapAlloc failed for wDefault.pDatatype with last error %lu!\n", GetLastError());
417 MultiByteToWideChar(CP_ACP
, 0, pDefault
->pDatatype
, -1, wDefault
.pDatatype
, cch
+ 1);
420 if (pDefault
->pDevMode
)
421 wDefault
.pDevMode
= GdiConvertToDevmodeW(pDefault
->pDevMode
);
424 bReturnValue
= OpenPrinterW(pwszPrinterName
, phPrinter
, &wDefault
);
427 if (wDefault
.pDatatype
)
428 HeapFree(hProcessHeap
, 0, wDefault
.pDatatype
);
430 if (wDefault
.pDevMode
)
431 HeapFree(hProcessHeap
, 0, wDefault
.pDevMode
);
434 HeapFree(hProcessHeap
, 0, pwszPrinterName
);
440 OpenPrinterW(LPWSTR pPrinterName
, LPHANDLE phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
444 PSPOOLER_HANDLE pHandle
;
445 PWSTR pDatatype
= NULL
;
446 WINSPOOL_DEVMODE_CONTAINER DevModeContainer
= { 0 };
447 ACCESS_MASK AccessRequired
= 0;
449 // Prepare the additional parameters in the format required by _RpcOpenPrinter
452 pDatatype
= pDefault
->pDatatype
;
453 DevModeContainer
.cbBuf
= sizeof(DEVMODEW
);
454 DevModeContainer
.pDevMode
= (BYTE
*)pDefault
->pDevMode
;
455 AccessRequired
= pDefault
->DesiredAccess
;
461 dwErrorCode
= _RpcOpenPrinter(pPrinterName
, &hPrinter
, pDatatype
, &DevModeContainer
, AccessRequired
);
463 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
465 dwErrorCode
= RpcExceptionCode();
466 ERR("_RpcOpenPrinter failed with exception code %lu!\n", dwErrorCode
);
470 if (dwErrorCode
== ERROR_SUCCESS
)
472 // Create a new SPOOLER_HANDLE structure.
473 pHandle
= HeapAlloc(hProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(SPOOLER_HANDLE
));
476 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
477 ERR("HeapAlloc failed with error %lu!\n", GetLastError());
481 pHandle
->hPrinter
= hPrinter
;
482 pHandle
->hSPLFile
= INVALID_HANDLE_VALUE
;
484 // Return it as phPrinter.
485 *phPrinter
= (HANDLE
)pHandle
;
489 SetLastError(dwErrorCode
);
490 return (dwErrorCode
== ERROR_SUCCESS
);
494 ReadPrinter(HANDLE hPrinter
, PVOID pBuf
, DWORD cbBuf
, PDWORD pNoBytesRead
)
497 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
502 dwErrorCode
= ERROR_INVALID_HANDLE
;
509 dwErrorCode
= _RpcReadPrinter(pHandle
->hPrinter
, pBuf
, cbBuf
, pNoBytesRead
);
511 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
513 dwErrorCode
= RpcExceptionCode();
514 ERR("_RpcReadPrinter failed with exception code %lu!\n", dwErrorCode
);
519 SetLastError(dwErrorCode
);
520 return (dwErrorCode
== ERROR_SUCCESS
);
524 ResetPrinterW(HANDLE hPrinter
, PPRINTER_DEFAULTSW pDefault
)
531 SetPrinterW(HANDLE hPrinter
, DWORD Level
, PBYTE pPrinter
, DWORD Command
)
538 StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, PBYTE pDocInfo
)
540 DOC_INFO_1W wDocInfo1
= { 0 };
543 DWORD dwReturnValue
= 0;
544 PDOC_INFO_1A pDocInfo1
= (PDOC_INFO_1A
)pDocInfo
;
546 // Only check the minimum required for accessing pDocInfo.
547 // Additional sanity checks are done in StartDocPrinterW.
550 dwErrorCode
= ERROR_INVALID_PARAMETER
;
556 dwErrorCode
= ERROR_INVALID_LEVEL
;
560 if (pDocInfo1
->pDatatype
)
562 // Convert pDocInfo1->pDatatype to a Unicode string wDocInfo1.pDatatype
563 cch
= strlen(pDocInfo1
->pDatatype
);
565 wDocInfo1
.pDatatype
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
566 if (!wDocInfo1
.pDatatype
)
568 ERR("HeapAlloc failed for wDocInfo1.pDatatype with last error %lu!\n", GetLastError());
572 MultiByteToWideChar(CP_ACP
, 0, pDocInfo1
->pDatatype
, -1, wDocInfo1
.pDatatype
, cch
+ 1);
575 if (pDocInfo1
->pDocName
)
577 // Convert pDocInfo1->pDocName to a Unicode string wDocInfo1.pDocName
578 cch
= strlen(pDocInfo1
->pDocName
);
580 wDocInfo1
.pDocName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
581 if (!wDocInfo1
.pDocName
)
583 ERR("HeapAlloc failed for wDocInfo1.pDocName with last error %lu!\n", GetLastError());
587 MultiByteToWideChar(CP_ACP
, 0, pDocInfo1
->pDocName
, -1, wDocInfo1
.pDocName
, cch
+ 1);
590 if (pDocInfo1
->pOutputFile
)
592 // Convert pDocInfo1->pOutputFile to a Unicode string wDocInfo1.pOutputFile
593 cch
= strlen(pDocInfo1
->pOutputFile
);
595 wDocInfo1
.pOutputFile
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
596 if (!wDocInfo1
.pOutputFile
)
598 ERR("HeapAlloc failed for wDocInfo1.pOutputFile with last error %lu!\n", GetLastError());
602 MultiByteToWideChar(CP_ACP
, 0, pDocInfo1
->pOutputFile
, -1, wDocInfo1
.pOutputFile
, cch
+ 1);
605 dwReturnValue
= StartDocPrinterW(hPrinter
, Level
, (PBYTE
)&wDocInfo1
);
606 dwErrorCode
= GetLastError();
609 if (wDocInfo1
.pDatatype
)
610 HeapFree(hProcessHeap
, 0, wDocInfo1
.pDatatype
);
612 if (wDocInfo1
.pDocName
)
613 HeapFree(hProcessHeap
, 0, wDocInfo1
.pDocName
);
615 if (wDocInfo1
.pOutputFile
)
616 HeapFree(hProcessHeap
, 0, wDocInfo1
.pOutputFile
);
618 SetLastError(dwErrorCode
);
619 return dwReturnValue
;
623 StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, PBYTE pDocInfo
)
628 DWORD dwReturnValue
= 0;
629 PADDJOB_INFO_1W pAddJobInfo1
= NULL
;
630 PDOC_INFO_1W pDocInfo1
= (PDOC_INFO_1W
)pDocInfo
;
631 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
636 dwErrorCode
= ERROR_INVALID_HANDLE
;
642 dwErrorCode
= ERROR_INVALID_PARAMETER
;
648 dwErrorCode
= ERROR_INVALID_LEVEL
;
652 if (pHandle
->bStartedDoc
)
654 dwErrorCode
= ERROR_INVALID_PRINTER_STATE
;
658 // Check if we want to redirect output into a file.
659 if (pDocInfo1
->pOutputFile
)
661 // Do a StartDocPrinter RPC call in this case.
662 dwErrorCode
= _StartDocPrinterWithRPC(pHandle
, pDocInfo1
);
666 // Allocate memory for the ADDJOB_INFO_1W structure and a path.
667 cbAddJobInfo1
= sizeof(ADDJOB_INFO_1W
) + MAX_PATH
* sizeof(WCHAR
);
668 pAddJobInfo1
= HeapAlloc(hProcessHeap
, 0, cbAddJobInfo1
);
671 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
672 ERR("HeapAlloc failed with error %lu!\n", GetLastError());
676 // Try to add a new job.
677 // This only succeeds if the printer is set to do spooled printing.
678 if (AddJobW((HANDLE
)pHandle
, 1, (PBYTE
)pAddJobInfo1
, cbAddJobInfo1
, &cbNeeded
))
680 // Do spooled printing.
681 dwErrorCode
= _StartDocPrinterSpooled(pHandle
, pDocInfo1
, pAddJobInfo1
);
683 else if (GetLastError() == ERROR_INVALID_ACCESS
)
685 // ERROR_INVALID_ACCESS is returned when the printer is set to do direct printing.
686 // In this case, we do a StartDocPrinter RPC call.
687 dwErrorCode
= _StartDocPrinterWithRPC(pHandle
, pDocInfo1
);
691 dwErrorCode
= GetLastError();
692 ERR("AddJobW failed with error %lu!\n", dwErrorCode
);
697 if (dwErrorCode
== ERROR_SUCCESS
)
699 pHandle
->bStartedDoc
= TRUE
;
700 dwReturnValue
= pHandle
->dwJobID
;
705 HeapFree(hProcessHeap
, 0, pAddJobInfo1
);
707 SetLastError(dwErrorCode
);
708 return dwReturnValue
;
712 StartPagePrinter(HANDLE hPrinter
)
715 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
720 dwErrorCode
= ERROR_INVALID_HANDLE
;
727 dwErrorCode
= _RpcStartPagePrinter(pHandle
->hPrinter
);
729 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
731 dwErrorCode
= RpcExceptionCode();
732 ERR("_RpcStartPagePrinter failed with exception code %lu!\n", dwErrorCode
);
737 SetLastError(dwErrorCode
);
738 return (dwErrorCode
== ERROR_SUCCESS
);
742 WritePrinter(HANDLE hPrinter
, PVOID pBuf
, DWORD cbBuf
, PDWORD pcWritten
)
745 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
750 dwErrorCode
= ERROR_INVALID_HANDLE
;
754 if (!pHandle
->bStartedDoc
)
756 dwErrorCode
= ERROR_SPL_NO_STARTDOC
;
760 if (pHandle
->hSPLFile
!= INVALID_HANDLE_VALUE
)
762 // Write to the spool file. This doesn't need an RPC request.
763 if (!WriteFile(pHandle
->hSPLFile
, pBuf
, cbBuf
, pcWritten
, NULL
))
765 dwErrorCode
= GetLastError();
766 ERR("WriteFile failed with error %lu!\n", dwErrorCode
);
770 dwErrorCode
= ERROR_SUCCESS
;
774 // TODO: This case (for direct printing or remote printing) has bad performance if multiple small-sized WritePrinter calls are performed.
775 // We may increase performance by writing into a buffer and only doing a single RPC call when the buffer is full.
780 dwErrorCode
= _RpcWritePrinter(pHandle
->hPrinter
, pBuf
, cbBuf
, pcWritten
);
782 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
784 dwErrorCode
= RpcExceptionCode();
785 ERR("_RpcWritePrinter failed with exception code %lu!\n", dwErrorCode
);
791 SetLastError(dwErrorCode
);
792 return (dwErrorCode
== ERROR_SUCCESS
);
796 XcvDataW(HANDLE hXcv
, PCWSTR pszDataName
, PBYTE pInputData
, DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
, PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)