2 * PROJECT: ReactOS Spooler API
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Functions related to Printers and printing
5 * COPYRIGHT: Copyright 2015-2018 Colin Finck (colin@reactos.org)
9 #include <marshalling/printers.h>
10 #include <marshalling/printerdrivers.h>
15 /** And the award for the most confusingly named setting goes to "Device", for storing the default printer of the current user.
16 Ok, I admit that this has historical reasons. It's still not straightforward in any way though! */
17 static const WCHAR wszWindowsKey
[] = L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows";
18 static const WCHAR wszDeviceValue
[] = L
"Device";
21 _StartDocPrinterSpooled(PSPOOLER_HANDLE pHandle
, PDOC_INFO_1W pDocInfo1
, PADDJOB_INFO_1W pAddJobInfo1
)
25 PJOB_INFO_1W pJobInfo1
= NULL
;
27 // Create the spool file.
28 pHandle
->hSPLFile
= CreateFileW(pAddJobInfo1
->Path
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, CREATE_ALWAYS
, 0, NULL
);
29 if (pHandle
->hSPLFile
== INVALID_HANDLE_VALUE
)
31 dwErrorCode
= GetLastError();
32 ERR("CreateFileW failed for \"%S\" with error %lu!\n", pAddJobInfo1
->Path
, dwErrorCode
);
36 // Get the size of the job information.
37 GetJobW((HANDLE
)pHandle
, pAddJobInfo1
->JobId
, 1, NULL
, 0, &cbNeeded
);
38 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
40 dwErrorCode
= GetLastError();
41 ERR("GetJobW failed with error %lu!\n", dwErrorCode
);
45 // Allocate enough memory for the returned job information.
46 pJobInfo1
= HeapAlloc(hProcessHeap
, 0, cbNeeded
);
49 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
50 ERR("HeapAlloc failed!\n");
54 // Get the job information.
55 if (!GetJobW((HANDLE
)pHandle
, pAddJobInfo1
->JobId
, 1, (PBYTE
)pJobInfo1
, cbNeeded
, &cbNeeded
))
57 dwErrorCode
= GetLastError();
58 ERR("GetJobW failed with error %lu!\n", dwErrorCode
);
62 // Add our document information.
63 if (pDocInfo1
->pDatatype
)
64 pJobInfo1
->pDatatype
= pDocInfo1
->pDatatype
;
66 pJobInfo1
->pDocument
= pDocInfo1
->pDocName
;
68 // Set the new job information.
69 if (!SetJobW((HANDLE
)pHandle
, pAddJobInfo1
->JobId
, 1, (PBYTE
)pJobInfo1
, 0))
71 dwErrorCode
= GetLastError();
72 ERR("SetJobW failed with error %lu!\n", dwErrorCode
);
76 // We were successful!
77 pHandle
->dwJobID
= pAddJobInfo1
->JobId
;
78 dwErrorCode
= ERROR_SUCCESS
;
82 HeapFree(hProcessHeap
, 0, pJobInfo1
);
88 _StartDocPrinterWithRPC(PSPOOLER_HANDLE pHandle
, PDOC_INFO_1W pDocInfo1
)
91 WINSPOOL_DOC_INFO_CONTAINER DocInfoContainer
;
93 DocInfoContainer
.Level
= 1;
94 DocInfoContainer
.DocInfo
.pDocInfo1
= (WINSPOOL_DOC_INFO_1
*)pDocInfo1
;
98 dwErrorCode
= _RpcStartDocPrinter(pHandle
->hPrinter
, &DocInfoContainer
, &pHandle
->dwJobID
);
100 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
102 dwErrorCode
= RpcExceptionCode();
103 ERR("_RpcStartDocPrinter failed with exception code %lu!\n", dwErrorCode
);
111 AbortPrinter(HANDLE hPrinter
)
113 TRACE("AbortPrinter(%p)\n", hPrinter
);
119 AddPrinterA(PSTR pName
, DWORD Level
, PBYTE pPrinter
)
121 TRACE("AddPrinterA(%s, %lu, %p)\n", pName
, Level
, pPrinter
);
127 AddPrinterW(PWSTR pName
, DWORD Level
, PBYTE pPrinter
)
129 TRACE("AddPrinterW(%S, %lu, %p)\n", pName
, Level
, pPrinter
);
135 ClosePrinter(HANDLE hPrinter
)
138 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
140 TRACE("ClosePrinter(%p)\n", hPrinter
);
145 dwErrorCode
= ERROR_INVALID_HANDLE
;
152 dwErrorCode
= _RpcClosePrinter(&pHandle
->hPrinter
);
154 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
156 dwErrorCode
= RpcExceptionCode();
157 ERR("_RpcClosePrinter failed with exception code %lu!\n", dwErrorCode
);
161 // Close any open file handle.
162 if (pHandle
->hSPLFile
!= INVALID_HANDLE_VALUE
)
163 CloseHandle(pHandle
->hSPLFile
);
165 // Free the memory for the handle.
166 HeapFree(hProcessHeap
, 0, pHandle
);
169 SetLastError(dwErrorCode
);
170 return (dwErrorCode
== ERROR_SUCCESS
);
174 DeletePrinter(HANDLE hPrinter
)
176 TRACE("DeletePrinter(%p)\n", hPrinter
);
182 DeviceCapabilitiesA(LPCSTR pDevice
, LPCSTR pPort
, WORD fwCapability
, LPSTR pOutput
, const DEVMODEA
* pDevMode
)
184 TRACE("DeviceCapabilitiesA(%s, %s, %hu, %p, %p)\n", pDevice
, pPort
, fwCapability
, pOutput
, pDevMode
);
190 DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
, WORD fwCapability
, LPWSTR pOutput
, const DEVMODEW
* pDevMode
)
192 TRACE("DeviceCapabilitiesW(%S, %S, %hu, %p, %p)\n", pDevice
, pPort
, fwCapability
, pOutput
, pDevMode
);
198 DocumentEvent( HANDLE hPrinter
, HDC hdc
, int iEsc
, ULONG cbIn
, PVOID pvIn
, ULONG cbOut
, PVOID pvOut
)
200 TRACE("DocumentEvent(%p, %p, %lu, %lu, %p, %lu, %p)\n", hPrinter
, hdc
, iEsc
, cbIn
, pvIn
, cbOut
, pvOut
);
202 return DOCUMENTEVENT_UNSUPPORTED
;
206 DocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
, PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
, DWORD fMode
)
208 TRACE("DocumentPropertiesA(%p, %p, %s, %p, %p, %lu)\n", hWnd
, hPrinter
, pDeviceName
, pDevModeOutput
, pDevModeInput
, fMode
);
213 static PRINTER_INFO_9W
* get_devmodeW(HANDLE hprn
)
215 PRINTER_INFO_9W
*pi9
= NULL
;
219 res
= GetPrinterW(hprn
, 9, NULL
, 0, &needed
);
220 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
))
222 pi9
= HeapAlloc(hProcessHeap
, 0, needed
);
223 res
= GetPrinterW(hprn
, 9, (LPBYTE
)pi9
, needed
, &needed
);
229 ERR("GetPrinterW failed with %u\n", GetLastError());
230 HeapFree(hProcessHeap
, 0, pi9
);
235 DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
, PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
, DWORD fMode
)
237 HANDLE hUseHandle
= NULL
;
238 PRINTER_INFO_9W
*pi9
= NULL
;
239 LONG Result
= -1, Length
;
241 TRACE("DocumentPropertiesW(%p, %p, %S, %p, %p, %lu)\n", hWnd
, hPrinter
, pDeviceName
, pDevModeOutput
, pDevModeInput
, fMode
);
244 hUseHandle
= hPrinter
;
246 else if (!OpenPrinterW(pDeviceName
, &hUseHandle
, NULL
))
248 ERR("No handle, and no usable printer name passed in\n");
252 pi9
= get_devmodeW(hUseHandle
);
256 Length
= pi9
->pDevMode
->dmSize
+ pi9
->pDevMode
->dmDriverExtra
;
257 // See wineps.drv PSDRV_ExtDeviceMode
260 Result
= 1; /* IDOK */
262 if (fMode
& DM_IN_BUFFER
)
264 FIXME("Merge pDevModeInput with pi9, write back to driver!\n");
265 // See wineps.drv PSDRV_MergeDevmodes
268 if (fMode
& DM_IN_PROMPT
)
270 FIXME("Show property sheet!\n");
271 Result
= 2; /* IDCANCEL */
274 if (fMode
& (DM_OUT_BUFFER
| DM_OUT_DEFAULT
))
278 memcpy(pDevModeOutput
, pi9
->pDevMode
, pi9
->pDevMode
->dmSize
+ pi9
->pDevMode
->dmDriverExtra
);
282 ERR("No pDevModeOutput\n");
292 HeapFree(hProcessHeap
, 0, pi9
);
295 if (hUseHandle
&& !hPrinter
)
296 ClosePrinter(hUseHandle
);
301 EndDocPrinter(HANDLE hPrinter
)
304 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
306 TRACE("EndDocPrinter(%p)\n", hPrinter
);
311 dwErrorCode
= ERROR_INVALID_HANDLE
;
315 if (pHandle
->hSPLFile
!= INVALID_HANDLE_VALUE
)
317 // For spooled jobs, the document is finished by calling _RpcScheduleJob.
320 dwErrorCode
= _RpcScheduleJob(pHandle
->hPrinter
, pHandle
->dwJobID
);
322 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
324 dwErrorCode
= RpcExceptionCode();
325 ERR("_RpcScheduleJob failed with exception code %lu!\n", dwErrorCode
);
329 // Close the spool file handle.
330 CloseHandle(pHandle
->hSPLFile
);
334 // In all other cases, just call _RpcEndDocPrinter.
337 dwErrorCode
= _RpcEndDocPrinter(pHandle
->hPrinter
);
339 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
341 dwErrorCode
= RpcExceptionCode();
342 ERR("_RpcEndDocPrinter failed with exception code %lu!\n", dwErrorCode
);
347 // A new document can now be started again.
348 pHandle
->bStartedDoc
= FALSE
;
351 SetLastError(dwErrorCode
);
352 return (dwErrorCode
== ERROR_SUCCESS
);
356 EndPagePrinter(HANDLE hPrinter
)
359 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
361 TRACE("EndPagePrinter(%p)\n", hPrinter
);
366 dwErrorCode
= ERROR_INVALID_HANDLE
;
370 if (pHandle
->hSPLFile
!= INVALID_HANDLE_VALUE
)
372 // For spooled jobs, we don't need to do anything.
373 dwErrorCode
= ERROR_SUCCESS
;
377 // In all other cases, just call _RpcEndPagePrinter.
380 dwErrorCode
= _RpcEndPagePrinter(pHandle
->hPrinter
);
382 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
384 dwErrorCode
= RpcExceptionCode();
385 ERR("_RpcEndPagePrinter failed with exception code %lu!\n", dwErrorCode
);
391 SetLastError(dwErrorCode
);
392 return (dwErrorCode
== ERROR_SUCCESS
);
396 EnumPrintersA(DWORD Flags
, PSTR Name
, DWORD Level
, PBYTE pPrinterEnum
, DWORD cbBuf
, PDWORD pcbNeeded
, PDWORD pcReturned
)
398 BOOL bReturnValue
= FALSE
;
400 PWSTR pwszName
= NULL
;
401 PSTR pszPrinterName
= NULL
;
402 PSTR pszServerName
= NULL
;
403 PSTR pszDescription
= NULL
;
405 PSTR pszComment
= NULL
;
406 PSTR pszShareName
= NULL
;
407 PSTR pszPortName
= NULL
;
408 PSTR pszDriverName
= NULL
;
409 PSTR pszLocation
= NULL
;
410 PSTR pszSepFile
= NULL
;
411 PSTR pszPrintProcessor
= NULL
;
412 PSTR pszDatatype
= NULL
;
413 PSTR pszParameters
= NULL
;
415 PPRINTER_INFO_1W ppi1w
= NULL
;
416 PPRINTER_INFO_1A ppi1a
= NULL
;
417 PPRINTER_INFO_2W ppi2w
= NULL
;
418 PPRINTER_INFO_2A ppi2a
= NULL
;
419 PPRINTER_INFO_4W ppi4w
= NULL
;
420 PPRINTER_INFO_4A ppi4a
= NULL
;
421 PPRINTER_INFO_5W ppi5w
= NULL
;
422 PPRINTER_INFO_5A ppi5a
= NULL
;
424 TRACE("EnumPrintersA(%lu, %s, %lu, %p, %lu, %p, %p)\n", Flags
, Name
, Level
, pPrinterEnum
, cbBuf
, pcbNeeded
, pcReturned
);
426 // Check for invalid levels here for early error return. MSDN says that only 1, 2, 4, and 5 are allowable.
427 if (Level
!= 1 && Level
!= 2 && Level
!= 4 && Level
!= 5)
429 SetLastError(ERROR_INVALID_LEVEL
);
430 ERR("Invalid Level!\n");
436 // Convert pName to a Unicode string pwszName.
439 pwszName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
442 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
443 ERR("HeapAlloc failed!\n");
447 MultiByteToWideChar(CP_ACP
, 0, Name
, -1, pwszName
, cch
+ 1);
450 /* Ref: https://stackoverflow.com/questions/41147180/why-enumprintersa-and-enumprintersw-request-the-same-amount-of-memory */
451 bReturnValue
= EnumPrintersW(Flags
, pwszName
, Level
, pPrinterEnum
, cbBuf
, pcbNeeded
, pcReturned
);
452 HeapFree(hProcessHeap
, 0, pwszName
);
454 TRACE("*pcReturned is '%d' and bReturnValue is '%d' and GetLastError is '%ld'.\n", *pcReturned
, bReturnValue
, GetLastError());
456 /* We are mapping multiple different pointers to the same pPrinterEnum pointer here so that */
457 /* we can do in-place conversion. We read the Unicode response from the EnumPrintersW and */
458 /* then we write back the ANSI conversion into the same buffer for our EnumPrintersA output */
460 /* mapping to pPrinterEnum for Unicode (w) characters for Levels 1, 2, 4, and 5 */
461 ppi1w
= (PPRINTER_INFO_1W
)pPrinterEnum
;
462 ppi2w
= (PPRINTER_INFO_2W
)pPrinterEnum
;
463 ppi4w
= (PPRINTER_INFO_4W
)pPrinterEnum
;
464 ppi5w
= (PPRINTER_INFO_5W
)pPrinterEnum
;
465 /* mapping to pPrinterEnum for ANSI (a) characters for Levels 1, 2, 4, and 5 */
466 ppi1a
= (PPRINTER_INFO_1A
)pPrinterEnum
;
467 ppi2a
= (PPRINTER_INFO_2A
)pPrinterEnum
;
468 ppi4a
= (PPRINTER_INFO_4A
)pPrinterEnum
;
469 ppi5a
= (PPRINTER_INFO_5A
)pPrinterEnum
;
471 for (i
= 0; i
< *pcReturned
; i
++)
477 if (ppi1w
[i
].pDescription
)
479 // Convert Unicode pDescription to a ANSI string pszDescription.
480 cch
= wcslen(ppi1w
[i
].pDescription
);
482 pszDescription
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
485 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
486 ERR("HeapAlloc failed!\n");
490 WideCharToMultiByte(CP_ACP
, 0, ppi1w
[i
].pDescription
, -1, pszDescription
, cch
+ 1, NULL
, NULL
);
491 StringCchCopyA(ppi1a
[i
].pDescription
, cch
+ 1, pszDescription
);
493 HeapFree(hProcessHeap
, 0, pszDescription
);
498 // Convert Unicode pName to a ANSI string pszName.
499 cch
= wcslen(ppi1w
[i
].pName
);
501 pszName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
504 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
505 ERR("HeapAlloc failed!\n");
509 WideCharToMultiByte(CP_ACP
, 0, ppi1w
[i
].pName
, -1, pszName
, cch
+ 1, NULL
, NULL
);
510 StringCchCopyA(ppi1a
[i
].pName
, cch
+ 1, pszName
);
512 HeapFree(hProcessHeap
, 0, pszName
);
515 if (ppi1w
[i
].pComment
)
517 // Convert Unicode pComment to a ANSI string pszComment.
518 cch
= wcslen(ppi1w
[i
].pComment
);
520 pszComment
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
523 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
524 ERR("HeapAlloc failed!\n");
528 WideCharToMultiByte(CP_ACP
, 0, ppi1w
[i
].pComment
, -1, pszComment
, cch
+ 1, NULL
, NULL
);
529 StringCchCopyA(ppi1a
[i
].pComment
, cch
+ 1, pszComment
);
531 HeapFree(hProcessHeap
, 0, pszComment
);
539 if (ppi2w
[i
].pServerName
)
541 // Convert Unicode pServerName to a ANSI string pszServerName.
542 cch
= wcslen(ppi2w
[i
].pServerName
);
544 pszServerName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
547 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
548 ERR("HeapAlloc failed!\n");
552 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pServerName
, -1, pszServerName
, cch
+ 1, NULL
, NULL
);
553 StringCchCopyA(ppi2a
[i
].pServerName
, cch
+ 1, pszServerName
);
555 HeapFree(hProcessHeap
, 0, pszServerName
);
558 if (ppi2w
[i
].pPrinterName
)
560 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
561 cch
= wcslen(ppi2w
[i
].pPrinterName
);
563 pszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
566 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
567 ERR("HeapAlloc failed!\n");
571 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pPrinterName
, -1, pszPrinterName
, cch
+ 1, NULL
, NULL
);
572 StringCchCopyA(ppi2a
[i
].pPrinterName
, cch
+ 1, pszPrinterName
);
574 HeapFree(hProcessHeap
, 0, pszPrinterName
);
577 if (ppi2w
[i
].pShareName
)
579 // Convert Unicode pShareName to a ANSI string pszShareName.
580 cch
= wcslen(ppi2w
[i
].pShareName
);
582 pszShareName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
585 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
586 ERR("HeapAlloc failed!\n");
590 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pShareName
, -1, pszShareName
, cch
+ 1, NULL
, NULL
);
591 StringCchCopyA(ppi2a
[i
].pShareName
, cch
+ 1, pszShareName
);
593 HeapFree(hProcessHeap
, 0, pszShareName
);
596 if (ppi2w
[i
].pPortName
)
598 // Convert Unicode pPortName to a ANSI string pszPortName.
599 cch
= wcslen(ppi2w
[i
].pPortName
);
601 pszPortName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
604 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
605 ERR("HeapAlloc failed!\n");
609 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pPortName
, -1, pszPortName
, cch
+ 1, NULL
, NULL
);
610 StringCchCopyA(ppi2a
[i
].pPortName
, cch
+ 1, pszPortName
);
612 HeapFree(hProcessHeap
, 0, pszPortName
);
615 if (ppi2w
[i
].pDriverName
)
617 // Convert Unicode pDriverName to a ANSI string pszDriverName.
618 cch
= wcslen(ppi2w
[i
].pDriverName
);
620 pszDriverName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
623 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
624 ERR("HeapAlloc failed!\n");
628 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pDriverName
, -1, pszDriverName
, cch
+ 1, NULL
, NULL
);
629 StringCchCopyA(ppi2a
[i
].pDriverName
, cch
+ 1, pszDriverName
);
631 HeapFree(hProcessHeap
, 0, pszDriverName
);
634 if (ppi2w
[i
].pComment
)
636 // Convert Unicode pComment to a ANSI string pszComment.
637 cch
= wcslen(ppi2w
[i
].pComment
);
639 pszComment
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
642 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
643 ERR("HeapAlloc failed!\n");
647 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pComment
, -1, pszComment
, cch
+ 1, NULL
, NULL
);
648 StringCchCopyA(ppi2a
[i
].pComment
, cch
+ 1, pszComment
);
650 HeapFree(hProcessHeap
, 0, pszComment
);
653 if (ppi2w
[i
].pLocation
)
655 // Convert Unicode pLocation to a ANSI string pszLocation.
656 cch
= wcslen(ppi2w
[i
].pLocation
);
658 pszLocation
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
661 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
662 ERR("HeapAlloc failed!\n");
666 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pLocation
, -1, pszLocation
, cch
+ 1, NULL
, NULL
);
667 StringCchCopyA(ppi2a
[i
].pLocation
, cch
+ 1, pszLocation
);
669 HeapFree(hProcessHeap
, 0, pszLocation
);
673 if (ppi2w
[i
].pSepFile
)
675 // Convert Unicode pSepFile to a ANSI string pszSepFile.
676 cch
= wcslen(ppi2w
[i
].pSepFile
);
678 pszSepFile
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
681 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
682 ERR("HeapAlloc failed!\n");
686 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pSepFile
, -1, pszSepFile
, cch
+ 1, NULL
, NULL
);
687 StringCchCopyA(ppi2a
[i
].pSepFile
, cch
+ 1, pszSepFile
);
689 HeapFree(hProcessHeap
, 0, pszSepFile
);
692 if (ppi2w
[i
].pPrintProcessor
)
694 // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor.
695 cch
= wcslen(ppi2w
[i
].pPrintProcessor
);
697 pszPrintProcessor
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
698 if (!pszPrintProcessor
)
700 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
701 ERR("HeapAlloc failed!\n");
705 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pPrintProcessor
, -1, pszPrintProcessor
, cch
+ 1, NULL
, NULL
);
706 StringCchCopyA(ppi2a
[i
].pPrintProcessor
, cch
+ 1, pszPrintProcessor
);
708 HeapFree(hProcessHeap
, 0, pszPrintProcessor
);
712 if (ppi2w
[i
].pDatatype
)
714 // Convert Unicode pDatatype to a ANSI string pszDatatype.
715 cch
= wcslen(ppi2w
[i
].pDatatype
);
717 pszDatatype
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
720 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
721 ERR("HeapAlloc failed!\n");
725 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pDatatype
, -1, pszDatatype
, cch
+ 1, NULL
, NULL
);
726 StringCchCopyA(ppi2a
[i
].pDatatype
, cch
+ 1, pszDatatype
);
728 HeapFree(hProcessHeap
, 0, pszDatatype
);
731 if (ppi2w
[i
].pParameters
)
733 // Convert Unicode pParameters to a ANSI string pszParameters.
734 cch
= wcslen(ppi2w
[i
].pParameters
);
736 pszParameters
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
739 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
740 ERR("HeapAlloc failed!\n");
744 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pParameters
, -1, pszParameters
, cch
+ 1, NULL
, NULL
);
745 StringCchCopyA(ppi2a
[i
].pParameters
, cch
+ 1, pszParameters
);
747 HeapFree(hProcessHeap
, 0, pszParameters
);
755 if (ppi4w
[i
].pPrinterName
)
757 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
758 cch
= wcslen(ppi4w
[i
].pPrinterName
);
760 pszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
763 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
764 ERR("HeapAlloc failed!\n");
768 WideCharToMultiByte(CP_ACP
, 0, ppi4w
[i
].pPrinterName
, -1, pszPrinterName
, cch
+ 1, NULL
, NULL
);
769 StringCchCopyA(ppi4a
[i
].pPrinterName
, cch
+ 1, pszPrinterName
);
771 HeapFree(hProcessHeap
, 0, pszPrinterName
);
774 if (ppi4w
[i
].pServerName
)
776 // Convert Unicode pServerName to a ANSI string pszServerName.
777 cch
= wcslen(ppi4w
[i
].pServerName
);
779 pszServerName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
782 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
783 ERR("HeapAlloc failed!\n");
787 WideCharToMultiByte(CP_ACP
, 0, ppi4w
[i
].pServerName
, -1, pszServerName
, cch
+ 1, NULL
, NULL
);
788 StringCchCopyA(ppi4a
[i
].pServerName
, cch
+ 1, pszServerName
);
790 HeapFree(hProcessHeap
, 0, pszServerName
);
797 if (ppi5w
[i
].pPrinterName
)
799 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
800 cch
= wcslen(ppi5w
[i
].pPrinterName
);
802 pszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
805 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
806 ERR("HeapAlloc failed!\n");
810 WideCharToMultiByte(CP_ACP
, 0, ppi5w
[i
].pPrinterName
, -1, pszPrinterName
, cch
+ 1, NULL
, NULL
);
811 StringCchCopyA(ppi5a
[i
].pPrinterName
, cch
+ 1, pszPrinterName
);
813 HeapFree(hProcessHeap
, 0, pszPrinterName
);
816 if (ppi5w
[i
].pPortName
)
818 // Convert Unicode pPortName to a ANSI string pszPortName.
819 cch
= wcslen(ppi5w
[i
].pPortName
);
821 pszPortName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
824 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
825 ERR("HeapAlloc failed!\n");
829 WideCharToMultiByte(CP_ACP
, 0, ppi5w
[i
].pPortName
, -1, pszPortName
, cch
+ 1, NULL
, NULL
);
830 StringCchCopyA(ppi5a
[i
].pPortName
, cch
+ 1, pszPortName
);
832 HeapFree(hProcessHeap
, 0, pszPortName
);
846 EnumPrintersW(DWORD Flags
, PWSTR Name
, DWORD Level
, PBYTE pPrinterEnum
, DWORD cbBuf
, PDWORD pcbNeeded
, PDWORD pcReturned
)
850 TRACE("EnumPrintersW(%lu, %S, %lu, %p, %lu, %p, %p)\n", Flags
, Name
, Level
, pPrinterEnum
, cbBuf
, pcbNeeded
, pcReturned
);
852 // Dismiss invalid levels already at this point.
853 if (Level
== 3 || Level
> 5)
855 dwErrorCode
= ERROR_INVALID_LEVEL
;
859 if (cbBuf
&& pPrinterEnum
)
860 ZeroMemory(pPrinterEnum
, cbBuf
);
865 dwErrorCode
= _RpcEnumPrinters(Flags
, Name
, Level
, pPrinterEnum
, cbBuf
, pcbNeeded
, pcReturned
);
867 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
869 dwErrorCode
= RpcExceptionCode();
870 ERR("_RpcEnumPrinters failed with exception code %lu!\n", dwErrorCode
);
874 if (dwErrorCode
== ERROR_SUCCESS
)
876 // Replace relative offset addresses in the output by absolute pointers.
878 MarshallUpStructuresArray(cbBuf
, pPrinterEnum
, *pcReturned
, pPrinterInfoMarshalling
[Level
]->pInfo
, pPrinterInfoMarshalling
[Level
]->cbStructureSize
, TRUE
);
882 SetLastError(dwErrorCode
);
883 return (dwErrorCode
== ERROR_SUCCESS
);
887 FlushPrinter(HANDLE hPrinter
, PVOID pBuf
, DWORD cbBuf
, PDWORD pcWritten
, DWORD cSleep
)
889 TRACE("FlushPrinter(%p, %p, %lu, %p, %lu)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
, cSleep
);
895 GetDefaultPrinterA(LPSTR pszBuffer
, LPDWORD pcchBuffer
)
898 PWSTR pwszBuffer
= NULL
;
900 TRACE("GetDefaultPrinterA(%p, %p)\n", pszBuffer
, pcchBuffer
);
905 dwErrorCode
= ERROR_INVALID_PARAMETER
;
909 // Check if an ANSI buffer was given and if so, allocate a Unicode buffer of the same size.
910 if (pszBuffer
&& *pcchBuffer
)
912 pwszBuffer
= HeapAlloc(hProcessHeap
, 0, *pcchBuffer
* sizeof(WCHAR
));
915 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
916 ERR("HeapAlloc failed!\n");
921 if (!GetDefaultPrinterW(pwszBuffer
, pcchBuffer
))
923 dwErrorCode
= GetLastError();
927 // We successfully got a string in pwszBuffer, so convert the Unicode string to ANSI.
928 WideCharToMultiByte(CP_ACP
, 0, pwszBuffer
, -1, pszBuffer
, *pcchBuffer
, NULL
, NULL
);
930 dwErrorCode
= ERROR_SUCCESS
;
934 HeapFree(hProcessHeap
, 0, pwszBuffer
);
936 SetLastError(dwErrorCode
);
937 return (dwErrorCode
== ERROR_SUCCESS
);
941 GetDefaultPrinterW(LPWSTR pszBuffer
, LPDWORD pcchBuffer
)
944 DWORD cchInputBuffer
;
946 HKEY hWindowsKey
= NULL
;
947 PWSTR pwszDevice
= NULL
;
950 TRACE("GetDefaultPrinterW(%p, %p)\n", pszBuffer
, pcchBuffer
);
955 dwErrorCode
= ERROR_INVALID_PARAMETER
;
959 cchInputBuffer
= *pcchBuffer
;
961 // Open the registry key where the default printer for the current user is stored.
962 dwErrorCode
= (DWORD
)RegOpenKeyExW(HKEY_CURRENT_USER
, wszWindowsKey
, 0, KEY_READ
, &hWindowsKey
);
963 if (dwErrorCode
!= ERROR_SUCCESS
)
965 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode
);
969 // Determine the size of the required buffer.
970 dwErrorCode
= (DWORD
)RegQueryValueExW(hWindowsKey
, wszDeviceValue
, NULL
, NULL
, NULL
, &cbNeeded
);
971 if (dwErrorCode
!= ERROR_SUCCESS
)
973 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode
);
978 pwszDevice
= HeapAlloc(hProcessHeap
, 0, cbNeeded
);
981 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
982 ERR("HeapAlloc failed!\n");
986 // Now get the actual value.
987 dwErrorCode
= RegQueryValueExW(hWindowsKey
, wszDeviceValue
, NULL
, NULL
, (PBYTE
)pwszDevice
, &cbNeeded
);
988 if (dwErrorCode
!= ERROR_SUCCESS
)
990 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode
);
994 // We get a string "<Printer Name>,winspool,<Port>:".
995 // Extract the printer name from it.
996 pwszComma
= wcschr(pwszDevice
, L
',');
999 ERR("Found no or invalid default printer: %S!\n", pwszDevice
);
1000 dwErrorCode
= ERROR_INVALID_NAME
;
1004 // Store the length of the Printer Name (including the terminating NUL character!) in *pcchBuffer.
1005 *pcchBuffer
= pwszComma
- pwszDevice
+ 1;
1007 // Check if the supplied buffer is large enough.
1008 if (cchInputBuffer
< *pcchBuffer
)
1010 dwErrorCode
= ERROR_INSUFFICIENT_BUFFER
;
1014 // Copy the default printer.
1016 CopyMemory(pszBuffer
, pwszDevice
, *pcchBuffer
* sizeof(WCHAR
));
1018 dwErrorCode
= ERROR_SUCCESS
;
1022 RegCloseKey(hWindowsKey
);
1025 HeapFree(hProcessHeap
, 0, pwszDevice
);
1027 SetLastError(dwErrorCode
);
1028 return (dwErrorCode
== ERROR_SUCCESS
);
1032 GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1034 PPRINTER_INFO_1A ppi1a
= (PPRINTER_INFO_1A
)pPrinter
;
1035 PPRINTER_INFO_1W ppi1w
= (PPRINTER_INFO_1W
)pPrinter
;
1036 PPRINTER_INFO_2A ppi2a
= (PPRINTER_INFO_2A
)pPrinter
;
1037 PPRINTER_INFO_2W ppi2w
= (PPRINTER_INFO_2W
)pPrinter
;
1038 PPRINTER_INFO_4A ppi4a
= (PPRINTER_INFO_4A
)pPrinter
;
1039 PPRINTER_INFO_4W ppi4w
= (PPRINTER_INFO_4W
)pPrinter
;
1040 PPRINTER_INFO_5A ppi5a
= (PPRINTER_INFO_5A
)pPrinter
;
1041 PPRINTER_INFO_5W ppi5w
= (PPRINTER_INFO_5W
)pPrinter
;
1042 PPRINTER_INFO_7A ppi7a
= (PPRINTER_INFO_7A
)pPrinter
;
1043 PPRINTER_INFO_7W ppi7w
= (PPRINTER_INFO_7W
)pPrinter
;
1045 BOOL bReturnValue
= FALSE
;
1047 TRACE("GetPrinterA(%p, %lu, %p, %lu, %p)\n", hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
);
1049 // Check for invalid levels here for early error return. Should be 1-9.
1050 if (Level
< 1 || Level
> 9)
1052 SetLastError(ERROR_INVALID_LEVEL
);
1053 ERR("Invalid Level!\n");
1057 bReturnValue
= GetPrinterW(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
);
1061 TRACE("GetPrinterW failed!\n");
1069 if (ppi1w
->pDescription
)
1071 PSTR pszDescription
;
1073 // Convert Unicode pDescription to a ANSI string pszDescription.
1074 cch
= wcslen(ppi1w
->pDescription
);
1076 pszDescription
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1077 if (!pszDescription
)
1079 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1080 ERR("HeapAlloc failed!\n");
1084 WideCharToMultiByte(CP_ACP
, 0, ppi1w
->pDescription
, -1, pszDescription
, cch
+ 1, NULL
, NULL
);
1085 StringCchCopyA(ppi1a
->pDescription
, cch
+ 1, pszDescription
);
1087 HeapFree(hProcessHeap
, 0, pszDescription
);
1094 // Convert Unicode pName to a ANSI string pszName.
1095 cch
= wcslen(ppi1w
->pName
);
1097 pszName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1100 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1101 ERR("HeapAlloc failed!\n");
1105 WideCharToMultiByte(CP_ACP
, 0, ppi1w
->pName
, -1, pszName
, cch
+ 1, NULL
, NULL
);
1106 StringCchCopyA(ppi1a
->pName
, cch
+ 1, pszName
);
1108 HeapFree(hProcessHeap
, 0, pszName
);
1111 if (ppi1w
->pComment
)
1115 // Convert Unicode pComment to a ANSI string pszComment.
1116 cch
= wcslen(ppi1w
->pComment
);
1118 pszComment
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1121 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1122 ERR("HeapAlloc failed!\n");
1126 WideCharToMultiByte(CP_ACP
, 0, ppi1w
->pComment
, -1, pszComment
, cch
+ 1, NULL
, NULL
);
1127 StringCchCopyA(ppi1a
->pComment
, cch
+ 1, pszComment
);
1129 HeapFree(hProcessHeap
, 0, pszComment
);
1136 if (ppi2w
->pServerName
)
1140 // Convert Unicode pServerName to a ANSI string pszServerName.
1141 cch
= wcslen(ppi2w
->pServerName
);
1143 pszServerName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1146 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1147 ERR("HeapAlloc failed!\n");
1151 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pServerName
, -1, pszServerName
, cch
+ 1, NULL
, NULL
);
1152 StringCchCopyA(ppi2a
->pServerName
, cch
+ 1, pszServerName
);
1154 HeapFree(hProcessHeap
, 0, pszServerName
);
1157 if (ppi2w
->pPrinterName
)
1159 PSTR pszPrinterName
;
1161 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
1162 cch
= wcslen(ppi2w
->pPrinterName
);
1164 pszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1165 if (!pszPrinterName
)
1167 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1168 ERR("HeapAlloc failed!\n");
1172 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pPrinterName
, -1, pszPrinterName
, cch
+ 1, NULL
, NULL
);
1173 StringCchCopyA(ppi2a
->pPrinterName
, cch
+ 1, pszPrinterName
);
1175 HeapFree(hProcessHeap
, 0, pszPrinterName
);
1178 if (ppi2w
->pShareName
)
1182 // Convert Unicode pShareName to a ANSI string pszShareName.
1183 cch
= wcslen(ppi2w
->pShareName
);
1185 pszShareName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1188 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1189 ERR("HeapAlloc failed!\n");
1193 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pShareName
, -1, pszShareName
, cch
+ 1, NULL
, NULL
);
1194 StringCchCopyA(ppi2a
->pShareName
, cch
+ 1, pszShareName
);
1196 HeapFree(hProcessHeap
, 0, pszShareName
);
1199 if (ppi2w
->pPortName
)
1203 // Convert Unicode pPortName to a ANSI string pszPortName.
1204 cch
= wcslen(ppi2w
->pPortName
);
1206 pszPortName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1209 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1210 ERR("HeapAlloc failed!\n");
1214 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pPortName
, -1, pszPortName
, cch
+ 1, NULL
, NULL
);
1215 StringCchCopyA(ppi2a
->pPortName
, cch
+ 1, pszPortName
);
1217 HeapFree(hProcessHeap
, 0, pszPortName
);
1220 if (ppi2w
->pDriverName
)
1224 // Convert Unicode pDriverName to a ANSI string pszDriverName.
1225 cch
= wcslen(ppi2w
->pDriverName
);
1227 pszDriverName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1230 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1231 ERR("HeapAlloc failed!\n");
1235 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pDriverName
, -1, pszDriverName
, cch
+ 1, NULL
, NULL
);
1236 StringCchCopyA(ppi2a
->pDriverName
, cch
+ 1, pszDriverName
);
1238 HeapFree(hProcessHeap
, 0, pszDriverName
);
1241 if (ppi2w
->pComment
)
1245 // Convert Unicode pComment to a ANSI string pszComment.
1246 cch
= wcslen(ppi2w
->pComment
);
1248 pszComment
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1251 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1252 ERR("HeapAlloc failed!\n");
1256 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pComment
, -1, pszComment
, cch
+ 1, NULL
, NULL
);
1257 StringCchCopyA(ppi2a
->pComment
, cch
+ 1, pszComment
);
1259 HeapFree(hProcessHeap
, 0, pszComment
);
1262 if (ppi2w
->pLocation
)
1266 // Convert Unicode pLocation to a ANSI string pszLocation.
1267 cch
= wcslen(ppi2w
->pLocation
);
1269 pszLocation
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1272 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1273 ERR("HeapAlloc failed!\n");
1277 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pLocation
, -1, pszLocation
, cch
+ 1, NULL
, NULL
);
1278 StringCchCopyA(ppi2a
->pLocation
, cch
+ 1, pszLocation
);
1280 HeapFree(hProcessHeap
, 0, pszLocation
);
1283 if (ppi2w
->pSepFile
)
1287 // Convert Unicode pSepFile to a ANSI string pszSepFile.
1288 cch
= wcslen(ppi2w
->pSepFile
);
1290 pszSepFile
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1293 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1294 ERR("HeapAlloc failed!\n");
1298 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pSepFile
, -1, pszSepFile
, cch
+ 1, NULL
, NULL
);
1299 StringCchCopyA(ppi2a
->pSepFile
, cch
+ 1, pszSepFile
);
1301 HeapFree(hProcessHeap
, 0, pszSepFile
);
1304 if (ppi2w
->pPrintProcessor
)
1306 PSTR pszPrintProcessor
;
1308 // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor.
1309 cch
= wcslen(ppi2w
->pPrintProcessor
);
1311 pszPrintProcessor
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1312 if (!pszPrintProcessor
)
1314 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1315 ERR("HeapAlloc failed!\n");
1319 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pPrintProcessor
, -1, pszPrintProcessor
, cch
+ 1, NULL
, NULL
);
1320 StringCchCopyA(ppi2a
->pPrintProcessor
, cch
+ 1, pszPrintProcessor
);
1322 HeapFree(hProcessHeap
, 0, pszPrintProcessor
);
1325 if (ppi2w
->pDatatype
)
1329 // Convert Unicode pDatatype to a ANSI string pszDatatype.
1330 cch
= wcslen(ppi2w
->pDatatype
);
1332 pszDatatype
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1335 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1336 ERR("HeapAlloc failed!\n");
1340 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pDatatype
, -1, pszDatatype
, cch
+ 1, NULL
, NULL
);
1341 StringCchCopyA(ppi2a
->pDatatype
, cch
+ 1, pszDatatype
);
1343 HeapFree(hProcessHeap
, 0, pszDatatype
);
1346 if (ppi2w
->pParameters
)
1350 // Convert Unicode pParameters to a ANSI string pszParameters.
1351 cch
= wcslen(ppi2w
->pParameters
);
1353 pszParameters
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1356 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1357 ERR("HeapAlloc failed!\n");
1361 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pParameters
, -1, pszParameters
, cch
+ 1, NULL
, NULL
);
1362 StringCchCopyA(ppi2a
->pParameters
, cch
+ 1, pszParameters
);
1364 HeapFree(hProcessHeap
, 0, pszParameters
);
1371 if (ppi4w
->pPrinterName
)
1373 PSTR pszPrinterName
;
1375 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
1376 cch
= wcslen(ppi4w
->pPrinterName
);
1378 pszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1379 if (!pszPrinterName
)
1381 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1382 ERR("HeapAlloc failed!\n");
1386 WideCharToMultiByte(CP_ACP
, 0, ppi4w
->pPrinterName
, -1, pszPrinterName
, cch
+ 1, NULL
, NULL
);
1387 StringCchCopyA(ppi4a
->pPrinterName
, cch
+ 1, pszPrinterName
);
1389 HeapFree(hProcessHeap
, 0, pszPrinterName
);
1392 if (ppi4w
->pServerName
)
1396 // Convert Unicode pServerName to a ANSI string pszServerName.
1397 cch
= wcslen(ppi4w
->pServerName
);
1399 pszServerName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1402 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1403 ERR("HeapAlloc failed!\n");
1407 WideCharToMultiByte(CP_ACP
, 0, ppi4w
->pServerName
, -1, pszServerName
, cch
+ 1, NULL
, NULL
);
1408 StringCchCopyA(ppi4a
->pServerName
, cch
+ 1, pszServerName
);
1410 HeapFree(hProcessHeap
, 0, pszServerName
);
1417 if (ppi5w
->pPrinterName
)
1419 PSTR pszPrinterName
;
1421 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
1422 cch
= wcslen(ppi5w
->pPrinterName
);
1424 pszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1425 if (!pszPrinterName
)
1427 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1428 ERR("HeapAlloc failed!\n");
1432 WideCharToMultiByte(CP_ACP
, 0, ppi5w
->pPrinterName
, -1, pszPrinterName
, cch
+ 1, NULL
, NULL
);
1433 StringCchCopyA(ppi5a
->pPrinterName
, cch
+ 1, pszPrinterName
);
1435 HeapFree(hProcessHeap
, 0, pszPrinterName
);
1438 if (ppi5w
->pPortName
)
1442 // Convert Unicode pPortName to a ANSI string pszPortName.
1443 cch
= wcslen(ppi5w
->pPortName
);
1445 pszPortName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1448 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1449 ERR("HeapAlloc failed!\n");
1453 WideCharToMultiByte(CP_ACP
, 0, ppi5w
->pPortName
, -1, pszPortName
, cch
+ 1, NULL
, NULL
);
1454 StringCchCopyA(ppi5a
->pPortName
, cch
+ 1, pszPortName
);
1456 HeapFree(hProcessHeap
, 0, pszPortName
);
1463 if (ppi7w
->pszObjectGUID
)
1465 PSTR pszaObjectGUID
;
1467 // Convert Unicode pszObjectGUID to a ANSI string pszaObjectGUID.
1468 cch
= wcslen(ppi7w
->pszObjectGUID
);
1470 pszaObjectGUID
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1471 if (!pszaObjectGUID
)
1473 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1474 ERR("HeapAlloc failed!\n");
1478 WideCharToMultiByte(CP_ACP
, 0, ppi7w
->pszObjectGUID
, -1, pszaObjectGUID
, cch
+ 1, NULL
, NULL
);
1479 StringCchCopyA(ppi7a
->pszObjectGUID
, cch
+ 1, pszaObjectGUID
);
1481 HeapFree(hProcessHeap
, 0, pszaObjectGUID
);
1488 return bReturnValue
;
1492 GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
, DWORD Level
, LPBYTE pDriverInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1494 ERR("GetPrinterDriverA(%p, %s, %lu, %p, %lu, %p)\n", hPrinter
, pEnvironment
, Level
, pDriverInfo
, cbBuf
, pcbNeeded
);
1495 if (pcbNeeded
) *pcbNeeded
= 0;
1500 GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
, DWORD Level
, LPBYTE pDriverInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1503 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
1505 TRACE("GetPrinterDriverW(%p, %S, %lu, %p, %lu, %p)\n", hPrinter
, pEnvironment
, Level
, pDriverInfo
, cbBuf
, pcbNeeded
);
1510 dwErrorCode
= ERROR_INVALID_HANDLE
;
1514 // Dismiss invalid levels already at this point.
1515 if (Level
> 8 || Level
< 1)
1517 dwErrorCode
= ERROR_INVALID_LEVEL
;
1521 if (cbBuf
&& pDriverInfo
)
1522 ZeroMemory(pDriverInfo
, cbBuf
);
1527 dwErrorCode
= _RpcGetPrinterDriver(pHandle
->hPrinter
, pEnvironment
, Level
, pDriverInfo
, cbBuf
, pcbNeeded
);
1529 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
1531 dwErrorCode
= RpcExceptionCode();
1532 ERR("_RpcGetPrinterDriver failed with exception code %lu!\n", dwErrorCode
);
1536 if (dwErrorCode
== ERROR_SUCCESS
)
1538 // Replace relative offset addresses in the output by absolute pointers.
1540 MarshallUpStructure(cbBuf
, pDriverInfo
, pPrinterDriverMarshalling
[Level
]->pInfo
, pPrinterDriverMarshalling
[Level
]->cbStructureSize
, TRUE
);
1544 SetLastError(dwErrorCode
);
1545 return (dwErrorCode
== ERROR_SUCCESS
);
1549 GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1552 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
1554 TRACE("GetPrinterW(%p, %lu, %p, %lu, %p)\n", hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
);
1559 dwErrorCode
= ERROR_INVALID_HANDLE
;
1563 // Dismiss invalid levels already at this point.
1566 dwErrorCode
= ERROR_INVALID_LEVEL
;
1570 if (cbBuf
&& pPrinter
)
1571 ZeroMemory(pPrinter
, cbBuf
);
1576 dwErrorCode
= _RpcGetPrinter(pHandle
->hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
);
1578 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
1580 dwErrorCode
= RpcExceptionCode();
1581 ERR("_RpcGetPrinter failed with exception code %lu!\n", dwErrorCode
);
1585 if (dwErrorCode
== ERROR_SUCCESS
)
1587 // Replace relative offset addresses in the output by absolute pointers.
1589 MarshallUpStructure(cbBuf
, pPrinter
, pPrinterInfoMarshalling
[Level
]->pInfo
, pPrinterInfoMarshalling
[Level
]->cbStructureSize
, TRUE
);
1593 SetLastError(dwErrorCode
);
1594 return (dwErrorCode
== ERROR_SUCCESS
);
1598 OpenPrinterA(LPSTR pPrinterName
, LPHANDLE phPrinter
, LPPRINTER_DEFAULTSA pDefault
)
1600 BOOL bReturnValue
= FALSE
;
1602 PWSTR pwszPrinterName
= NULL
;
1603 PRINTER_DEFAULTSW wDefault
= { 0 };
1605 TRACE("OpenPrinterA(%s, %p, %p)\n", pPrinterName
, phPrinter
, pDefault
);
1609 // Convert pPrinterName to a Unicode string pwszPrinterName
1610 cch
= strlen(pPrinterName
);
1612 pwszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
1613 if (!pwszPrinterName
)
1615 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1616 ERR("HeapAlloc failed!\n");
1620 MultiByteToWideChar(CP_ACP
, 0, pPrinterName
, -1, pwszPrinterName
, cch
+ 1);
1625 wDefault
.DesiredAccess
= pDefault
->DesiredAccess
;
1627 if (pDefault
->pDatatype
)
1629 // Convert pDefault->pDatatype to a Unicode string wDefault.pDatatype
1630 cch
= strlen(pDefault
->pDatatype
);
1632 wDefault
.pDatatype
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
1633 if (!wDefault
.pDatatype
)
1635 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1636 ERR("HeapAlloc failed!\n");
1640 MultiByteToWideChar(CP_ACP
, 0, pDefault
->pDatatype
, -1, wDefault
.pDatatype
, cch
+ 1);
1643 if (pDefault
->pDevMode
)
1644 wDefault
.pDevMode
= GdiConvertToDevmodeW(pDefault
->pDevMode
);
1647 bReturnValue
= OpenPrinterW(pwszPrinterName
, phPrinter
, &wDefault
);
1650 if (wDefault
.pDatatype
)
1651 HeapFree(hProcessHeap
, 0, wDefault
.pDatatype
);
1653 if (wDefault
.pDevMode
)
1654 HeapFree(hProcessHeap
, 0, wDefault
.pDevMode
);
1656 if (pwszPrinterName
)
1657 HeapFree(hProcessHeap
, 0, pwszPrinterName
);
1659 return bReturnValue
;
1663 OpenPrinterW(LPWSTR pPrinterName
, LPHANDLE phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
1667 PSPOOLER_HANDLE pHandle
;
1668 PWSTR pDatatype
= NULL
;
1669 WINSPOOL_DEVMODE_CONTAINER DevModeContainer
= { 0 };
1670 ACCESS_MASK AccessRequired
= 0;
1672 TRACE("OpenPrinterW(%S, %p, %p)\n", pPrinterName
, phPrinter
, pDefault
);
1677 dwErrorCode
= ERROR_INVALID_PARAMETER
;
1681 // Prepare the additional parameters in the format required by _RpcOpenPrinter
1684 pDatatype
= pDefault
->pDatatype
;
1685 DevModeContainer
.cbBuf
= sizeof(DEVMODEW
);
1686 DevModeContainer
.pDevMode
= (BYTE
*)pDefault
->pDevMode
;
1687 AccessRequired
= pDefault
->DesiredAccess
;
1693 dwErrorCode
= _RpcOpenPrinter(pPrinterName
, &hPrinter
, pDatatype
, &DevModeContainer
, AccessRequired
);
1695 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
1697 dwErrorCode
= RpcExceptionCode();
1698 ERR("_RpcOpenPrinter failed with exception code %lu!\n", dwErrorCode
);
1702 if (dwErrorCode
== ERROR_SUCCESS
)
1704 // Create a new SPOOLER_HANDLE structure.
1705 pHandle
= HeapAlloc(hProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(SPOOLER_HANDLE
));
1708 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1709 ERR("HeapAlloc failed!\n");
1713 pHandle
->hPrinter
= hPrinter
;
1714 pHandle
->hSPLFile
= INVALID_HANDLE_VALUE
;
1716 // Return it as phPrinter.
1717 *phPrinter
= (HANDLE
)pHandle
;
1721 SetLastError(dwErrorCode
);
1722 return (dwErrorCode
== ERROR_SUCCESS
);
1726 ReadPrinter(HANDLE hPrinter
, PVOID pBuf
, DWORD cbBuf
, PDWORD pNoBytesRead
)
1729 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
1731 TRACE("ReadPrinter(%p, %p, %lu, %p)\n", hPrinter
, pBuf
, cbBuf
, pNoBytesRead
);
1736 dwErrorCode
= ERROR_INVALID_HANDLE
;
1743 dwErrorCode
= _RpcReadPrinter(pHandle
->hPrinter
, pBuf
, cbBuf
, pNoBytesRead
);
1745 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
1747 dwErrorCode
= RpcExceptionCode();
1748 ERR("_RpcReadPrinter failed with exception code %lu!\n", dwErrorCode
);
1753 SetLastError(dwErrorCode
);
1754 return (dwErrorCode
== ERROR_SUCCESS
);
1758 ResetPrinterA(HANDLE hPrinter
, PPRINTER_DEFAULTSA pDefault
)
1760 TRACE("ResetPrinterA(%p, %p)\n", hPrinter
, pDefault
);
1766 ResetPrinterW(HANDLE hPrinter
, PPRINTER_DEFAULTSW pDefault
)
1768 TRACE("ResetPrinterW(%p, %p)\n", hPrinter
, pDefault
);
1774 SetDefaultPrinterA(LPCSTR pszPrinter
)
1776 BOOL bReturnValue
= FALSE
;
1778 PWSTR pwszPrinter
= NULL
;
1780 TRACE("SetDefaultPrinterA(%s)\n", pszPrinter
);
1784 // Convert pszPrinter to a Unicode string pwszPrinter
1785 cch
= strlen(pszPrinter
);
1787 pwszPrinter
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
1790 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1791 ERR("HeapAlloc failed!\n");
1795 MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, pwszPrinter
, cch
+ 1);
1798 bReturnValue
= SetDefaultPrinterW(pwszPrinter
);
1802 HeapFree(hProcessHeap
, 0, pwszPrinter
);
1804 return bReturnValue
;
1808 SetDefaultPrinterW(LPCWSTR pszPrinter
)
1810 const WCHAR wszDevicesKey
[] = L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Devices";
1812 DWORD cbDeviceValueData
;
1813 DWORD cbPrinterValueData
= 0;
1816 HKEY hDevicesKey
= NULL
;
1817 HKEY hWindowsKey
= NULL
;
1818 PWSTR pwszDeviceValueData
= NULL
;
1819 WCHAR wszPrinter
[MAX_PRINTER_NAME
+ 1];
1821 TRACE("SetDefaultPrinterW(%S)\n", pszPrinter
);
1823 // Open the Devices registry key.
1824 dwErrorCode
= (DWORD
)RegOpenKeyExW(HKEY_CURRENT_USER
, wszDevicesKey
, 0, KEY_READ
, &hDevicesKey
);
1825 if (dwErrorCode
!= ERROR_SUCCESS
)
1827 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode
);
1831 // Did the caller give us a printer to set as default?
1832 if (pszPrinter
&& *pszPrinter
)
1834 // Check if the given printer exists and query the value data size.
1835 dwErrorCode
= (DWORD
)RegQueryValueExW(hDevicesKey
, pszPrinter
, NULL
, NULL
, NULL
, &cbPrinterValueData
);
1836 if (dwErrorCode
== ERROR_FILE_NOT_FOUND
)
1838 dwErrorCode
= ERROR_INVALID_PRINTER_NAME
;
1841 else if (dwErrorCode
!= ERROR_SUCCESS
)
1843 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode
);
1847 cchPrinter
= wcslen(pszPrinter
);
1851 // If there is already a default printer, we're done!
1852 cchPrinter
= _countof(wszPrinter
);
1853 if (GetDefaultPrinterW(wszPrinter
, &cchPrinter
))
1855 dwErrorCode
= ERROR_SUCCESS
;
1859 // Otherwise, get us the first printer from the "Devices" key to later set it as default and query the value data size.
1860 cchPrinter
= _countof(wszPrinter
);
1861 dwErrorCode
= (DWORD
)RegEnumValueW(hDevicesKey
, 0, wszPrinter
, &cchPrinter
, NULL
, NULL
, NULL
, &cbPrinterValueData
);
1862 if (dwErrorCode
!= ERROR_MORE_DATA
)
1865 pszPrinter
= wszPrinter
;
1868 // We now need to query the value data, which has the format "winspool,<Port>:"
1869 // and make "<Printer Name>,winspool,<Port>:" out of it.
1870 // Allocate a buffer large enough for the final data.
1871 cbDeviceValueData
= (cchPrinter
+ 1) * sizeof(WCHAR
) + cbPrinterValueData
;
1872 pwszDeviceValueData
= HeapAlloc(hProcessHeap
, 0, cbDeviceValueData
);
1873 if (!pwszDeviceValueData
)
1875 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1876 ERR("HeapAlloc failed!\n");
1880 // Copy the Printer Name and a comma into it.
1881 CopyMemory(pwszDeviceValueData
, pszPrinter
, cchPrinter
* sizeof(WCHAR
));
1882 pwszDeviceValueData
[cchPrinter
] = L
',';
1884 // Append the value data, which has the format "winspool,<Port>:"
1885 dwErrorCode
= (DWORD
)RegQueryValueExW(hDevicesKey
, pszPrinter
, NULL
, NULL
, (PBYTE
)&pwszDeviceValueData
[cchPrinter
+ 1], &cbPrinterValueData
);
1886 if (dwErrorCode
!= ERROR_SUCCESS
)
1889 // Open the Windows registry key.
1890 dwErrorCode
= (DWORD
)RegOpenKeyExW(HKEY_CURRENT_USER
, wszWindowsKey
, 0, KEY_SET_VALUE
, &hWindowsKey
);
1891 if (dwErrorCode
!= ERROR_SUCCESS
)
1893 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode
);
1897 // Store our new default printer.
1898 dwErrorCode
= (DWORD
)RegSetValueExW(hWindowsKey
, wszDeviceValue
, 0, REG_SZ
, (PBYTE
)pwszDeviceValueData
, cbDeviceValueData
);
1899 if (dwErrorCode
!= ERROR_SUCCESS
)
1901 ERR("RegSetValueExW failed with status %lu!\n", dwErrorCode
);
1907 RegCloseKey(hDevicesKey
);
1910 RegCloseKey(hWindowsKey
);
1912 if (pwszDeviceValueData
)
1913 HeapFree(hProcessHeap
, 0, pwszDeviceValueData
);
1915 SetLastError(dwErrorCode
);
1916 return (dwErrorCode
== ERROR_SUCCESS
);
1920 SetPrinterA(HANDLE hPrinter
, DWORD Level
, PBYTE pPrinter
, DWORD Command
)
1922 TRACE("SetPrinterA(%p, %lu, %p, %lu)\n", hPrinter
, Level
, pPrinter
, Command
);
1928 SetPrinterW(HANDLE hPrinter
, DWORD Level
, PBYTE pPrinter
, DWORD Command
)
1930 TRACE("SetPrinterW(%p, %lu, %p, %lu)\n", hPrinter
, Level
, pPrinter
, Command
);
1936 SplDriverUnloadComplete(LPWSTR pDriverFile
)
1938 TRACE("DriverUnloadComplete(%S)\n", pDriverFile
);
1940 return TRUE
; // return true for now.
1944 StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, PBYTE pDocInfo
)
1946 DOC_INFO_1W wDocInfo1
= { 0 };
1949 DWORD dwReturnValue
= 0;
1950 PDOC_INFO_1A pDocInfo1
= (PDOC_INFO_1A
)pDocInfo
;
1952 TRACE("StartDocPrinterA(%p, %lu, %p)\n", hPrinter
, Level
, pDocInfo
);
1954 // Only check the minimum required for accessing pDocInfo.
1955 // Additional sanity checks are done in StartDocPrinterW.
1958 dwErrorCode
= ERROR_INVALID_PARAMETER
;
1964 dwErrorCode
= ERROR_INVALID_LEVEL
;
1968 if (pDocInfo1
->pDatatype
)
1970 // Convert pDocInfo1->pDatatype to a Unicode string wDocInfo1.pDatatype
1971 cch
= strlen(pDocInfo1
->pDatatype
);
1973 wDocInfo1
.pDatatype
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
1974 if (!wDocInfo1
.pDatatype
)
1976 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1977 ERR("HeapAlloc failed!\n");
1981 MultiByteToWideChar(CP_ACP
, 0, pDocInfo1
->pDatatype
, -1, wDocInfo1
.pDatatype
, cch
+ 1);
1984 if (pDocInfo1
->pDocName
)
1986 // Convert pDocInfo1->pDocName to a Unicode string wDocInfo1.pDocName
1987 cch
= strlen(pDocInfo1
->pDocName
);
1989 wDocInfo1
.pDocName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
1990 if (!wDocInfo1
.pDocName
)
1992 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1993 ERR("HeapAlloc failed!\n");
1997 MultiByteToWideChar(CP_ACP
, 0, pDocInfo1
->pDocName
, -1, wDocInfo1
.pDocName
, cch
+ 1);
2000 if (pDocInfo1
->pOutputFile
)
2002 // Convert pDocInfo1->pOutputFile to a Unicode string wDocInfo1.pOutputFile
2003 cch
= strlen(pDocInfo1
->pOutputFile
);
2005 wDocInfo1
.pOutputFile
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
2006 if (!wDocInfo1
.pOutputFile
)
2008 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2009 ERR("HeapAlloc failed!\n");
2013 MultiByteToWideChar(CP_ACP
, 0, pDocInfo1
->pOutputFile
, -1, wDocInfo1
.pOutputFile
, cch
+ 1);
2016 dwReturnValue
= StartDocPrinterW(hPrinter
, Level
, (PBYTE
)&wDocInfo1
);
2017 dwErrorCode
= GetLastError();
2020 if (wDocInfo1
.pDatatype
)
2021 HeapFree(hProcessHeap
, 0, wDocInfo1
.pDatatype
);
2023 if (wDocInfo1
.pDocName
)
2024 HeapFree(hProcessHeap
, 0, wDocInfo1
.pDocName
);
2026 if (wDocInfo1
.pOutputFile
)
2027 HeapFree(hProcessHeap
, 0, wDocInfo1
.pOutputFile
);
2029 SetLastError(dwErrorCode
);
2030 return dwReturnValue
;
2034 StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, PBYTE pDocInfo
)
2036 DWORD cbAddJobInfo1
;
2039 DWORD dwReturnValue
= 0;
2040 PADDJOB_INFO_1W pAddJobInfo1
= NULL
;
2041 PDOC_INFO_1W pDocInfo1
= (PDOC_INFO_1W
)pDocInfo
;
2042 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
2044 TRACE("StartDocPrinterW(%p, %lu, %p)\n", hPrinter
, Level
, pDocInfo
);
2049 dwErrorCode
= ERROR_INVALID_HANDLE
;
2055 dwErrorCode
= ERROR_INVALID_PARAMETER
;
2061 dwErrorCode
= ERROR_INVALID_LEVEL
;
2065 if (pHandle
->bStartedDoc
)
2067 dwErrorCode
= ERROR_INVALID_PRINTER_STATE
;
2071 // Check if we want to redirect output into a file.
2072 if (pDocInfo1
->pOutputFile
)
2074 // Do a StartDocPrinter RPC call in this case.
2075 dwErrorCode
= _StartDocPrinterWithRPC(pHandle
, pDocInfo1
);
2079 // Allocate memory for the ADDJOB_INFO_1W structure and a path.
2080 cbAddJobInfo1
= sizeof(ADDJOB_INFO_1W
) + MAX_PATH
* sizeof(WCHAR
);
2081 pAddJobInfo1
= HeapAlloc(hProcessHeap
, 0, cbAddJobInfo1
);
2084 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2085 ERR("HeapAlloc failed!\n");
2089 // Try to add a new job.
2090 // This only succeeds if the printer is set to do spooled printing.
2091 if (AddJobW((HANDLE
)pHandle
, 1, (PBYTE
)pAddJobInfo1
, cbAddJobInfo1
, &cbNeeded
))
2093 // Do spooled printing.
2094 dwErrorCode
= _StartDocPrinterSpooled(pHandle
, pDocInfo1
, pAddJobInfo1
);
2096 else if (GetLastError() == ERROR_INVALID_ACCESS
)
2098 // ERROR_INVALID_ACCESS is returned when the printer is set to do direct printing.
2099 // In this case, we do a StartDocPrinter RPC call.
2100 dwErrorCode
= _StartDocPrinterWithRPC(pHandle
, pDocInfo1
);
2104 dwErrorCode
= GetLastError();
2105 ERR("AddJobW failed with error %lu!\n", dwErrorCode
);
2110 if (dwErrorCode
== ERROR_SUCCESS
)
2112 pHandle
->bStartedDoc
= TRUE
;
2113 dwReturnValue
= pHandle
->dwJobID
;
2118 HeapFree(hProcessHeap
, 0, pAddJobInfo1
);
2120 SetLastError(dwErrorCode
);
2121 return dwReturnValue
;
2125 StartPagePrinter(HANDLE hPrinter
)
2128 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
2130 TRACE("StartPagePrinter(%p)\n", hPrinter
);
2135 dwErrorCode
= ERROR_INVALID_HANDLE
;
2142 dwErrorCode
= _RpcStartPagePrinter(pHandle
->hPrinter
);
2144 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
2146 dwErrorCode
= RpcExceptionCode();
2147 ERR("_RpcStartPagePrinter failed with exception code %lu!\n", dwErrorCode
);
2152 SetLastError(dwErrorCode
);
2153 return (dwErrorCode
== ERROR_SUCCESS
);
2157 WritePrinter(HANDLE hPrinter
, PVOID pBuf
, DWORD cbBuf
, PDWORD pcWritten
)
2160 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
2162 TRACE("WritePrinter(%p, %p, %lu, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2167 dwErrorCode
= ERROR_INVALID_HANDLE
;
2171 if (!pHandle
->bStartedDoc
)
2173 dwErrorCode
= ERROR_SPL_NO_STARTDOC
;
2177 if (pHandle
->hSPLFile
!= INVALID_HANDLE_VALUE
)
2179 // Write to the spool file. This doesn't need an RPC request.
2180 if (!WriteFile(pHandle
->hSPLFile
, pBuf
, cbBuf
, pcWritten
, NULL
))
2182 dwErrorCode
= GetLastError();
2183 ERR("WriteFile failed with error %lu!\n", dwErrorCode
);
2187 dwErrorCode
= ERROR_SUCCESS
;
2191 // TODO: This case (for direct printing or remote printing) has bad performance if multiple small-sized WritePrinter calls are performed.
2192 // We may increase performance by writing into a buffer and only doing a single RPC call when the buffer is full.
2197 dwErrorCode
= _RpcWritePrinter(pHandle
->hPrinter
, pBuf
, cbBuf
, pcWritten
);
2199 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
2201 dwErrorCode
= RpcExceptionCode();
2202 ERR("_RpcWritePrinter failed with exception code %lu!\n", dwErrorCode
);
2208 SetLastError(dwErrorCode
);
2209 return (dwErrorCode
== ERROR_SUCCESS
);
2213 XcvDataW(HANDLE hXcv
, PCWSTR pszDataName
, PBYTE pInputData
, DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
, PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
2215 TRACE("XcvDataW(%p, %S, %p, %lu, %p, %lu, %p, %p)\n", hXcv
, pszDataName
, pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);