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 DocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
, PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
, DWORD fMode
)
200 TRACE("DocumentPropertiesA(%p, %p, %s, %p, %p, %lu)\n", hWnd
, hPrinter
, pDeviceName
, pDevModeOutput
, pDevModeInput
, fMode
);
205 static PRINTER_INFO_9W
* get_devmodeW(HANDLE hprn
)
207 PRINTER_INFO_9W
*pi9
= NULL
;
211 res
= GetPrinterW(hprn
, 9, NULL
, 0, &needed
);
212 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
))
214 pi9
= HeapAlloc(hProcessHeap
, 0, needed
);
215 res
= GetPrinterW(hprn
, 9, (LPBYTE
)pi9
, needed
, &needed
);
221 ERR("GetPrinterW failed with %u\n", GetLastError());
222 HeapFree(hProcessHeap
, 0, pi9
);
227 DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
, PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
, DWORD fMode
)
229 HANDLE hUseHandle
= NULL
;
230 PRINTER_INFO_9W
*pi9
= NULL
;
231 LONG Result
= -1, Length
;
233 TRACE("DocumentPropertiesW(%p, %p, %S, %p, %p, %lu)\n", hWnd
, hPrinter
, pDeviceName
, pDevModeOutput
, pDevModeInput
, fMode
);
236 hUseHandle
= hPrinter
;
238 else if (!OpenPrinterW(pDeviceName
, &hUseHandle
, NULL
))
240 ERR("No handle, and no usable printer name passed in\n");
244 pi9
= get_devmodeW(hUseHandle
);
248 Length
= pi9
->pDevMode
->dmSize
+ pi9
->pDevMode
->dmDriverExtra
;
249 // See wineps.drv PSDRV_ExtDeviceMode
252 Result
= 1; /* IDOK */
254 if (fMode
& DM_IN_BUFFER
)
256 FIXME("Merge pDevModeInput with pi9, write back to driver!\n");
257 // See wineps.drv PSDRV_MergeDevmodes
260 if (fMode
& DM_IN_PROMPT
)
262 FIXME("Show property sheet!\n");
263 Result
= 2; /* IDCANCEL */
266 if (fMode
& (DM_OUT_BUFFER
| DM_OUT_DEFAULT
))
270 memcpy(pDevModeOutput
, pi9
->pDevMode
, pi9
->pDevMode
->dmSize
+ pi9
->pDevMode
->dmDriverExtra
);
274 ERR("No pDevModeOutput\n");
284 HeapFree(hProcessHeap
, 0, pi9
);
287 if (hUseHandle
&& !hPrinter
)
288 ClosePrinter(hUseHandle
);
293 EndDocPrinter(HANDLE hPrinter
)
296 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
298 TRACE("EndDocPrinter(%p)\n", hPrinter
);
303 dwErrorCode
= ERROR_INVALID_HANDLE
;
307 if (pHandle
->hSPLFile
!= INVALID_HANDLE_VALUE
)
309 // For spooled jobs, the document is finished by calling _RpcScheduleJob.
312 dwErrorCode
= _RpcScheduleJob(pHandle
->hPrinter
, pHandle
->dwJobID
);
314 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
316 dwErrorCode
= RpcExceptionCode();
317 ERR("_RpcScheduleJob failed with exception code %lu!\n", dwErrorCode
);
321 // Close the spool file handle.
322 CloseHandle(pHandle
->hSPLFile
);
326 // In all other cases, just call _RpcEndDocPrinter.
329 dwErrorCode
= _RpcEndDocPrinter(pHandle
->hPrinter
);
331 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
333 dwErrorCode
= RpcExceptionCode();
334 ERR("_RpcEndDocPrinter failed with exception code %lu!\n", dwErrorCode
);
339 // A new document can now be started again.
340 pHandle
->bStartedDoc
= FALSE
;
343 SetLastError(dwErrorCode
);
344 return (dwErrorCode
== ERROR_SUCCESS
);
348 EndPagePrinter(HANDLE hPrinter
)
351 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
353 TRACE("EndPagePrinter(%p)\n", hPrinter
);
358 dwErrorCode
= ERROR_INVALID_HANDLE
;
362 if (pHandle
->hSPLFile
!= INVALID_HANDLE_VALUE
)
364 // For spooled jobs, we don't need to do anything.
365 dwErrorCode
= ERROR_SUCCESS
;
369 // In all other cases, just call _RpcEndPagePrinter.
372 dwErrorCode
= _RpcEndPagePrinter(pHandle
->hPrinter
);
374 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
376 dwErrorCode
= RpcExceptionCode();
377 ERR("_RpcEndPagePrinter failed with exception code %lu!\n", dwErrorCode
);
383 SetLastError(dwErrorCode
);
384 return (dwErrorCode
== ERROR_SUCCESS
);
388 EnumPrintersA(DWORD Flags
, PSTR Name
, DWORD Level
, PBYTE pPrinterEnum
, DWORD cbBuf
, PDWORD pcbNeeded
, PDWORD pcReturned
)
390 BOOL bReturnValue
= FALSE
;
392 PWSTR pwszName
= NULL
;
393 PSTR pszPrinterName
= NULL
;
394 PSTR pszServerName
= NULL
;
395 PSTR pszDescription
= NULL
;
397 PSTR pszComment
= NULL
;
398 PSTR pszShareName
= NULL
;
399 PSTR pszPortName
= NULL
;
400 PSTR pszDriverName
= NULL
;
401 PSTR pszLocation
= NULL
;
402 PSTR pszSepFile
= NULL
;
403 PSTR pszPrintProcessor
= NULL
;
404 PSTR pszDatatype
= NULL
;
405 PSTR pszParameters
= NULL
;
407 PPRINTER_INFO_1W ppi1w
= NULL
;
408 PPRINTER_INFO_1A ppi1a
= NULL
;
409 PPRINTER_INFO_2W ppi2w
= NULL
;
410 PPRINTER_INFO_2A ppi2a
= NULL
;
411 PPRINTER_INFO_4W ppi4w
= NULL
;
412 PPRINTER_INFO_4A ppi4a
= NULL
;
413 PPRINTER_INFO_5W ppi5w
= NULL
;
414 PPRINTER_INFO_5A ppi5a
= NULL
;
416 TRACE("EnumPrintersA(%lu, %s, %lu, %p, %lu, %p, %p)\n", Flags
, Name
, Level
, pPrinterEnum
, cbBuf
, pcbNeeded
, pcReturned
);
418 // Check for invalid levels here for early error return. MSDN says that only 1, 2, 4, and 5 are allowable.
419 if (Level
!= 1 && Level
!= 2 && Level
!= 4 && Level
!= 5)
421 SetLastError(ERROR_INVALID_LEVEL
);
422 ERR("Invalid Level!\n");
428 // Convert pName to a Unicode string pwszName.
431 pwszName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
434 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
435 ERR("HeapAlloc failed!\n");
439 MultiByteToWideChar(CP_ACP
, 0, Name
, -1, pwszName
, cch
+ 1);
442 /* Ref: https://stackoverflow.com/questions/41147180/why-enumprintersa-and-enumprintersw-request-the-same-amount-of-memory */
443 bReturnValue
= EnumPrintersW(Flags
, pwszName
, Level
, pPrinterEnum
, cbBuf
, pcbNeeded
, pcReturned
);
444 HeapFree(hProcessHeap
, 0, pwszName
);
446 TRACE("*pcReturned is '%d' and bReturnValue is '%d' and GetLastError is '%ld'.\n", *pcReturned
, bReturnValue
, GetLastError());
448 /* We are mapping multiple different pointers to the same pPrinterEnum pointer here so that */
449 /* we can do in-place conversion. We read the Unicode response from the EnumPrintersW and */
450 /* then we write back the ANSI conversion into the same buffer for our EnumPrintersA output */
452 /* mapping to pPrinterEnum for Unicode (w) characters for Levels 1, 2, 4, and 5 */
453 ppi1w
= (PPRINTER_INFO_1W
)pPrinterEnum
;
454 ppi2w
= (PPRINTER_INFO_2W
)pPrinterEnum
;
455 ppi4w
= (PPRINTER_INFO_4W
)pPrinterEnum
;
456 ppi5w
= (PPRINTER_INFO_5W
)pPrinterEnum
;
457 /* mapping to pPrinterEnum for ANSI (a) characters for Levels 1, 2, 4, and 5 */
458 ppi1a
= (PPRINTER_INFO_1A
)pPrinterEnum
;
459 ppi2a
= (PPRINTER_INFO_2A
)pPrinterEnum
;
460 ppi4a
= (PPRINTER_INFO_4A
)pPrinterEnum
;
461 ppi5a
= (PPRINTER_INFO_5A
)pPrinterEnum
;
463 for (i
= 0; i
< *pcReturned
; i
++)
469 if (ppi1w
[i
].pDescription
)
471 // Convert Unicode pDescription to a ANSI string pszDescription.
472 cch
= wcslen(ppi1w
[i
].pDescription
);
474 pszDescription
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
477 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
478 ERR("HeapAlloc failed!\n");
482 WideCharToMultiByte(CP_ACP
, 0, ppi1w
[i
].pDescription
, -1, pszDescription
, cch
+ 1, NULL
, NULL
);
483 StringCchCopyA(ppi1a
[i
].pDescription
, cch
+ 1, pszDescription
);
485 HeapFree(hProcessHeap
, 0, pszDescription
);
490 // Convert Unicode pName to a ANSI string pszName.
491 cch
= wcslen(ppi1w
[i
].pName
);
493 pszName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
496 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
497 ERR("HeapAlloc failed!\n");
501 WideCharToMultiByte(CP_ACP
, 0, ppi1w
[i
].pName
, -1, pszName
, cch
+ 1, NULL
, NULL
);
502 StringCchCopyA(ppi1a
[i
].pName
, cch
+ 1, pszName
);
504 HeapFree(hProcessHeap
, 0, pszName
);
507 if (ppi1w
[i
].pComment
)
509 // Convert Unicode pComment to a ANSI string pszComment.
510 cch
= wcslen(ppi1w
[i
].pComment
);
512 pszComment
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
515 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
516 ERR("HeapAlloc failed!\n");
520 WideCharToMultiByte(CP_ACP
, 0, ppi1w
[i
].pComment
, -1, pszComment
, cch
+ 1, NULL
, NULL
);
521 StringCchCopyA(ppi1a
[i
].pComment
, cch
+ 1, pszComment
);
523 HeapFree(hProcessHeap
, 0, pszComment
);
531 if (ppi2w
[i
].pServerName
)
533 // Convert Unicode pServerName to a ANSI string pszServerName.
534 cch
= wcslen(ppi2w
[i
].pServerName
);
536 pszServerName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
539 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
540 ERR("HeapAlloc failed!\n");
544 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pServerName
, -1, pszServerName
, cch
+ 1, NULL
, NULL
);
545 StringCchCopyA(ppi2a
[i
].pServerName
, cch
+ 1, pszServerName
);
547 HeapFree(hProcessHeap
, 0, pszServerName
);
550 if (ppi2w
[i
].pPrinterName
)
552 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
553 cch
= wcslen(ppi2w
[i
].pPrinterName
);
555 pszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
558 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
559 ERR("HeapAlloc failed!\n");
563 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pPrinterName
, -1, pszPrinterName
, cch
+ 1, NULL
, NULL
);
564 StringCchCopyA(ppi2a
[i
].pPrinterName
, cch
+ 1, pszPrinterName
);
566 HeapFree(hProcessHeap
, 0, pszPrinterName
);
569 if (ppi2w
[i
].pShareName
)
571 // Convert Unicode pShareName to a ANSI string pszShareName.
572 cch
= wcslen(ppi2w
[i
].pShareName
);
574 pszShareName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
577 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
578 ERR("HeapAlloc failed!\n");
582 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pShareName
, -1, pszShareName
, cch
+ 1, NULL
, NULL
);
583 StringCchCopyA(ppi2a
[i
].pShareName
, cch
+ 1, pszShareName
);
585 HeapFree(hProcessHeap
, 0, pszShareName
);
588 if (ppi2w
[i
].pPortName
)
590 // Convert Unicode pPortName to a ANSI string pszPortName.
591 cch
= wcslen(ppi2w
[i
].pPortName
);
593 pszPortName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
596 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
597 ERR("HeapAlloc failed!\n");
601 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pPortName
, -1, pszPortName
, cch
+ 1, NULL
, NULL
);
602 StringCchCopyA(ppi2a
[i
].pPortName
, cch
+ 1, pszPortName
);
604 HeapFree(hProcessHeap
, 0, pszPortName
);
607 if (ppi2w
[i
].pDriverName
)
609 // Convert Unicode pDriverName to a ANSI string pszDriverName.
610 cch
= wcslen(ppi2w
[i
].pDriverName
);
612 pszDriverName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
615 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
616 ERR("HeapAlloc failed!\n");
620 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pDriverName
, -1, pszDriverName
, cch
+ 1, NULL
, NULL
);
621 StringCchCopyA(ppi2a
[i
].pDriverName
, cch
+ 1, pszDriverName
);
623 HeapFree(hProcessHeap
, 0, pszDriverName
);
626 if (ppi2w
[i
].pComment
)
628 // Convert Unicode pComment to a ANSI string pszComment.
629 cch
= wcslen(ppi2w
[i
].pComment
);
631 pszComment
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
634 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
635 ERR("HeapAlloc failed!\n");
639 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pComment
, -1, pszComment
, cch
+ 1, NULL
, NULL
);
640 StringCchCopyA(ppi2a
[i
].pComment
, cch
+ 1, pszComment
);
642 HeapFree(hProcessHeap
, 0, pszComment
);
645 if (ppi2w
[i
].pLocation
)
647 // Convert Unicode pLocation to a ANSI string pszLocation.
648 cch
= wcslen(ppi2w
[i
].pLocation
);
650 pszLocation
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
653 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
654 ERR("HeapAlloc failed!\n");
658 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pLocation
, -1, pszLocation
, cch
+ 1, NULL
, NULL
);
659 StringCchCopyA(ppi2a
[i
].pLocation
, cch
+ 1, pszLocation
);
661 HeapFree(hProcessHeap
, 0, pszLocation
);
665 if (ppi2w
[i
].pSepFile
)
667 // Convert Unicode pSepFile to a ANSI string pszSepFile.
668 cch
= wcslen(ppi2w
[i
].pSepFile
);
670 pszSepFile
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
673 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
674 ERR("HeapAlloc failed!\n");
678 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pSepFile
, -1, pszSepFile
, cch
+ 1, NULL
, NULL
);
679 StringCchCopyA(ppi2a
[i
].pSepFile
, cch
+ 1, pszSepFile
);
681 HeapFree(hProcessHeap
, 0, pszSepFile
);
684 if (ppi2w
[i
].pPrintProcessor
)
686 // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor.
687 cch
= wcslen(ppi2w
[i
].pPrintProcessor
);
689 pszPrintProcessor
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
690 if (!pszPrintProcessor
)
692 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
693 ERR("HeapAlloc failed!\n");
697 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pPrintProcessor
, -1, pszPrintProcessor
, cch
+ 1, NULL
, NULL
);
698 StringCchCopyA(ppi2a
[i
].pPrintProcessor
, cch
+ 1, pszPrintProcessor
);
700 HeapFree(hProcessHeap
, 0, pszPrintProcessor
);
704 if (ppi2w
[i
].pDatatype
)
706 // Convert Unicode pDatatype to a ANSI string pszDatatype.
707 cch
= wcslen(ppi2w
[i
].pDatatype
);
709 pszDatatype
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
712 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
713 ERR("HeapAlloc failed!\n");
717 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pDatatype
, -1, pszDatatype
, cch
+ 1, NULL
, NULL
);
718 StringCchCopyA(ppi2a
[i
].pDatatype
, cch
+ 1, pszDatatype
);
720 HeapFree(hProcessHeap
, 0, pszDatatype
);
723 if (ppi2w
[i
].pParameters
)
725 // Convert Unicode pParameters to a ANSI string pszParameters.
726 cch
= wcslen(ppi2w
[i
].pParameters
);
728 pszParameters
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
731 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
732 ERR("HeapAlloc failed!\n");
736 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pParameters
, -1, pszParameters
, cch
+ 1, NULL
, NULL
);
737 StringCchCopyA(ppi2a
[i
].pParameters
, cch
+ 1, pszParameters
);
739 HeapFree(hProcessHeap
, 0, pszParameters
);
747 if (ppi4w
[i
].pPrinterName
)
749 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
750 cch
= wcslen(ppi4w
[i
].pPrinterName
);
752 pszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
755 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
756 ERR("HeapAlloc failed!\n");
760 WideCharToMultiByte(CP_ACP
, 0, ppi4w
[i
].pPrinterName
, -1, pszPrinterName
, cch
+ 1, NULL
, NULL
);
761 StringCchCopyA(ppi4a
[i
].pPrinterName
, cch
+ 1, pszPrinterName
);
763 HeapFree(hProcessHeap
, 0, pszPrinterName
);
766 if (ppi4w
[i
].pServerName
)
768 // Convert Unicode pServerName to a ANSI string pszServerName.
769 cch
= wcslen(ppi4w
[i
].pServerName
);
771 pszServerName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
774 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
775 ERR("HeapAlloc failed!\n");
779 WideCharToMultiByte(CP_ACP
, 0, ppi4w
[i
].pServerName
, -1, pszServerName
, cch
+ 1, NULL
, NULL
);
780 StringCchCopyA(ppi4a
[i
].pServerName
, cch
+ 1, pszServerName
);
782 HeapFree(hProcessHeap
, 0, pszServerName
);
789 if (ppi5w
[i
].pPrinterName
)
791 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
792 cch
= wcslen(ppi5w
[i
].pPrinterName
);
794 pszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
797 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
798 ERR("HeapAlloc failed!\n");
802 WideCharToMultiByte(CP_ACP
, 0, ppi5w
[i
].pPrinterName
, -1, pszPrinterName
, cch
+ 1, NULL
, NULL
);
803 StringCchCopyA(ppi5a
[i
].pPrinterName
, cch
+ 1, pszPrinterName
);
805 HeapFree(hProcessHeap
, 0, pszPrinterName
);
808 if (ppi5w
[i
].pPortName
)
810 // Convert Unicode pPortName to a ANSI string pszPortName.
811 cch
= wcslen(ppi5w
[i
].pPortName
);
813 pszPortName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
816 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
817 ERR("HeapAlloc failed!\n");
821 WideCharToMultiByte(CP_ACP
, 0, ppi5w
[i
].pPortName
, -1, pszPortName
, cch
+ 1, NULL
, NULL
);
822 StringCchCopyA(ppi5a
[i
].pPortName
, cch
+ 1, pszPortName
);
824 HeapFree(hProcessHeap
, 0, pszPortName
);
838 EnumPrintersW(DWORD Flags
, PWSTR Name
, DWORD Level
, PBYTE pPrinterEnum
, DWORD cbBuf
, PDWORD pcbNeeded
, PDWORD pcReturned
)
842 TRACE("EnumPrintersW(%lu, %S, %lu, %p, %lu, %p, %p)\n", Flags
, Name
, Level
, pPrinterEnum
, cbBuf
, pcbNeeded
, pcReturned
);
844 // Dismiss invalid levels already at this point.
845 if (Level
== 3 || Level
> 5)
847 dwErrorCode
= ERROR_INVALID_LEVEL
;
851 if (cbBuf
&& pPrinterEnum
)
852 ZeroMemory(pPrinterEnum
, cbBuf
);
857 dwErrorCode
= _RpcEnumPrinters(Flags
, Name
, Level
, pPrinterEnum
, cbBuf
, pcbNeeded
, pcReturned
);
859 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
861 dwErrorCode
= RpcExceptionCode();
862 ERR("_RpcEnumPrinters failed with exception code %lu!\n", dwErrorCode
);
866 if (dwErrorCode
== ERROR_SUCCESS
)
868 // Replace relative offset addresses in the output by absolute pointers.
870 MarshallUpStructuresArray(cbBuf
, pPrinterEnum
, *pcReturned
, pPrinterInfoMarshalling
[Level
]->pInfo
, pPrinterInfoMarshalling
[Level
]->cbStructureSize
, TRUE
);
874 SetLastError(dwErrorCode
);
875 return (dwErrorCode
== ERROR_SUCCESS
);
879 FlushPrinter(HANDLE hPrinter
, PVOID pBuf
, DWORD cbBuf
, PDWORD pcWritten
, DWORD cSleep
)
881 TRACE("FlushPrinter(%p, %p, %lu, %p, %lu)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
, cSleep
);
887 GetDefaultPrinterA(LPSTR pszBuffer
, LPDWORD pcchBuffer
)
890 PWSTR pwszBuffer
= NULL
;
892 TRACE("GetDefaultPrinterA(%p, %p)\n", pszBuffer
, pcchBuffer
);
897 dwErrorCode
= ERROR_INVALID_PARAMETER
;
901 // Check if an ANSI buffer was given and if so, allocate a Unicode buffer of the same size.
902 if (pszBuffer
&& *pcchBuffer
)
904 pwszBuffer
= HeapAlloc(hProcessHeap
, 0, *pcchBuffer
* sizeof(WCHAR
));
907 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
908 ERR("HeapAlloc failed!\n");
913 if (!GetDefaultPrinterW(pwszBuffer
, pcchBuffer
))
915 dwErrorCode
= GetLastError();
919 // We successfully got a string in pwszBuffer, so convert the Unicode string to ANSI.
920 WideCharToMultiByte(CP_ACP
, 0, pwszBuffer
, -1, pszBuffer
, *pcchBuffer
, NULL
, NULL
);
922 dwErrorCode
= ERROR_SUCCESS
;
926 HeapFree(hProcessHeap
, 0, pwszBuffer
);
928 SetLastError(dwErrorCode
);
929 return (dwErrorCode
== ERROR_SUCCESS
);
933 GetDefaultPrinterW(LPWSTR pszBuffer
, LPDWORD pcchBuffer
)
936 DWORD cchInputBuffer
;
938 HKEY hWindowsKey
= NULL
;
939 PWSTR pwszDevice
= NULL
;
942 TRACE("GetDefaultPrinterW(%p, %p)\n", pszBuffer
, pcchBuffer
);
947 dwErrorCode
= ERROR_INVALID_PARAMETER
;
951 cchInputBuffer
= *pcchBuffer
;
953 // Open the registry key where the default printer for the current user is stored.
954 dwErrorCode
= (DWORD
)RegOpenKeyExW(HKEY_CURRENT_USER
, wszWindowsKey
, 0, KEY_READ
, &hWindowsKey
);
955 if (dwErrorCode
!= ERROR_SUCCESS
)
957 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode
);
961 // Determine the size of the required buffer.
962 dwErrorCode
= (DWORD
)RegQueryValueExW(hWindowsKey
, wszDeviceValue
, NULL
, NULL
, NULL
, &cbNeeded
);
963 if (dwErrorCode
!= ERROR_SUCCESS
)
965 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode
);
970 pwszDevice
= HeapAlloc(hProcessHeap
, 0, cbNeeded
);
973 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
974 ERR("HeapAlloc failed!\n");
978 // Now get the actual value.
979 dwErrorCode
= RegQueryValueExW(hWindowsKey
, wszDeviceValue
, NULL
, NULL
, (PBYTE
)pwszDevice
, &cbNeeded
);
980 if (dwErrorCode
!= ERROR_SUCCESS
)
982 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode
);
986 // We get a string "<Printer Name>,winspool,<Port>:".
987 // Extract the printer name from it.
988 pwszComma
= wcschr(pwszDevice
, L
',');
991 ERR("Found no or invalid default printer: %S!\n", pwszDevice
);
992 dwErrorCode
= ERROR_INVALID_NAME
;
996 // Store the length of the Printer Name (including the terminating NUL character!) in *pcchBuffer.
997 *pcchBuffer
= pwszComma
- pwszDevice
+ 1;
999 // Check if the supplied buffer is large enough.
1000 if (cchInputBuffer
< *pcchBuffer
)
1002 dwErrorCode
= ERROR_INSUFFICIENT_BUFFER
;
1006 // Copy the default printer.
1008 CopyMemory(pszBuffer
, pwszDevice
, *pcchBuffer
* sizeof(WCHAR
));
1010 dwErrorCode
= ERROR_SUCCESS
;
1014 RegCloseKey(hWindowsKey
);
1017 HeapFree(hProcessHeap
, 0, pwszDevice
);
1019 SetLastError(dwErrorCode
);
1020 return (dwErrorCode
== ERROR_SUCCESS
);
1024 GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1026 TRACE("GetPrinterA(%p, %lu, %p, %lu, %p)\n", hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
);
1027 if(pcbNeeded
) *pcbNeeded
= 0;
1032 GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
, DWORD Level
, LPBYTE pDriverInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1034 TRACE("GetPrinterDriverA(%p, %s, %lu, %p, %lu, %p)\n", hPrinter
, pEnvironment
, Level
, pDriverInfo
, cbBuf
, pcbNeeded
);
1035 if(pcbNeeded
) *pcbNeeded
= 0;
1040 GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
, DWORD Level
, LPBYTE pDriverInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1043 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
1045 TRACE("GetPrinterDriverW(%p, %S, %lu, %p, %lu, %p)\n", hPrinter
, pEnvironment
, Level
, pDriverInfo
, cbBuf
, pcbNeeded
);
1050 dwErrorCode
= ERROR_INVALID_HANDLE
;
1054 // Dismiss invalid levels already at this point.
1055 if (Level
> 8 || Level
< 1)
1057 dwErrorCode
= ERROR_INVALID_LEVEL
;
1061 if (cbBuf
&& pDriverInfo
)
1062 ZeroMemory(pDriverInfo
, cbBuf
);
1067 dwErrorCode
= _RpcGetPrinterDriver(pHandle
->hPrinter
, pEnvironment
, Level
, pDriverInfo
, cbBuf
, pcbNeeded
);
1069 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
1071 dwErrorCode
= RpcExceptionCode();
1072 ERR("_RpcGetPrinter failed with exception code %lu!\n", dwErrorCode
);
1076 if (dwErrorCode
== ERROR_SUCCESS
)
1078 // Replace relative offset addresses in the output by absolute pointers.
1080 MarshallUpStructure(cbBuf
, pDriverInfo
, pPrinterDriverMarshalling
[Level
]->pInfo
, pPrinterDriverMarshalling
[Level
]->cbStructureSize
, TRUE
);
1084 SetLastError(dwErrorCode
);
1085 return (dwErrorCode
== ERROR_SUCCESS
);
1089 GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1092 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
1094 TRACE("GetPrinterW(%p, %lu, %p, %lu, %p)\n", hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
);
1099 dwErrorCode
= ERROR_INVALID_HANDLE
;
1103 // Dismiss invalid levels already at this point.
1106 dwErrorCode
= ERROR_INVALID_LEVEL
;
1110 if (cbBuf
&& pPrinter
)
1111 ZeroMemory(pPrinter
, cbBuf
);
1116 dwErrorCode
= _RpcGetPrinter(pHandle
->hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
);
1118 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
1120 dwErrorCode
= RpcExceptionCode();
1121 ERR("_RpcGetPrinter failed with exception code %lu!\n", dwErrorCode
);
1125 if (dwErrorCode
== ERROR_SUCCESS
)
1127 // Replace relative offset addresses in the output by absolute pointers.
1129 MarshallUpStructure(cbBuf
, pPrinter
, pPrinterInfoMarshalling
[Level
]->pInfo
, pPrinterInfoMarshalling
[Level
]->cbStructureSize
, TRUE
);
1133 SetLastError(dwErrorCode
);
1134 return (dwErrorCode
== ERROR_SUCCESS
);
1138 OpenPrinterA(LPSTR pPrinterName
, LPHANDLE phPrinter
, LPPRINTER_DEFAULTSA pDefault
)
1140 BOOL bReturnValue
= FALSE
;
1142 PWSTR pwszPrinterName
= NULL
;
1143 PRINTER_DEFAULTSW wDefault
= { 0 };
1145 TRACE("OpenPrinterA(%s, %p, %p)\n", pPrinterName
, phPrinter
, pDefault
);
1149 // Convert pPrinterName to a Unicode string pwszPrinterName
1150 cch
= strlen(pPrinterName
);
1152 pwszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
1153 if (!pwszPrinterName
)
1155 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1156 ERR("HeapAlloc failed!\n");
1160 MultiByteToWideChar(CP_ACP
, 0, pPrinterName
, -1, pwszPrinterName
, cch
+ 1);
1165 wDefault
.DesiredAccess
= pDefault
->DesiredAccess
;
1167 if (pDefault
->pDatatype
)
1169 // Convert pDefault->pDatatype to a Unicode string wDefault.pDatatype
1170 cch
= strlen(pDefault
->pDatatype
);
1172 wDefault
.pDatatype
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
1173 if (!wDefault
.pDatatype
)
1175 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1176 ERR("HeapAlloc failed!\n");
1180 MultiByteToWideChar(CP_ACP
, 0, pDefault
->pDatatype
, -1, wDefault
.pDatatype
, cch
+ 1);
1183 if (pDefault
->pDevMode
)
1184 wDefault
.pDevMode
= GdiConvertToDevmodeW(pDefault
->pDevMode
);
1187 bReturnValue
= OpenPrinterW(pwszPrinterName
, phPrinter
, &wDefault
);
1190 if (wDefault
.pDatatype
)
1191 HeapFree(hProcessHeap
, 0, wDefault
.pDatatype
);
1193 if (wDefault
.pDevMode
)
1194 HeapFree(hProcessHeap
, 0, wDefault
.pDevMode
);
1196 if (pwszPrinterName
)
1197 HeapFree(hProcessHeap
, 0, pwszPrinterName
);
1199 return bReturnValue
;
1203 OpenPrinterW(LPWSTR pPrinterName
, LPHANDLE phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
1207 PSPOOLER_HANDLE pHandle
;
1208 PWSTR pDatatype
= NULL
;
1209 WINSPOOL_DEVMODE_CONTAINER DevModeContainer
= { 0 };
1210 ACCESS_MASK AccessRequired
= 0;
1212 TRACE("OpenPrinterW(%S, %p, %p)\n", pPrinterName
, phPrinter
, pDefault
);
1217 dwErrorCode
= ERROR_INVALID_PARAMETER
;
1221 // Prepare the additional parameters in the format required by _RpcOpenPrinter
1224 pDatatype
= pDefault
->pDatatype
;
1225 DevModeContainer
.cbBuf
= sizeof(DEVMODEW
);
1226 DevModeContainer
.pDevMode
= (BYTE
*)pDefault
->pDevMode
;
1227 AccessRequired
= pDefault
->DesiredAccess
;
1233 dwErrorCode
= _RpcOpenPrinter(pPrinterName
, &hPrinter
, pDatatype
, &DevModeContainer
, AccessRequired
);
1235 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
1237 dwErrorCode
= RpcExceptionCode();
1238 ERR("_RpcOpenPrinter failed with exception code %lu!\n", dwErrorCode
);
1242 if (dwErrorCode
== ERROR_SUCCESS
)
1244 // Create a new SPOOLER_HANDLE structure.
1245 pHandle
= HeapAlloc(hProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(SPOOLER_HANDLE
));
1248 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1249 ERR("HeapAlloc failed!\n");
1253 pHandle
->hPrinter
= hPrinter
;
1254 pHandle
->hSPLFile
= INVALID_HANDLE_VALUE
;
1256 // Return it as phPrinter.
1257 *phPrinter
= (HANDLE
)pHandle
;
1261 SetLastError(dwErrorCode
);
1262 return (dwErrorCode
== ERROR_SUCCESS
);
1266 ReadPrinter(HANDLE hPrinter
, PVOID pBuf
, DWORD cbBuf
, PDWORD pNoBytesRead
)
1269 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
1271 TRACE("ReadPrinter(%p, %p, %lu, %p)\n", hPrinter
, pBuf
, cbBuf
, pNoBytesRead
);
1276 dwErrorCode
= ERROR_INVALID_HANDLE
;
1283 dwErrorCode
= _RpcReadPrinter(pHandle
->hPrinter
, pBuf
, cbBuf
, pNoBytesRead
);
1285 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
1287 dwErrorCode
= RpcExceptionCode();
1288 ERR("_RpcReadPrinter failed with exception code %lu!\n", dwErrorCode
);
1293 SetLastError(dwErrorCode
);
1294 return (dwErrorCode
== ERROR_SUCCESS
);
1298 ResetPrinterA(HANDLE hPrinter
, PPRINTER_DEFAULTSA pDefault
)
1300 TRACE("ResetPrinterA(%p, %p)\n", hPrinter
, pDefault
);
1306 ResetPrinterW(HANDLE hPrinter
, PPRINTER_DEFAULTSW pDefault
)
1308 TRACE("ResetPrinterW(%p, %p)\n", hPrinter
, pDefault
);
1314 SetDefaultPrinterA(LPCSTR pszPrinter
)
1316 BOOL bReturnValue
= FALSE
;
1318 PWSTR pwszPrinter
= NULL
;
1320 TRACE("SetDefaultPrinterA(%s)\n", pszPrinter
);
1324 // Convert pszPrinter to a Unicode string pwszPrinter
1325 cch
= strlen(pszPrinter
);
1327 pwszPrinter
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
1330 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1331 ERR("HeapAlloc failed!\n");
1335 MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, pwszPrinter
, cch
+ 1);
1338 bReturnValue
= SetDefaultPrinterW(pwszPrinter
);
1342 HeapFree(hProcessHeap
, 0, pwszPrinter
);
1344 return bReturnValue
;
1348 SetDefaultPrinterW(LPCWSTR pszPrinter
)
1350 const WCHAR wszDevicesKey
[] = L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Devices";
1352 DWORD cbDeviceValueData
;
1353 DWORD cbPrinterValueData
= 0;
1356 HKEY hDevicesKey
= NULL
;
1357 HKEY hWindowsKey
= NULL
;
1358 PWSTR pwszDeviceValueData
= NULL
;
1359 WCHAR wszPrinter
[MAX_PRINTER_NAME
+ 1];
1361 TRACE("SetDefaultPrinterW(%S)\n", pszPrinter
);
1363 // Open the Devices registry key.
1364 dwErrorCode
= (DWORD
)RegOpenKeyExW(HKEY_CURRENT_USER
, wszDevicesKey
, 0, KEY_READ
, &hDevicesKey
);
1365 if (dwErrorCode
!= ERROR_SUCCESS
)
1367 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode
);
1371 // Did the caller give us a printer to set as default?
1372 if (pszPrinter
&& *pszPrinter
)
1374 // Check if the given printer exists and query the value data size.
1375 dwErrorCode
= (DWORD
)RegQueryValueExW(hDevicesKey
, pszPrinter
, NULL
, NULL
, NULL
, &cbPrinterValueData
);
1376 if (dwErrorCode
== ERROR_FILE_NOT_FOUND
)
1378 dwErrorCode
= ERROR_INVALID_PRINTER_NAME
;
1381 else if (dwErrorCode
!= ERROR_SUCCESS
)
1383 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode
);
1387 cchPrinter
= wcslen(pszPrinter
);
1391 // If there is already a default printer, we're done!
1392 cchPrinter
= _countof(wszPrinter
);
1393 if (GetDefaultPrinterW(wszPrinter
, &cchPrinter
))
1395 dwErrorCode
= ERROR_SUCCESS
;
1399 // Otherwise, get us the first printer from the "Devices" key to later set it as default and query the value data size.
1400 cchPrinter
= _countof(wszPrinter
);
1401 dwErrorCode
= (DWORD
)RegEnumValueW(hDevicesKey
, 0, wszPrinter
, &cchPrinter
, NULL
, NULL
, NULL
, &cbPrinterValueData
);
1402 if (dwErrorCode
!= ERROR_MORE_DATA
)
1405 pszPrinter
= wszPrinter
;
1408 // We now need to query the value data, which has the format "winspool,<Port>:"
1409 // and make "<Printer Name>,winspool,<Port>:" out of it.
1410 // Allocate a buffer large enough for the final data.
1411 cbDeviceValueData
= (cchPrinter
+ 1) * sizeof(WCHAR
) + cbPrinterValueData
;
1412 pwszDeviceValueData
= HeapAlloc(hProcessHeap
, 0, cbDeviceValueData
);
1413 if (!pwszDeviceValueData
)
1415 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1416 ERR("HeapAlloc failed!\n");
1420 // Copy the Printer Name and a comma into it.
1421 CopyMemory(pwszDeviceValueData
, pszPrinter
, cchPrinter
* sizeof(WCHAR
));
1422 pwszDeviceValueData
[cchPrinter
] = L
',';
1424 // Append the value data, which has the format "winspool,<Port>:"
1425 dwErrorCode
= (DWORD
)RegQueryValueExW(hDevicesKey
, pszPrinter
, NULL
, NULL
, (PBYTE
)&pwszDeviceValueData
[cchPrinter
+ 1], &cbPrinterValueData
);
1426 if (dwErrorCode
!= ERROR_SUCCESS
)
1429 // Open the Windows registry key.
1430 dwErrorCode
= (DWORD
)RegOpenKeyExW(HKEY_CURRENT_USER
, wszWindowsKey
, 0, KEY_SET_VALUE
, &hWindowsKey
);
1431 if (dwErrorCode
!= ERROR_SUCCESS
)
1433 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode
);
1437 // Store our new default printer.
1438 dwErrorCode
= (DWORD
)RegSetValueExW(hWindowsKey
, wszDeviceValue
, 0, REG_SZ
, (PBYTE
)pwszDeviceValueData
, cbDeviceValueData
);
1439 if (dwErrorCode
!= ERROR_SUCCESS
)
1441 ERR("RegSetValueExW failed with status %lu!\n", dwErrorCode
);
1447 RegCloseKey(hDevicesKey
);
1450 RegCloseKey(hWindowsKey
);
1452 if (pwszDeviceValueData
)
1453 HeapFree(hProcessHeap
, 0, pwszDeviceValueData
);
1455 SetLastError(dwErrorCode
);
1456 return (dwErrorCode
== ERROR_SUCCESS
);
1460 SetPrinterA(HANDLE hPrinter
, DWORD Level
, PBYTE pPrinter
, DWORD Command
)
1462 TRACE("SetPrinterA(%p, %lu, %p, %lu)\n", hPrinter
, Level
, pPrinter
, Command
);
1468 SetPrinterW(HANDLE hPrinter
, DWORD Level
, PBYTE pPrinter
, DWORD Command
)
1470 TRACE("SetPrinterW(%p, %lu, %p, %lu)\n", hPrinter
, Level
, pPrinter
, Command
);
1476 StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, PBYTE pDocInfo
)
1478 DOC_INFO_1W wDocInfo1
= { 0 };
1481 DWORD dwReturnValue
= 0;
1482 PDOC_INFO_1A pDocInfo1
= (PDOC_INFO_1A
)pDocInfo
;
1484 TRACE("StartDocPrinterA(%p, %lu, %p)\n", hPrinter
, Level
, pDocInfo
);
1486 // Only check the minimum required for accessing pDocInfo.
1487 // Additional sanity checks are done in StartDocPrinterW.
1490 dwErrorCode
= ERROR_INVALID_PARAMETER
;
1496 dwErrorCode
= ERROR_INVALID_LEVEL
;
1500 if (pDocInfo1
->pDatatype
)
1502 // Convert pDocInfo1->pDatatype to a Unicode string wDocInfo1.pDatatype
1503 cch
= strlen(pDocInfo1
->pDatatype
);
1505 wDocInfo1
.pDatatype
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
1506 if (!wDocInfo1
.pDatatype
)
1508 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1509 ERR("HeapAlloc failed!\n");
1513 MultiByteToWideChar(CP_ACP
, 0, pDocInfo1
->pDatatype
, -1, wDocInfo1
.pDatatype
, cch
+ 1);
1516 if (pDocInfo1
->pDocName
)
1518 // Convert pDocInfo1->pDocName to a Unicode string wDocInfo1.pDocName
1519 cch
= strlen(pDocInfo1
->pDocName
);
1521 wDocInfo1
.pDocName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
1522 if (!wDocInfo1
.pDocName
)
1524 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1525 ERR("HeapAlloc failed!\n");
1529 MultiByteToWideChar(CP_ACP
, 0, pDocInfo1
->pDocName
, -1, wDocInfo1
.pDocName
, cch
+ 1);
1532 if (pDocInfo1
->pOutputFile
)
1534 // Convert pDocInfo1->pOutputFile to a Unicode string wDocInfo1.pOutputFile
1535 cch
= strlen(pDocInfo1
->pOutputFile
);
1537 wDocInfo1
.pOutputFile
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
1538 if (!wDocInfo1
.pOutputFile
)
1540 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1541 ERR("HeapAlloc failed!\n");
1545 MultiByteToWideChar(CP_ACP
, 0, pDocInfo1
->pOutputFile
, -1, wDocInfo1
.pOutputFile
, cch
+ 1);
1548 dwReturnValue
= StartDocPrinterW(hPrinter
, Level
, (PBYTE
)&wDocInfo1
);
1549 dwErrorCode
= GetLastError();
1552 if (wDocInfo1
.pDatatype
)
1553 HeapFree(hProcessHeap
, 0, wDocInfo1
.pDatatype
);
1555 if (wDocInfo1
.pDocName
)
1556 HeapFree(hProcessHeap
, 0, wDocInfo1
.pDocName
);
1558 if (wDocInfo1
.pOutputFile
)
1559 HeapFree(hProcessHeap
, 0, wDocInfo1
.pOutputFile
);
1561 SetLastError(dwErrorCode
);
1562 return dwReturnValue
;
1566 StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, PBYTE pDocInfo
)
1568 DWORD cbAddJobInfo1
;
1571 DWORD dwReturnValue
= 0;
1572 PADDJOB_INFO_1W pAddJobInfo1
= NULL
;
1573 PDOC_INFO_1W pDocInfo1
= (PDOC_INFO_1W
)pDocInfo
;
1574 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
1576 TRACE("StartDocPrinterW(%p, %lu, %p)\n", hPrinter
, Level
, pDocInfo
);
1581 dwErrorCode
= ERROR_INVALID_HANDLE
;
1587 dwErrorCode
= ERROR_INVALID_PARAMETER
;
1593 dwErrorCode
= ERROR_INVALID_LEVEL
;
1597 if (pHandle
->bStartedDoc
)
1599 dwErrorCode
= ERROR_INVALID_PRINTER_STATE
;
1603 // Check if we want to redirect output into a file.
1604 if (pDocInfo1
->pOutputFile
)
1606 // Do a StartDocPrinter RPC call in this case.
1607 dwErrorCode
= _StartDocPrinterWithRPC(pHandle
, pDocInfo1
);
1611 // Allocate memory for the ADDJOB_INFO_1W structure and a path.
1612 cbAddJobInfo1
= sizeof(ADDJOB_INFO_1W
) + MAX_PATH
* sizeof(WCHAR
);
1613 pAddJobInfo1
= HeapAlloc(hProcessHeap
, 0, cbAddJobInfo1
);
1616 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1617 ERR("HeapAlloc failed!\n");
1621 // Try to add a new job.
1622 // This only succeeds if the printer is set to do spooled printing.
1623 if (AddJobW((HANDLE
)pHandle
, 1, (PBYTE
)pAddJobInfo1
, cbAddJobInfo1
, &cbNeeded
))
1625 // Do spooled printing.
1626 dwErrorCode
= _StartDocPrinterSpooled(pHandle
, pDocInfo1
, pAddJobInfo1
);
1628 else if (GetLastError() == ERROR_INVALID_ACCESS
)
1630 // ERROR_INVALID_ACCESS is returned when the printer is set to do direct printing.
1631 // In this case, we do a StartDocPrinter RPC call.
1632 dwErrorCode
= _StartDocPrinterWithRPC(pHandle
, pDocInfo1
);
1636 dwErrorCode
= GetLastError();
1637 ERR("AddJobW failed with error %lu!\n", dwErrorCode
);
1642 if (dwErrorCode
== ERROR_SUCCESS
)
1644 pHandle
->bStartedDoc
= TRUE
;
1645 dwReturnValue
= pHandle
->dwJobID
;
1650 HeapFree(hProcessHeap
, 0, pAddJobInfo1
);
1652 SetLastError(dwErrorCode
);
1653 return dwReturnValue
;
1657 StartPagePrinter(HANDLE hPrinter
)
1660 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
1662 TRACE("StartPagePrinter(%p)\n", hPrinter
);
1667 dwErrorCode
= ERROR_INVALID_HANDLE
;
1674 dwErrorCode
= _RpcStartPagePrinter(pHandle
->hPrinter
);
1676 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
1678 dwErrorCode
= RpcExceptionCode();
1679 ERR("_RpcStartPagePrinter failed with exception code %lu!\n", dwErrorCode
);
1684 SetLastError(dwErrorCode
);
1685 return (dwErrorCode
== ERROR_SUCCESS
);
1689 WritePrinter(HANDLE hPrinter
, PVOID pBuf
, DWORD cbBuf
, PDWORD pcWritten
)
1692 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
1694 TRACE("WritePrinter(%p, %p, %lu, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
1699 dwErrorCode
= ERROR_INVALID_HANDLE
;
1703 if (!pHandle
->bStartedDoc
)
1705 dwErrorCode
= ERROR_SPL_NO_STARTDOC
;
1709 if (pHandle
->hSPLFile
!= INVALID_HANDLE_VALUE
)
1711 // Write to the spool file. This doesn't need an RPC request.
1712 if (!WriteFile(pHandle
->hSPLFile
, pBuf
, cbBuf
, pcWritten
, NULL
))
1714 dwErrorCode
= GetLastError();
1715 ERR("WriteFile failed with error %lu!\n", dwErrorCode
);
1719 dwErrorCode
= ERROR_SUCCESS
;
1723 // TODO: This case (for direct printing or remote printing) has bad performance if multiple small-sized WritePrinter calls are performed.
1724 // We may increase performance by writing into a buffer and only doing a single RPC call when the buffer is full.
1729 dwErrorCode
= _RpcWritePrinter(pHandle
->hPrinter
, pBuf
, cbBuf
, pcWritten
);
1731 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
1733 dwErrorCode
= RpcExceptionCode();
1734 ERR("_RpcWritePrinter failed with exception code %lu!\n", dwErrorCode
);
1740 SetLastError(dwErrorCode
);
1741 return (dwErrorCode
== ERROR_SUCCESS
);
1745 XcvDataW(HANDLE hXcv
, PCWSTR pszDataName
, PBYTE pInputData
, DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
, PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
1747 TRACE("XcvDataW(%p, %S, %p, %lu, %p, %lu, %p, %p)\n", hXcv
, pszDataName
, pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);