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 PWSTR pwszDeviceName
= NULL
;
209 PDEVMODEW pdmwInput
= NULL
;
210 PDEVMODEW pdmwOutput
= NULL
;
211 BOOL bReturnValue
= -1;
214 TRACE("DocumentPropertiesA(%p, %p, %s, %p, %p, %lu)\n", hWnd
, hPrinter
, pDeviceName
, pDevModeOutput
, pDevModeInput
, fMode
);
218 // Convert pName to a Unicode string pwszDeviceName.
219 cch
= strlen(pDeviceName
);
221 pwszDeviceName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
224 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
225 ERR("HeapAlloc failed!\n");
229 MultiByteToWideChar(CP_ACP
, 0, pDeviceName
, -1, pwszDeviceName
, cch
+ 1);
234 // Create working buffer for input to DocumentPropertiesW.
235 pdmwInput
= HeapAlloc(hProcessHeap
, 0, sizeof(DEVMODEW
));
238 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
239 ERR("HeapAlloc failed!\n");
242 RosConvertAnsiDevModeToUnicodeDevmode(pDevModeInput
, pdmwInput
);
247 // Create working buffer for output from DocumentPropertiesW.
248 pdmwOutput
= HeapAlloc(hProcessHeap
, 0, sizeof(DEVMODEW
));
251 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
252 ERR("HeapAlloc failed!\n");
257 bReturnValue
= DocumentPropertiesW(hWnd
, hPrinter
, pwszDeviceName
, pdmwOutput
, pdmwInput
, fMode
);
258 TRACE("bReturnValue from DocumentPropertiesW is '%ld'.\n", bReturnValue
);
262 HeapFree(hProcessHeap
, 0, pwszDeviceName
);
265 if (bReturnValue
< 0)
267 TRACE("DocumentPropertiesW failed!\n");
273 RosConvertUnicodeDevModeToAnsiDevmode(pdmwOutput
, pDevModeOutput
);
278 HeapFree(hProcessHeap
, 0, pwszDeviceName
);
281 HeapFree(hProcessHeap
, 0, pdmwInput
);
284 HeapFree(hProcessHeap
, 0, pdmwOutput
);
289 static PRINTER_INFO_9W
* get_devmodeW(HANDLE hprn
)
291 PRINTER_INFO_9W
*pi9
= NULL
;
295 res
= GetPrinterW(hprn
, 9, NULL
, 0, &needed
);
296 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
))
298 pi9
= HeapAlloc(hProcessHeap
, 0, needed
);
299 res
= GetPrinterW(hprn
, 9, (LPBYTE
)pi9
, needed
, &needed
);
305 ERR("GetPrinterW failed with %u\n", GetLastError());
306 HeapFree(hProcessHeap
, 0, pi9
);
311 DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
, PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
, DWORD fMode
)
313 HANDLE hUseHandle
= NULL
;
314 PRINTER_INFO_9W
*pi9
= NULL
;
315 LONG Result
= -1, Length
;
317 TRACE("DocumentPropertiesW(%p, %p, %S, %p, %p, %lu)\n", hWnd
, hPrinter
, pDeviceName
, pDevModeOutput
, pDevModeInput
, fMode
);
320 hUseHandle
= hPrinter
;
322 else if (!OpenPrinterW(pDeviceName
, &hUseHandle
, NULL
))
324 ERR("No handle, and no usable printer name passed in\n");
328 pi9
= get_devmodeW(hUseHandle
);
332 Length
= pi9
->pDevMode
->dmSize
+ pi9
->pDevMode
->dmDriverExtra
;
333 // See wineps.drv PSDRV_ExtDeviceMode
336 Result
= 1; /* IDOK */
338 if (fMode
& DM_IN_BUFFER
)
340 FIXME("Merge pDevModeInput with pi9, write back to driver!\n");
341 // See wineps.drv PSDRV_MergeDevmodes
344 if (fMode
& DM_IN_PROMPT
)
346 FIXME("Show property sheet!\n");
347 Result
= 2; /* IDCANCEL */
350 if (fMode
& (DM_OUT_BUFFER
| DM_OUT_DEFAULT
))
354 memcpy(pDevModeOutput
, pi9
->pDevMode
, pi9
->pDevMode
->dmSize
+ pi9
->pDevMode
->dmDriverExtra
);
358 ERR("No pDevModeOutput\n");
368 HeapFree(hProcessHeap
, 0, pi9
);
371 if (hUseHandle
&& !hPrinter
)
372 ClosePrinter(hUseHandle
);
377 EndDocPrinter(HANDLE hPrinter
)
380 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
382 TRACE("EndDocPrinter(%p)\n", hPrinter
);
387 dwErrorCode
= ERROR_INVALID_HANDLE
;
391 if (pHandle
->hSPLFile
!= INVALID_HANDLE_VALUE
)
393 // For spooled jobs, the document is finished by calling _RpcScheduleJob.
396 dwErrorCode
= _RpcScheduleJob(pHandle
->hPrinter
, pHandle
->dwJobID
);
398 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
400 dwErrorCode
= RpcExceptionCode();
401 ERR("_RpcScheduleJob failed with exception code %lu!\n", dwErrorCode
);
405 // Close the spool file handle.
406 CloseHandle(pHandle
->hSPLFile
);
410 // In all other cases, just call _RpcEndDocPrinter.
413 dwErrorCode
= _RpcEndDocPrinter(pHandle
->hPrinter
);
415 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
417 dwErrorCode
= RpcExceptionCode();
418 ERR("_RpcEndDocPrinter failed with exception code %lu!\n", dwErrorCode
);
423 // A new document can now be started again.
424 pHandle
->bStartedDoc
= FALSE
;
427 SetLastError(dwErrorCode
);
428 return (dwErrorCode
== ERROR_SUCCESS
);
432 EndPagePrinter(HANDLE hPrinter
)
435 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
437 TRACE("EndPagePrinter(%p)\n", hPrinter
);
442 dwErrorCode
= ERROR_INVALID_HANDLE
;
446 if (pHandle
->hSPLFile
!= INVALID_HANDLE_VALUE
)
448 // For spooled jobs, we don't need to do anything.
449 dwErrorCode
= ERROR_SUCCESS
;
453 // In all other cases, just call _RpcEndPagePrinter.
456 dwErrorCode
= _RpcEndPagePrinter(pHandle
->hPrinter
);
458 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
460 dwErrorCode
= RpcExceptionCode();
461 ERR("_RpcEndPagePrinter failed with exception code %lu!\n", dwErrorCode
);
467 SetLastError(dwErrorCode
);
468 return (dwErrorCode
== ERROR_SUCCESS
);
472 EnumPrintersA(DWORD Flags
, PSTR Name
, DWORD Level
, PBYTE pPrinterEnum
, DWORD cbBuf
, PDWORD pcbNeeded
, PDWORD pcReturned
)
474 BOOL bReturnValue
= FALSE
;
476 PWSTR pwszName
= NULL
;
477 PSTR pszPrinterName
= NULL
;
478 PSTR pszServerName
= NULL
;
479 PSTR pszDescription
= NULL
;
481 PSTR pszComment
= NULL
;
482 PSTR pszShareName
= NULL
;
483 PSTR pszPortName
= NULL
;
484 PSTR pszDriverName
= NULL
;
485 PSTR pszLocation
= NULL
;
486 PSTR pszSepFile
= NULL
;
487 PSTR pszPrintProcessor
= NULL
;
488 PSTR pszDatatype
= NULL
;
489 PSTR pszParameters
= NULL
;
491 PPRINTER_INFO_1W ppi1w
= NULL
;
492 PPRINTER_INFO_1A ppi1a
= NULL
;
493 PPRINTER_INFO_2W ppi2w
= NULL
;
494 PPRINTER_INFO_2A ppi2a
= NULL
;
495 PPRINTER_INFO_4W ppi4w
= NULL
;
496 PPRINTER_INFO_4A ppi4a
= NULL
;
497 PPRINTER_INFO_5W ppi5w
= NULL
;
498 PPRINTER_INFO_5A ppi5a
= NULL
;
500 TRACE("EnumPrintersA(%lu, %s, %lu, %p, %lu, %p, %p)\n", Flags
, Name
, Level
, pPrinterEnum
, cbBuf
, pcbNeeded
, pcReturned
);
502 // Check for invalid levels here for early error return. MSDN says that only 1, 2, 4, and 5 are allowable.
503 if (Level
!= 1 && Level
!= 2 && Level
!= 4 && Level
!= 5)
505 SetLastError(ERROR_INVALID_LEVEL
);
506 ERR("Invalid Level!\n");
512 // Convert pName to a Unicode string pwszName.
515 pwszName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
518 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
519 ERR("HeapAlloc failed!\n");
523 MultiByteToWideChar(CP_ACP
, 0, Name
, -1, pwszName
, cch
+ 1);
526 /* Ref: https://stackoverflow.com/questions/41147180/why-enumprintersa-and-enumprintersw-request-the-same-amount-of-memory */
527 bReturnValue
= EnumPrintersW(Flags
, pwszName
, Level
, pPrinterEnum
, cbBuf
, pcbNeeded
, pcReturned
);
528 HeapFree(hProcessHeap
, 0, pwszName
);
530 TRACE("*pcReturned is '%d' and bReturnValue is '%d' and GetLastError is '%ld'.\n", *pcReturned
, bReturnValue
, GetLastError());
532 /* We are mapping multiple different pointers to the same pPrinterEnum pointer here so that */
533 /* we can do in-place conversion. We read the Unicode response from the EnumPrintersW and */
534 /* then we write back the ANSI conversion into the same buffer for our EnumPrintersA output */
536 /* mapping to pPrinterEnum for Unicode (w) characters for Levels 1, 2, 4, and 5 */
537 ppi1w
= (PPRINTER_INFO_1W
)pPrinterEnum
;
538 ppi2w
= (PPRINTER_INFO_2W
)pPrinterEnum
;
539 ppi4w
= (PPRINTER_INFO_4W
)pPrinterEnum
;
540 ppi5w
= (PPRINTER_INFO_5W
)pPrinterEnum
;
541 /* mapping to pPrinterEnum for ANSI (a) characters for Levels 1, 2, 4, and 5 */
542 ppi1a
= (PPRINTER_INFO_1A
)pPrinterEnum
;
543 ppi2a
= (PPRINTER_INFO_2A
)pPrinterEnum
;
544 ppi4a
= (PPRINTER_INFO_4A
)pPrinterEnum
;
545 ppi5a
= (PPRINTER_INFO_5A
)pPrinterEnum
;
547 for (i
= 0; i
< *pcReturned
; i
++)
553 if (ppi1w
[i
].pDescription
)
555 // Convert Unicode pDescription to a ANSI string pszDescription.
556 cch
= wcslen(ppi1w
[i
].pDescription
);
558 pszDescription
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
561 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
562 ERR("HeapAlloc failed!\n");
566 WideCharToMultiByte(CP_ACP
, 0, ppi1w
[i
].pDescription
, -1, pszDescription
, cch
+ 1, NULL
, NULL
);
567 StringCchCopyA(ppi1a
[i
].pDescription
, cch
+ 1, pszDescription
);
569 HeapFree(hProcessHeap
, 0, pszDescription
);
574 // Convert Unicode pName to a ANSI string pszName.
575 cch
= wcslen(ppi1w
[i
].pName
);
577 pszName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
580 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
581 ERR("HeapAlloc failed!\n");
585 WideCharToMultiByte(CP_ACP
, 0, ppi1w
[i
].pName
, -1, pszName
, cch
+ 1, NULL
, NULL
);
586 StringCchCopyA(ppi1a
[i
].pName
, cch
+ 1, pszName
);
588 HeapFree(hProcessHeap
, 0, pszName
);
591 if (ppi1w
[i
].pComment
)
593 // Convert Unicode pComment to a ANSI string pszComment.
594 cch
= wcslen(ppi1w
[i
].pComment
);
596 pszComment
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
599 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
600 ERR("HeapAlloc failed!\n");
604 WideCharToMultiByte(CP_ACP
, 0, ppi1w
[i
].pComment
, -1, pszComment
, cch
+ 1, NULL
, NULL
);
605 StringCchCopyA(ppi1a
[i
].pComment
, cch
+ 1, pszComment
);
607 HeapFree(hProcessHeap
, 0, pszComment
);
615 if (ppi2w
[i
].pServerName
)
617 // Convert Unicode pServerName to a ANSI string pszServerName.
618 cch
= wcslen(ppi2w
[i
].pServerName
);
620 pszServerName
= 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
].pServerName
, -1, pszServerName
, cch
+ 1, NULL
, NULL
);
629 StringCchCopyA(ppi2a
[i
].pServerName
, cch
+ 1, pszServerName
);
631 HeapFree(hProcessHeap
, 0, pszServerName
);
634 if (ppi2w
[i
].pPrinterName
)
636 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
637 cch
= wcslen(ppi2w
[i
].pPrinterName
);
639 pszPrinterName
= 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
].pPrinterName
, -1, pszPrinterName
, cch
+ 1, NULL
, NULL
);
648 StringCchCopyA(ppi2a
[i
].pPrinterName
, cch
+ 1, pszPrinterName
);
650 HeapFree(hProcessHeap
, 0, pszPrinterName
);
653 if (ppi2w
[i
].pShareName
)
655 // Convert Unicode pShareName to a ANSI string pszShareName.
656 cch
= wcslen(ppi2w
[i
].pShareName
);
658 pszShareName
= 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
].pShareName
, -1, pszShareName
, cch
+ 1, NULL
, NULL
);
667 StringCchCopyA(ppi2a
[i
].pShareName
, cch
+ 1, pszShareName
);
669 HeapFree(hProcessHeap
, 0, pszShareName
);
672 if (ppi2w
[i
].pPortName
)
674 // Convert Unicode pPortName to a ANSI string pszPortName.
675 cch
= wcslen(ppi2w
[i
].pPortName
);
677 pszPortName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
680 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
681 ERR("HeapAlloc failed!\n");
685 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pPortName
, -1, pszPortName
, cch
+ 1, NULL
, NULL
);
686 StringCchCopyA(ppi2a
[i
].pPortName
, cch
+ 1, pszPortName
);
688 HeapFree(hProcessHeap
, 0, pszPortName
);
691 if (ppi2w
[i
].pDriverName
)
693 // Convert Unicode pDriverName to a ANSI string pszDriverName.
694 cch
= wcslen(ppi2w
[i
].pDriverName
);
696 pszDriverName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
699 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
700 ERR("HeapAlloc failed!\n");
704 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pDriverName
, -1, pszDriverName
, cch
+ 1, NULL
, NULL
);
705 StringCchCopyA(ppi2a
[i
].pDriverName
, cch
+ 1, pszDriverName
);
707 HeapFree(hProcessHeap
, 0, pszDriverName
);
710 if (ppi2w
[i
].pComment
)
712 // Convert Unicode pComment to a ANSI string pszComment.
713 cch
= wcslen(ppi2w
[i
].pComment
);
715 pszComment
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
718 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
719 ERR("HeapAlloc failed!\n");
723 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pComment
, -1, pszComment
, cch
+ 1, NULL
, NULL
);
724 StringCchCopyA(ppi2a
[i
].pComment
, cch
+ 1, pszComment
);
726 HeapFree(hProcessHeap
, 0, pszComment
);
729 if (ppi2w
[i
].pLocation
)
731 // Convert Unicode pLocation to a ANSI string pszLocation.
732 cch
= wcslen(ppi2w
[i
].pLocation
);
734 pszLocation
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
737 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
738 ERR("HeapAlloc failed!\n");
742 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pLocation
, -1, pszLocation
, cch
+ 1, NULL
, NULL
);
743 StringCchCopyA(ppi2a
[i
].pLocation
, cch
+ 1, pszLocation
);
745 HeapFree(hProcessHeap
, 0, pszLocation
);
749 if (ppi2w
[i
].pSepFile
)
751 // Convert Unicode pSepFile to a ANSI string pszSepFile.
752 cch
= wcslen(ppi2w
[i
].pSepFile
);
754 pszSepFile
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
757 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
758 ERR("HeapAlloc failed!\n");
762 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pSepFile
, -1, pszSepFile
, cch
+ 1, NULL
, NULL
);
763 StringCchCopyA(ppi2a
[i
].pSepFile
, cch
+ 1, pszSepFile
);
765 HeapFree(hProcessHeap
, 0, pszSepFile
);
768 if (ppi2w
[i
].pPrintProcessor
)
770 // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor.
771 cch
= wcslen(ppi2w
[i
].pPrintProcessor
);
773 pszPrintProcessor
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
774 if (!pszPrintProcessor
)
776 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
777 ERR("HeapAlloc failed!\n");
781 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pPrintProcessor
, -1, pszPrintProcessor
, cch
+ 1, NULL
, NULL
);
782 StringCchCopyA(ppi2a
[i
].pPrintProcessor
, cch
+ 1, pszPrintProcessor
);
784 HeapFree(hProcessHeap
, 0, pszPrintProcessor
);
788 if (ppi2w
[i
].pDatatype
)
790 // Convert Unicode pDatatype to a ANSI string pszDatatype.
791 cch
= wcslen(ppi2w
[i
].pDatatype
);
793 pszDatatype
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
796 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
797 ERR("HeapAlloc failed!\n");
801 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pDatatype
, -1, pszDatatype
, cch
+ 1, NULL
, NULL
);
802 StringCchCopyA(ppi2a
[i
].pDatatype
, cch
+ 1, pszDatatype
);
804 HeapFree(hProcessHeap
, 0, pszDatatype
);
807 if (ppi2w
[i
].pParameters
)
809 // Convert Unicode pParameters to a ANSI string pszParameters.
810 cch
= wcslen(ppi2w
[i
].pParameters
);
812 pszParameters
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
815 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
816 ERR("HeapAlloc failed!\n");
820 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pParameters
, -1, pszParameters
, cch
+ 1, NULL
, NULL
);
821 StringCchCopyA(ppi2a
[i
].pParameters
, cch
+ 1, pszParameters
);
823 HeapFree(hProcessHeap
, 0, pszParameters
);
831 if (ppi4w
[i
].pPrinterName
)
833 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
834 cch
= wcslen(ppi4w
[i
].pPrinterName
);
836 pszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
839 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
840 ERR("HeapAlloc failed!\n");
844 WideCharToMultiByte(CP_ACP
, 0, ppi4w
[i
].pPrinterName
, -1, pszPrinterName
, cch
+ 1, NULL
, NULL
);
845 StringCchCopyA(ppi4a
[i
].pPrinterName
, cch
+ 1, pszPrinterName
);
847 HeapFree(hProcessHeap
, 0, pszPrinterName
);
850 if (ppi4w
[i
].pServerName
)
852 // Convert Unicode pServerName to a ANSI string pszServerName.
853 cch
= wcslen(ppi4w
[i
].pServerName
);
855 pszServerName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
858 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
859 ERR("HeapAlloc failed!\n");
863 WideCharToMultiByte(CP_ACP
, 0, ppi4w
[i
].pServerName
, -1, pszServerName
, cch
+ 1, NULL
, NULL
);
864 StringCchCopyA(ppi4a
[i
].pServerName
, cch
+ 1, pszServerName
);
866 HeapFree(hProcessHeap
, 0, pszServerName
);
873 if (ppi5w
[i
].pPrinterName
)
875 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
876 cch
= wcslen(ppi5w
[i
].pPrinterName
);
878 pszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
881 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
882 ERR("HeapAlloc failed!\n");
886 WideCharToMultiByte(CP_ACP
, 0, ppi5w
[i
].pPrinterName
, -1, pszPrinterName
, cch
+ 1, NULL
, NULL
);
887 StringCchCopyA(ppi5a
[i
].pPrinterName
, cch
+ 1, pszPrinterName
);
889 HeapFree(hProcessHeap
, 0, pszPrinterName
);
892 if (ppi5w
[i
].pPortName
)
894 // Convert Unicode pPortName to a ANSI string pszPortName.
895 cch
= wcslen(ppi5w
[i
].pPortName
);
897 pszPortName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
900 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
901 ERR("HeapAlloc failed!\n");
905 WideCharToMultiByte(CP_ACP
, 0, ppi5w
[i
].pPortName
, -1, pszPortName
, cch
+ 1, NULL
, NULL
);
906 StringCchCopyA(ppi5a
[i
].pPortName
, cch
+ 1, pszPortName
);
908 HeapFree(hProcessHeap
, 0, pszPortName
);
922 EnumPrintersW(DWORD Flags
, PWSTR Name
, DWORD Level
, PBYTE pPrinterEnum
, DWORD cbBuf
, PDWORD pcbNeeded
, PDWORD pcReturned
)
926 TRACE("EnumPrintersW(%lu, %S, %lu, %p, %lu, %p, %p)\n", Flags
, Name
, Level
, pPrinterEnum
, cbBuf
, pcbNeeded
, pcReturned
);
928 // Dismiss invalid levels already at this point.
929 if (Level
== 3 || Level
> 5)
931 dwErrorCode
= ERROR_INVALID_LEVEL
;
935 if (cbBuf
&& pPrinterEnum
)
936 ZeroMemory(pPrinterEnum
, cbBuf
);
941 dwErrorCode
= _RpcEnumPrinters(Flags
, Name
, Level
, pPrinterEnum
, cbBuf
, pcbNeeded
, pcReturned
);
943 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
945 dwErrorCode
= RpcExceptionCode();
946 ERR("_RpcEnumPrinters failed with exception code %lu!\n", dwErrorCode
);
950 if (dwErrorCode
== ERROR_SUCCESS
)
952 // Replace relative offset addresses in the output by absolute pointers.
954 MarshallUpStructuresArray(cbBuf
, pPrinterEnum
, *pcReturned
, pPrinterInfoMarshalling
[Level
]->pInfo
, pPrinterInfoMarshalling
[Level
]->cbStructureSize
, TRUE
);
958 SetLastError(dwErrorCode
);
959 return (dwErrorCode
== ERROR_SUCCESS
);
963 FlushPrinter(HANDLE hPrinter
, PVOID pBuf
, DWORD cbBuf
, PDWORD pcWritten
, DWORD cSleep
)
965 TRACE("FlushPrinter(%p, %p, %lu, %p, %lu)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
, cSleep
);
971 GetDefaultPrinterA(LPSTR pszBuffer
, LPDWORD pcchBuffer
)
974 PWSTR pwszBuffer
= NULL
;
976 TRACE("GetDefaultPrinterA(%p, %p)\n", pszBuffer
, pcchBuffer
);
981 dwErrorCode
= ERROR_INVALID_PARAMETER
;
985 // Check if an ANSI buffer was given and if so, allocate a Unicode buffer of the same size.
986 if (pszBuffer
&& *pcchBuffer
)
988 pwszBuffer
= HeapAlloc(hProcessHeap
, 0, *pcchBuffer
* sizeof(WCHAR
));
991 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
992 ERR("HeapAlloc failed!\n");
997 if (!GetDefaultPrinterW(pwszBuffer
, pcchBuffer
))
999 dwErrorCode
= GetLastError();
1003 // We successfully got a string in pwszBuffer, so convert the Unicode string to ANSI.
1004 WideCharToMultiByte(CP_ACP
, 0, pwszBuffer
, -1, pszBuffer
, *pcchBuffer
, NULL
, NULL
);
1006 dwErrorCode
= ERROR_SUCCESS
;
1010 HeapFree(hProcessHeap
, 0, pwszBuffer
);
1012 SetLastError(dwErrorCode
);
1013 return (dwErrorCode
== ERROR_SUCCESS
);
1017 GetDefaultPrinterW(LPWSTR pszBuffer
, LPDWORD pcchBuffer
)
1020 DWORD cchInputBuffer
;
1022 HKEY hWindowsKey
= NULL
;
1023 PWSTR pwszDevice
= NULL
;
1026 TRACE("GetDefaultPrinterW(%p, %p)\n", pszBuffer
, pcchBuffer
);
1031 dwErrorCode
= ERROR_INVALID_PARAMETER
;
1035 cchInputBuffer
= *pcchBuffer
;
1037 // Open the registry key where the default printer for the current user is stored.
1038 dwErrorCode
= (DWORD
)RegOpenKeyExW(HKEY_CURRENT_USER
, wszWindowsKey
, 0, KEY_READ
, &hWindowsKey
);
1039 if (dwErrorCode
!= ERROR_SUCCESS
)
1041 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode
);
1045 // Determine the size of the required buffer.
1046 dwErrorCode
= (DWORD
)RegQueryValueExW(hWindowsKey
, wszDeviceValue
, NULL
, NULL
, NULL
, &cbNeeded
);
1047 if (dwErrorCode
!= ERROR_SUCCESS
)
1049 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode
);
1054 pwszDevice
= HeapAlloc(hProcessHeap
, 0, cbNeeded
);
1057 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1058 ERR("HeapAlloc failed!\n");
1062 // Now get the actual value.
1063 dwErrorCode
= RegQueryValueExW(hWindowsKey
, wszDeviceValue
, NULL
, NULL
, (PBYTE
)pwszDevice
, &cbNeeded
);
1064 if (dwErrorCode
!= ERROR_SUCCESS
)
1066 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode
);
1070 // We get a string "<Printer Name>,winspool,<Port>:".
1071 // Extract the printer name from it.
1072 pwszComma
= wcschr(pwszDevice
, L
',');
1075 ERR("Found no or invalid default printer: %S!\n", pwszDevice
);
1076 dwErrorCode
= ERROR_INVALID_NAME
;
1080 // Store the length of the Printer Name (including the terminating NUL character!) in *pcchBuffer.
1081 *pcchBuffer
= pwszComma
- pwszDevice
+ 1;
1083 // Check if the supplied buffer is large enough.
1084 if (cchInputBuffer
< *pcchBuffer
)
1086 dwErrorCode
= ERROR_INSUFFICIENT_BUFFER
;
1090 // Copy the default printer.
1092 CopyMemory(pszBuffer
, pwszDevice
, *pcchBuffer
* sizeof(WCHAR
));
1094 dwErrorCode
= ERROR_SUCCESS
;
1098 RegCloseKey(hWindowsKey
);
1101 HeapFree(hProcessHeap
, 0, pwszDevice
);
1103 SetLastError(dwErrorCode
);
1104 return (dwErrorCode
== ERROR_SUCCESS
);
1108 GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1110 PPRINTER_INFO_1A ppi1a
= (PPRINTER_INFO_1A
)pPrinter
;
1111 PPRINTER_INFO_1W ppi1w
= (PPRINTER_INFO_1W
)pPrinter
;
1112 PPRINTER_INFO_2A ppi2a
= (PPRINTER_INFO_2A
)pPrinter
;
1113 PPRINTER_INFO_2W ppi2w
= (PPRINTER_INFO_2W
)pPrinter
;
1114 PPRINTER_INFO_4A ppi4a
= (PPRINTER_INFO_4A
)pPrinter
;
1115 PPRINTER_INFO_4W ppi4w
= (PPRINTER_INFO_4W
)pPrinter
;
1116 PPRINTER_INFO_5A ppi5a
= (PPRINTER_INFO_5A
)pPrinter
;
1117 PPRINTER_INFO_5W ppi5w
= (PPRINTER_INFO_5W
)pPrinter
;
1118 PPRINTER_INFO_7A ppi7a
= (PPRINTER_INFO_7A
)pPrinter
;
1119 PPRINTER_INFO_7W ppi7w
= (PPRINTER_INFO_7W
)pPrinter
;
1121 BOOL bReturnValue
= FALSE
;
1123 TRACE("GetPrinterA(%p, %lu, %p, %lu, %p)\n", hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
);
1125 // Check for invalid levels here for early error return. Should be 1-9.
1126 if (Level
< 1 || Level
> 9)
1128 SetLastError(ERROR_INVALID_LEVEL
);
1129 ERR("Invalid Level!\n");
1133 bReturnValue
= GetPrinterW(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
);
1137 TRACE("GetPrinterW failed!\n");
1145 if (ppi1w
->pDescription
)
1147 PSTR pszDescription
;
1149 // Convert Unicode pDescription to a ANSI string pszDescription.
1150 cch
= wcslen(ppi1w
->pDescription
);
1152 pszDescription
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1153 if (!pszDescription
)
1155 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1156 ERR("HeapAlloc failed!\n");
1160 WideCharToMultiByte(CP_ACP
, 0, ppi1w
->pDescription
, -1, pszDescription
, cch
+ 1, NULL
, NULL
);
1161 StringCchCopyA(ppi1a
->pDescription
, cch
+ 1, pszDescription
);
1163 HeapFree(hProcessHeap
, 0, pszDescription
);
1170 // Convert Unicode pName to a ANSI string pszName.
1171 cch
= wcslen(ppi1w
->pName
);
1173 pszName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1176 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1177 ERR("HeapAlloc failed!\n");
1181 WideCharToMultiByte(CP_ACP
, 0, ppi1w
->pName
, -1, pszName
, cch
+ 1, NULL
, NULL
);
1182 StringCchCopyA(ppi1a
->pName
, cch
+ 1, pszName
);
1184 HeapFree(hProcessHeap
, 0, pszName
);
1187 if (ppi1w
->pComment
)
1191 // Convert Unicode pComment to a ANSI string pszComment.
1192 cch
= wcslen(ppi1w
->pComment
);
1194 pszComment
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1197 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1198 ERR("HeapAlloc failed!\n");
1202 WideCharToMultiByte(CP_ACP
, 0, ppi1w
->pComment
, -1, pszComment
, cch
+ 1, NULL
, NULL
);
1203 StringCchCopyA(ppi1a
->pComment
, cch
+ 1, pszComment
);
1205 HeapFree(hProcessHeap
, 0, pszComment
);
1212 if (ppi2w
->pServerName
)
1216 // Convert Unicode pServerName to a ANSI string pszServerName.
1217 cch
= wcslen(ppi2w
->pServerName
);
1219 pszServerName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1222 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1223 ERR("HeapAlloc failed!\n");
1227 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pServerName
, -1, pszServerName
, cch
+ 1, NULL
, NULL
);
1228 StringCchCopyA(ppi2a
->pServerName
, cch
+ 1, pszServerName
);
1230 HeapFree(hProcessHeap
, 0, pszServerName
);
1233 if (ppi2w
->pPrinterName
)
1235 PSTR pszPrinterName
;
1237 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
1238 cch
= wcslen(ppi2w
->pPrinterName
);
1240 pszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1241 if (!pszPrinterName
)
1243 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1244 ERR("HeapAlloc failed!\n");
1248 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pPrinterName
, -1, pszPrinterName
, cch
+ 1, NULL
, NULL
);
1249 StringCchCopyA(ppi2a
->pPrinterName
, cch
+ 1, pszPrinterName
);
1251 HeapFree(hProcessHeap
, 0, pszPrinterName
);
1254 if (ppi2w
->pShareName
)
1258 // Convert Unicode pShareName to a ANSI string pszShareName.
1259 cch
= wcslen(ppi2w
->pShareName
);
1261 pszShareName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1264 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1265 ERR("HeapAlloc failed!\n");
1269 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pShareName
, -1, pszShareName
, cch
+ 1, NULL
, NULL
);
1270 StringCchCopyA(ppi2a
->pShareName
, cch
+ 1, pszShareName
);
1272 HeapFree(hProcessHeap
, 0, pszShareName
);
1275 if (ppi2w
->pPortName
)
1279 // Convert Unicode pPortName to a ANSI string pszPortName.
1280 cch
= wcslen(ppi2w
->pPortName
);
1282 pszPortName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1285 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1286 ERR("HeapAlloc failed!\n");
1290 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pPortName
, -1, pszPortName
, cch
+ 1, NULL
, NULL
);
1291 StringCchCopyA(ppi2a
->pPortName
, cch
+ 1, pszPortName
);
1293 HeapFree(hProcessHeap
, 0, pszPortName
);
1296 if (ppi2w
->pDriverName
)
1300 // Convert Unicode pDriverName to a ANSI string pszDriverName.
1301 cch
= wcslen(ppi2w
->pDriverName
);
1303 pszDriverName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1306 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1307 ERR("HeapAlloc failed!\n");
1311 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pDriverName
, -1, pszDriverName
, cch
+ 1, NULL
, NULL
);
1312 StringCchCopyA(ppi2a
->pDriverName
, cch
+ 1, pszDriverName
);
1314 HeapFree(hProcessHeap
, 0, pszDriverName
);
1317 if (ppi2w
->pComment
)
1321 // Convert Unicode pComment to a ANSI string pszComment.
1322 cch
= wcslen(ppi2w
->pComment
);
1324 pszComment
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1327 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1328 ERR("HeapAlloc failed!\n");
1332 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pComment
, -1, pszComment
, cch
+ 1, NULL
, NULL
);
1333 StringCchCopyA(ppi2a
->pComment
, cch
+ 1, pszComment
);
1335 HeapFree(hProcessHeap
, 0, pszComment
);
1338 if (ppi2w
->pLocation
)
1342 // Convert Unicode pLocation to a ANSI string pszLocation.
1343 cch
= wcslen(ppi2w
->pLocation
);
1345 pszLocation
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1348 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1349 ERR("HeapAlloc failed!\n");
1353 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pLocation
, -1, pszLocation
, cch
+ 1, NULL
, NULL
);
1354 StringCchCopyA(ppi2a
->pLocation
, cch
+ 1, pszLocation
);
1356 HeapFree(hProcessHeap
, 0, pszLocation
);
1359 if (ppi2w
->pSepFile
)
1363 // Convert Unicode pSepFile to a ANSI string pszSepFile.
1364 cch
= wcslen(ppi2w
->pSepFile
);
1366 pszSepFile
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1369 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1370 ERR("HeapAlloc failed!\n");
1374 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pSepFile
, -1, pszSepFile
, cch
+ 1, NULL
, NULL
);
1375 StringCchCopyA(ppi2a
->pSepFile
, cch
+ 1, pszSepFile
);
1377 HeapFree(hProcessHeap
, 0, pszSepFile
);
1380 if (ppi2w
->pPrintProcessor
)
1382 PSTR pszPrintProcessor
;
1384 // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor.
1385 cch
= wcslen(ppi2w
->pPrintProcessor
);
1387 pszPrintProcessor
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1388 if (!pszPrintProcessor
)
1390 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1391 ERR("HeapAlloc failed!\n");
1395 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pPrintProcessor
, -1, pszPrintProcessor
, cch
+ 1, NULL
, NULL
);
1396 StringCchCopyA(ppi2a
->pPrintProcessor
, cch
+ 1, pszPrintProcessor
);
1398 HeapFree(hProcessHeap
, 0, pszPrintProcessor
);
1401 if (ppi2w
->pDatatype
)
1405 // Convert Unicode pDatatype to a ANSI string pszDatatype.
1406 cch
= wcslen(ppi2w
->pDatatype
);
1408 pszDatatype
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1411 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1412 ERR("HeapAlloc failed!\n");
1416 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pDatatype
, -1, pszDatatype
, cch
+ 1, NULL
, NULL
);
1417 StringCchCopyA(ppi2a
->pDatatype
, cch
+ 1, pszDatatype
);
1419 HeapFree(hProcessHeap
, 0, pszDatatype
);
1422 if (ppi2w
->pParameters
)
1426 // Convert Unicode pParameters to a ANSI string pszParameters.
1427 cch
= wcslen(ppi2w
->pParameters
);
1429 pszParameters
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1432 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1433 ERR("HeapAlloc failed!\n");
1437 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pParameters
, -1, pszParameters
, cch
+ 1, NULL
, NULL
);
1438 StringCchCopyA(ppi2a
->pParameters
, cch
+ 1, pszParameters
);
1440 HeapFree(hProcessHeap
, 0, pszParameters
);
1447 if (ppi4w
->pPrinterName
)
1449 PSTR pszPrinterName
;
1451 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
1452 cch
= wcslen(ppi4w
->pPrinterName
);
1454 pszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1455 if (!pszPrinterName
)
1457 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1458 ERR("HeapAlloc failed!\n");
1462 WideCharToMultiByte(CP_ACP
, 0, ppi4w
->pPrinterName
, -1, pszPrinterName
, cch
+ 1, NULL
, NULL
);
1463 StringCchCopyA(ppi4a
->pPrinterName
, cch
+ 1, pszPrinterName
);
1465 HeapFree(hProcessHeap
, 0, pszPrinterName
);
1468 if (ppi4w
->pServerName
)
1472 // Convert Unicode pServerName to a ANSI string pszServerName.
1473 cch
= wcslen(ppi4w
->pServerName
);
1475 pszServerName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1478 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1479 ERR("HeapAlloc failed!\n");
1483 WideCharToMultiByte(CP_ACP
, 0, ppi4w
->pServerName
, -1, pszServerName
, cch
+ 1, NULL
, NULL
);
1484 StringCchCopyA(ppi4a
->pServerName
, cch
+ 1, pszServerName
);
1486 HeapFree(hProcessHeap
, 0, pszServerName
);
1493 if (ppi5w
->pPrinterName
)
1495 PSTR pszPrinterName
;
1497 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
1498 cch
= wcslen(ppi5w
->pPrinterName
);
1500 pszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1501 if (!pszPrinterName
)
1503 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1504 ERR("HeapAlloc failed!\n");
1508 WideCharToMultiByte(CP_ACP
, 0, ppi5w
->pPrinterName
, -1, pszPrinterName
, cch
+ 1, NULL
, NULL
);
1509 StringCchCopyA(ppi5a
->pPrinterName
, cch
+ 1, pszPrinterName
);
1511 HeapFree(hProcessHeap
, 0, pszPrinterName
);
1514 if (ppi5w
->pPortName
)
1518 // Convert Unicode pPortName to a ANSI string pszPortName.
1519 cch
= wcslen(ppi5w
->pPortName
);
1521 pszPortName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1524 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1525 ERR("HeapAlloc failed!\n");
1529 WideCharToMultiByte(CP_ACP
, 0, ppi5w
->pPortName
, -1, pszPortName
, cch
+ 1, NULL
, NULL
);
1530 StringCchCopyA(ppi5a
->pPortName
, cch
+ 1, pszPortName
);
1532 HeapFree(hProcessHeap
, 0, pszPortName
);
1539 if (ppi7w
->pszObjectGUID
)
1541 PSTR pszaObjectGUID
;
1543 // Convert Unicode pszObjectGUID to a ANSI string pszaObjectGUID.
1544 cch
= wcslen(ppi7w
->pszObjectGUID
);
1546 pszaObjectGUID
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1547 if (!pszaObjectGUID
)
1549 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1550 ERR("HeapAlloc failed!\n");
1554 WideCharToMultiByte(CP_ACP
, 0, ppi7w
->pszObjectGUID
, -1, pszaObjectGUID
, cch
+ 1, NULL
, NULL
);
1555 StringCchCopyA(ppi7a
->pszObjectGUID
, cch
+ 1, pszaObjectGUID
);
1557 HeapFree(hProcessHeap
, 0, pszaObjectGUID
);
1564 return bReturnValue
;
1568 GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
, DWORD Level
, LPBYTE pDriverInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1571 * We are mapping multiple different pointers to the same pDriverInfo pointer here so that
1572 * we can use the same incoming pointer for different Levels
1574 PDRIVER_INFO_1W pdi1w
= (PDRIVER_INFO_1W
)pDriverInfo
;
1575 PDRIVER_INFO_2W pdi2w
= (PDRIVER_INFO_2W
)pDriverInfo
;
1576 PDRIVER_INFO_3W pdi3w
= (PDRIVER_INFO_3W
)pDriverInfo
;
1577 PDRIVER_INFO_4W pdi4w
= (PDRIVER_INFO_4W
)pDriverInfo
;
1578 PDRIVER_INFO_5W pdi5w
= (PDRIVER_INFO_5W
)pDriverInfo
;
1579 PDRIVER_INFO_6W pdi6w
= (PDRIVER_INFO_6W
)pDriverInfo
;
1581 BOOL bReturnValue
= FALSE
;
1583 PWSTR pwszEnvironment
= NULL
;
1585 TRACE("GetPrinterDriverA(%p, %s, %lu, %p, %lu, %p)\n", hPrinter
, pEnvironment
, Level
, pDriverInfo
, cbBuf
, pcbNeeded
);
1587 // Check for invalid levels here for early error return. Should be 1-6.
1588 if (Level
< 1 || Level
> 6)
1590 SetLastError(ERROR_INVALID_LEVEL
);
1591 ERR("Invalid Level!\n");
1597 // Convert pEnvironment to a Unicode string pwszEnvironment.
1598 cch
= strlen(pEnvironment
);
1600 pwszEnvironment
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
1601 if (!pwszEnvironment
)
1603 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1604 ERR("HeapAlloc failed!\n");
1608 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, pwszEnvironment
, cch
+ 1);
1611 bReturnValue
= GetPrinterDriverW(hPrinter
, pwszEnvironment
, Level
, pDriverInfo
, cbBuf
, pcbNeeded
);
1612 TRACE("*pcbNeeded is '%d' and bReturnValue is '%d' and GetLastError is '%ld'.\n", *pcbNeeded
, bReturnValue
, GetLastError());
1614 if (pwszEnvironment
)
1616 HeapFree(hProcessHeap
, 0, pwszEnvironment
);
1621 TRACE("GetPrinterDriverW failed!\n");
1625 // Do Unicode to ANSI conversions for strings based on Level
1630 if (!UnicodeToAnsiInPlace(pdi1w
->pName
))
1638 if (!UnicodeToAnsiInPlace(pdi2w
->pName
))
1641 if (!UnicodeToAnsiInPlace(pdi2w
->pEnvironment
))
1644 if (!UnicodeToAnsiInPlace(pdi2w
->pDriverPath
))
1647 if (!UnicodeToAnsiInPlace(pdi2w
->pDataFile
))
1650 if (!UnicodeToAnsiInPlace(pdi2w
->pConfigFile
))
1658 if (!UnicodeToAnsiInPlace(pdi3w
->pName
))
1661 if (!UnicodeToAnsiInPlace(pdi3w
->pEnvironment
))
1664 if (!UnicodeToAnsiInPlace(pdi3w
->pDriverPath
))
1667 if (!UnicodeToAnsiInPlace(pdi3w
->pDataFile
))
1670 if (!UnicodeToAnsiInPlace(pdi3w
->pConfigFile
))
1673 if (!UnicodeToAnsiInPlace(pdi3w
->pHelpFile
))
1676 if (!UnicodeToAnsiInPlace(pdi3w
->pDependentFiles
))
1679 if (!UnicodeToAnsiInPlace(pdi3w
->pMonitorName
))
1682 if (!UnicodeToAnsiInPlace(pdi3w
->pDefaultDataType
))
1690 if (!UnicodeToAnsiInPlace(pdi4w
->pName
))
1693 if (!UnicodeToAnsiInPlace(pdi4w
->pEnvironment
))
1696 if (!UnicodeToAnsiInPlace(pdi4w
->pDriverPath
))
1699 if (!UnicodeToAnsiInPlace(pdi4w
->pDataFile
))
1702 if (!UnicodeToAnsiInPlace(pdi4w
->pConfigFile
))
1705 if (!UnicodeToAnsiInPlace(pdi4w
->pHelpFile
))
1708 if (!UnicodeToAnsiInPlace(pdi4w
->pDependentFiles
))
1711 if (!UnicodeToAnsiInPlace(pdi4w
->pMonitorName
))
1714 if (!UnicodeToAnsiInPlace(pdi4w
->pDefaultDataType
))
1717 if (!UnicodeToAnsiInPlace(pdi4w
->pszzPreviousNames
))
1725 if (!UnicodeToAnsiInPlace(pdi5w
->pName
))
1728 if (!UnicodeToAnsiInPlace(pdi5w
->pEnvironment
))
1731 if (!UnicodeToAnsiInPlace(pdi5w
->pDriverPath
))
1734 if (!UnicodeToAnsiInPlace(pdi5w
->pDataFile
))
1737 if (!UnicodeToAnsiInPlace(pdi5w
->pConfigFile
))
1745 if (!UnicodeToAnsiInPlace(pdi6w
->pName
))
1748 if (!UnicodeToAnsiInPlace(pdi6w
->pEnvironment
))
1751 if (!UnicodeToAnsiInPlace(pdi6w
->pDriverPath
))
1754 if (!UnicodeToAnsiInPlace(pdi6w
->pDataFile
))
1757 if (!UnicodeToAnsiInPlace(pdi6w
->pConfigFile
))
1760 if (!UnicodeToAnsiInPlace(pdi6w
->pHelpFile
))
1763 if (!UnicodeToAnsiInPlace(pdi6w
->pDependentFiles
))
1766 if (!UnicodeToAnsiInPlace(pdi6w
->pMonitorName
))
1769 if (!UnicodeToAnsiInPlace(pdi6w
->pDefaultDataType
))
1772 if (!UnicodeToAnsiInPlace(pdi6w
->pszzPreviousNames
))
1775 if (!UnicodeToAnsiInPlace(pdi6w
->pszMfgName
))
1778 if (!UnicodeToAnsiInPlace(pdi6w
->pszOEMUrl
))
1781 if (!UnicodeToAnsiInPlace(pdi6w
->pszHardwareID
))
1784 if (!UnicodeToAnsiInPlace(pdi6w
->pszProvider
))
1789 bReturnValue
= TRUE
;
1793 return bReturnValue
;
1797 GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
, DWORD Level
, LPBYTE pDriverInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1800 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
1802 TRACE("GetPrinterDriverW(%p, %S, %lu, %p, %lu, %p)\n", hPrinter
, pEnvironment
, Level
, pDriverInfo
, cbBuf
, pcbNeeded
);
1807 dwErrorCode
= ERROR_INVALID_HANDLE
;
1811 // Dismiss invalid levels already at this point.
1812 if (Level
> 8 || Level
< 1)
1814 dwErrorCode
= ERROR_INVALID_LEVEL
;
1818 if (cbBuf
&& pDriverInfo
)
1819 ZeroMemory(pDriverInfo
, cbBuf
);
1824 dwErrorCode
= _RpcGetPrinterDriver(pHandle
->hPrinter
, pEnvironment
, Level
, pDriverInfo
, cbBuf
, pcbNeeded
);
1826 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
1828 dwErrorCode
= RpcExceptionCode();
1829 ERR("_RpcGetPrinterDriver failed with exception code %lu!\n", dwErrorCode
);
1833 if (dwErrorCode
== ERROR_SUCCESS
)
1835 // Replace relative offset addresses in the output by absolute pointers.
1837 MarshallUpStructure(cbBuf
, pDriverInfo
, pPrinterDriverMarshalling
[Level
]->pInfo
, pPrinterDriverMarshalling
[Level
]->cbStructureSize
, TRUE
);
1841 SetLastError(dwErrorCode
);
1842 return (dwErrorCode
== ERROR_SUCCESS
);
1846 GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1849 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
1851 TRACE("GetPrinterW(%p, %lu, %p, %lu, %p)\n", hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
);
1856 dwErrorCode
= ERROR_INVALID_HANDLE
;
1860 // Dismiss invalid levels already at this point.
1863 dwErrorCode
= ERROR_INVALID_LEVEL
;
1867 if (cbBuf
&& pPrinter
)
1868 ZeroMemory(pPrinter
, cbBuf
);
1873 dwErrorCode
= _RpcGetPrinter(pHandle
->hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
);
1875 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
1877 dwErrorCode
= RpcExceptionCode();
1878 ERR("_RpcGetPrinter failed with exception code %lu!\n", dwErrorCode
);
1882 if (dwErrorCode
== ERROR_SUCCESS
)
1884 // Replace relative offset addresses in the output by absolute pointers.
1886 MarshallUpStructure(cbBuf
, pPrinter
, pPrinterInfoMarshalling
[Level
]->pInfo
, pPrinterInfoMarshalling
[Level
]->cbStructureSize
, TRUE
);
1890 SetLastError(dwErrorCode
);
1891 return (dwErrorCode
== ERROR_SUCCESS
);
1895 OpenPrinterA(LPSTR pPrinterName
, LPHANDLE phPrinter
, LPPRINTER_DEFAULTSA pDefault
)
1897 BOOL bReturnValue
= FALSE
;
1899 PWSTR pwszPrinterName
= NULL
;
1900 PRINTER_DEFAULTSW wDefault
= { 0 };
1902 TRACE("OpenPrinterA(%s, %p, %p)\n", pPrinterName
, phPrinter
, pDefault
);
1906 // Convert pPrinterName to a Unicode string pwszPrinterName
1907 cch
= strlen(pPrinterName
);
1909 pwszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
1910 if (!pwszPrinterName
)
1912 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1913 ERR("HeapAlloc failed!\n");
1917 MultiByteToWideChar(CP_ACP
, 0, pPrinterName
, -1, pwszPrinterName
, cch
+ 1);
1922 wDefault
.DesiredAccess
= pDefault
->DesiredAccess
;
1924 if (pDefault
->pDatatype
)
1926 // Convert pDefault->pDatatype to a Unicode string wDefault.pDatatype
1927 cch
= strlen(pDefault
->pDatatype
);
1929 wDefault
.pDatatype
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
1930 if (!wDefault
.pDatatype
)
1932 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1933 ERR("HeapAlloc failed!\n");
1937 MultiByteToWideChar(CP_ACP
, 0, pDefault
->pDatatype
, -1, wDefault
.pDatatype
, cch
+ 1);
1940 if (pDefault
->pDevMode
)
1941 wDefault
.pDevMode
= GdiConvertToDevmodeW(pDefault
->pDevMode
);
1944 bReturnValue
= OpenPrinterW(pwszPrinterName
, phPrinter
, &wDefault
);
1947 if (wDefault
.pDatatype
)
1948 HeapFree(hProcessHeap
, 0, wDefault
.pDatatype
);
1950 if (wDefault
.pDevMode
)
1951 HeapFree(hProcessHeap
, 0, wDefault
.pDevMode
);
1953 if (pwszPrinterName
)
1954 HeapFree(hProcessHeap
, 0, pwszPrinterName
);
1956 return bReturnValue
;
1960 OpenPrinterW(LPWSTR pPrinterName
, LPHANDLE phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
1964 PSPOOLER_HANDLE pHandle
;
1965 PWSTR pDatatype
= NULL
;
1966 WINSPOOL_DEVMODE_CONTAINER DevModeContainer
= { 0 };
1967 ACCESS_MASK AccessRequired
= 0;
1969 TRACE("OpenPrinterW(%S, %p, %p)\n", pPrinterName
, phPrinter
, pDefault
);
1974 dwErrorCode
= ERROR_INVALID_PARAMETER
;
1978 // Prepare the additional parameters in the format required by _RpcOpenPrinter
1981 pDatatype
= pDefault
->pDatatype
;
1982 DevModeContainer
.cbBuf
= sizeof(DEVMODEW
);
1983 DevModeContainer
.pDevMode
= (BYTE
*)pDefault
->pDevMode
;
1984 AccessRequired
= pDefault
->DesiredAccess
;
1990 dwErrorCode
= _RpcOpenPrinter(pPrinterName
, &hPrinter
, pDatatype
, &DevModeContainer
, AccessRequired
);
1992 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
1994 dwErrorCode
= RpcExceptionCode();
1995 ERR("_RpcOpenPrinter failed with exception code %lu!\n", dwErrorCode
);
1999 if (dwErrorCode
== ERROR_SUCCESS
)
2001 // Create a new SPOOLER_HANDLE structure.
2002 pHandle
= HeapAlloc(hProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(SPOOLER_HANDLE
));
2005 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2006 ERR("HeapAlloc failed!\n");
2010 pHandle
->hPrinter
= hPrinter
;
2011 pHandle
->hSPLFile
= INVALID_HANDLE_VALUE
;
2013 // Return it as phPrinter.
2014 *phPrinter
= (HANDLE
)pHandle
;
2018 SetLastError(dwErrorCode
);
2019 return (dwErrorCode
== ERROR_SUCCESS
);
2023 ReadPrinter(HANDLE hPrinter
, PVOID pBuf
, DWORD cbBuf
, PDWORD pNoBytesRead
)
2026 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
2028 TRACE("ReadPrinter(%p, %p, %lu, %p)\n", hPrinter
, pBuf
, cbBuf
, pNoBytesRead
);
2033 dwErrorCode
= ERROR_INVALID_HANDLE
;
2040 dwErrorCode
= _RpcReadPrinter(pHandle
->hPrinter
, pBuf
, cbBuf
, pNoBytesRead
);
2042 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
2044 dwErrorCode
= RpcExceptionCode();
2045 ERR("_RpcReadPrinter failed with exception code %lu!\n", dwErrorCode
);
2050 SetLastError(dwErrorCode
);
2051 return (dwErrorCode
== ERROR_SUCCESS
);
2055 ResetPrinterA(HANDLE hPrinter
, PPRINTER_DEFAULTSA pDefault
)
2057 TRACE("ResetPrinterA(%p, %p)\n", hPrinter
, pDefault
);
2063 ResetPrinterW(HANDLE hPrinter
, PPRINTER_DEFAULTSW pDefault
)
2065 TRACE("ResetPrinterW(%p, %p)\n", hPrinter
, pDefault
);
2071 SetDefaultPrinterA(LPCSTR pszPrinter
)
2073 BOOL bReturnValue
= FALSE
;
2075 PWSTR pwszPrinter
= NULL
;
2077 TRACE("SetDefaultPrinterA(%s)\n", pszPrinter
);
2081 // Convert pszPrinter to a Unicode string pwszPrinter
2082 cch
= strlen(pszPrinter
);
2084 pwszPrinter
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
2087 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2088 ERR("HeapAlloc failed!\n");
2092 MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, pwszPrinter
, cch
+ 1);
2095 bReturnValue
= SetDefaultPrinterW(pwszPrinter
);
2099 HeapFree(hProcessHeap
, 0, pwszPrinter
);
2101 return bReturnValue
;
2105 SetDefaultPrinterW(LPCWSTR pszPrinter
)
2107 const WCHAR wszDevicesKey
[] = L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Devices";
2109 DWORD cbDeviceValueData
;
2110 DWORD cbPrinterValueData
= 0;
2113 HKEY hDevicesKey
= NULL
;
2114 HKEY hWindowsKey
= NULL
;
2115 PWSTR pwszDeviceValueData
= NULL
;
2116 WCHAR wszPrinter
[MAX_PRINTER_NAME
+ 1];
2118 TRACE("SetDefaultPrinterW(%S)\n", pszPrinter
);
2120 // Open the Devices registry key.
2121 dwErrorCode
= (DWORD
)RegOpenKeyExW(HKEY_CURRENT_USER
, wszDevicesKey
, 0, KEY_READ
, &hDevicesKey
);
2122 if (dwErrorCode
!= ERROR_SUCCESS
)
2124 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode
);
2128 // Did the caller give us a printer to set as default?
2129 if (pszPrinter
&& *pszPrinter
)
2131 // Check if the given printer exists and query the value data size.
2132 dwErrorCode
= (DWORD
)RegQueryValueExW(hDevicesKey
, pszPrinter
, NULL
, NULL
, NULL
, &cbPrinterValueData
);
2133 if (dwErrorCode
== ERROR_FILE_NOT_FOUND
)
2135 dwErrorCode
= ERROR_INVALID_PRINTER_NAME
;
2138 else if (dwErrorCode
!= ERROR_SUCCESS
)
2140 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode
);
2144 cchPrinter
= wcslen(pszPrinter
);
2148 // If there is already a default printer, we're done!
2149 cchPrinter
= _countof(wszPrinter
);
2150 if (GetDefaultPrinterW(wszPrinter
, &cchPrinter
))
2152 dwErrorCode
= ERROR_SUCCESS
;
2156 // Otherwise, get us the first printer from the "Devices" key to later set it as default and query the value data size.
2157 cchPrinter
= _countof(wszPrinter
);
2158 dwErrorCode
= (DWORD
)RegEnumValueW(hDevicesKey
, 0, wszPrinter
, &cchPrinter
, NULL
, NULL
, NULL
, &cbPrinterValueData
);
2159 if (dwErrorCode
!= ERROR_MORE_DATA
)
2162 pszPrinter
= wszPrinter
;
2165 // We now need to query the value data, which has the format "winspool,<Port>:"
2166 // and make "<Printer Name>,winspool,<Port>:" out of it.
2167 // Allocate a buffer large enough for the final data.
2168 cbDeviceValueData
= (cchPrinter
+ 1) * sizeof(WCHAR
) + cbPrinterValueData
;
2169 pwszDeviceValueData
= HeapAlloc(hProcessHeap
, 0, cbDeviceValueData
);
2170 if (!pwszDeviceValueData
)
2172 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2173 ERR("HeapAlloc failed!\n");
2177 // Copy the Printer Name and a comma into it.
2178 CopyMemory(pwszDeviceValueData
, pszPrinter
, cchPrinter
* sizeof(WCHAR
));
2179 pwszDeviceValueData
[cchPrinter
] = L
',';
2181 // Append the value data, which has the format "winspool,<Port>:"
2182 dwErrorCode
= (DWORD
)RegQueryValueExW(hDevicesKey
, pszPrinter
, NULL
, NULL
, (PBYTE
)&pwszDeviceValueData
[cchPrinter
+ 1], &cbPrinterValueData
);
2183 if (dwErrorCode
!= ERROR_SUCCESS
)
2186 // Open the Windows registry key.
2187 dwErrorCode
= (DWORD
)RegOpenKeyExW(HKEY_CURRENT_USER
, wszWindowsKey
, 0, KEY_SET_VALUE
, &hWindowsKey
);
2188 if (dwErrorCode
!= ERROR_SUCCESS
)
2190 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode
);
2194 // Store our new default printer.
2195 dwErrorCode
= (DWORD
)RegSetValueExW(hWindowsKey
, wszDeviceValue
, 0, REG_SZ
, (PBYTE
)pwszDeviceValueData
, cbDeviceValueData
);
2196 if (dwErrorCode
!= ERROR_SUCCESS
)
2198 ERR("RegSetValueExW failed with status %lu!\n", dwErrorCode
);
2204 RegCloseKey(hDevicesKey
);
2207 RegCloseKey(hWindowsKey
);
2209 if (pwszDeviceValueData
)
2210 HeapFree(hProcessHeap
, 0, pwszDeviceValueData
);
2212 SetLastError(dwErrorCode
);
2213 return (dwErrorCode
== ERROR_SUCCESS
);
2217 SetPrinterA(HANDLE hPrinter
, DWORD Level
, PBYTE pPrinter
, DWORD Command
)
2219 TRACE("SetPrinterA(%p, %lu, %p, %lu)\n", hPrinter
, Level
, pPrinter
, Command
);
2225 SetPrinterW(HANDLE hPrinter
, DWORD Level
, PBYTE pPrinter
, DWORD Command
)
2227 TRACE("SetPrinterW(%p, %lu, %p, %lu)\n", hPrinter
, Level
, pPrinter
, Command
);
2233 SplDriverUnloadComplete(LPWSTR pDriverFile
)
2235 TRACE("DriverUnloadComplete(%S)\n", pDriverFile
);
2237 return TRUE
; // return true for now.
2241 StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, PBYTE pDocInfo
)
2243 DOC_INFO_1W wDocInfo1
= { 0 };
2246 DWORD dwReturnValue
= 0;
2247 PDOC_INFO_1A pDocInfo1
= (PDOC_INFO_1A
)pDocInfo
;
2249 TRACE("StartDocPrinterA(%p, %lu, %p)\n", hPrinter
, Level
, pDocInfo
);
2251 // Only check the minimum required for accessing pDocInfo.
2252 // Additional sanity checks are done in StartDocPrinterW.
2255 dwErrorCode
= ERROR_INVALID_PARAMETER
;
2261 dwErrorCode
= ERROR_INVALID_LEVEL
;
2265 if (pDocInfo1
->pDatatype
)
2267 // Convert pDocInfo1->pDatatype to a Unicode string wDocInfo1.pDatatype
2268 cch
= strlen(pDocInfo1
->pDatatype
);
2270 wDocInfo1
.pDatatype
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
2271 if (!wDocInfo1
.pDatatype
)
2273 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2274 ERR("HeapAlloc failed!\n");
2278 MultiByteToWideChar(CP_ACP
, 0, pDocInfo1
->pDatatype
, -1, wDocInfo1
.pDatatype
, cch
+ 1);
2281 if (pDocInfo1
->pDocName
)
2283 // Convert pDocInfo1->pDocName to a Unicode string wDocInfo1.pDocName
2284 cch
= strlen(pDocInfo1
->pDocName
);
2286 wDocInfo1
.pDocName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
2287 if (!wDocInfo1
.pDocName
)
2289 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2290 ERR("HeapAlloc failed!\n");
2294 MultiByteToWideChar(CP_ACP
, 0, pDocInfo1
->pDocName
, -1, wDocInfo1
.pDocName
, cch
+ 1);
2297 if (pDocInfo1
->pOutputFile
)
2299 // Convert pDocInfo1->pOutputFile to a Unicode string wDocInfo1.pOutputFile
2300 cch
= strlen(pDocInfo1
->pOutputFile
);
2302 wDocInfo1
.pOutputFile
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
2303 if (!wDocInfo1
.pOutputFile
)
2305 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2306 ERR("HeapAlloc failed!\n");
2310 MultiByteToWideChar(CP_ACP
, 0, pDocInfo1
->pOutputFile
, -1, wDocInfo1
.pOutputFile
, cch
+ 1);
2313 dwReturnValue
= StartDocPrinterW(hPrinter
, Level
, (PBYTE
)&wDocInfo1
);
2314 dwErrorCode
= GetLastError();
2317 if (wDocInfo1
.pDatatype
)
2318 HeapFree(hProcessHeap
, 0, wDocInfo1
.pDatatype
);
2320 if (wDocInfo1
.pDocName
)
2321 HeapFree(hProcessHeap
, 0, wDocInfo1
.pDocName
);
2323 if (wDocInfo1
.pOutputFile
)
2324 HeapFree(hProcessHeap
, 0, wDocInfo1
.pOutputFile
);
2326 SetLastError(dwErrorCode
);
2327 return dwReturnValue
;
2331 StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, PBYTE pDocInfo
)
2333 DWORD cbAddJobInfo1
;
2336 DWORD dwReturnValue
= 0;
2337 PADDJOB_INFO_1W pAddJobInfo1
= NULL
;
2338 PDOC_INFO_1W pDocInfo1
= (PDOC_INFO_1W
)pDocInfo
;
2339 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
2341 TRACE("StartDocPrinterW(%p, %lu, %p)\n", hPrinter
, Level
, pDocInfo
);
2346 dwErrorCode
= ERROR_INVALID_HANDLE
;
2352 dwErrorCode
= ERROR_INVALID_PARAMETER
;
2358 dwErrorCode
= ERROR_INVALID_LEVEL
;
2362 if (pHandle
->bStartedDoc
)
2364 dwErrorCode
= ERROR_INVALID_PRINTER_STATE
;
2368 // Check if we want to redirect output into a file.
2369 if (pDocInfo1
->pOutputFile
)
2371 // Do a StartDocPrinter RPC call in this case.
2372 dwErrorCode
= _StartDocPrinterWithRPC(pHandle
, pDocInfo1
);
2376 // Allocate memory for the ADDJOB_INFO_1W structure and a path.
2377 cbAddJobInfo1
= sizeof(ADDJOB_INFO_1W
) + MAX_PATH
* sizeof(WCHAR
);
2378 pAddJobInfo1
= HeapAlloc(hProcessHeap
, 0, cbAddJobInfo1
);
2381 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2382 ERR("HeapAlloc failed!\n");
2386 // Try to add a new job.
2387 // This only succeeds if the printer is set to do spooled printing.
2388 if (AddJobW((HANDLE
)pHandle
, 1, (PBYTE
)pAddJobInfo1
, cbAddJobInfo1
, &cbNeeded
))
2390 // Do spooled printing.
2391 dwErrorCode
= _StartDocPrinterSpooled(pHandle
, pDocInfo1
, pAddJobInfo1
);
2393 else if (GetLastError() == ERROR_INVALID_ACCESS
)
2395 // ERROR_INVALID_ACCESS is returned when the printer is set to do direct printing.
2396 // In this case, we do a StartDocPrinter RPC call.
2397 dwErrorCode
= _StartDocPrinterWithRPC(pHandle
, pDocInfo1
);
2401 dwErrorCode
= GetLastError();
2402 ERR("AddJobW failed with error %lu!\n", dwErrorCode
);
2407 if (dwErrorCode
== ERROR_SUCCESS
)
2409 pHandle
->bStartedDoc
= TRUE
;
2410 dwReturnValue
= pHandle
->dwJobID
;
2415 HeapFree(hProcessHeap
, 0, pAddJobInfo1
);
2417 SetLastError(dwErrorCode
);
2418 return dwReturnValue
;
2422 StartPagePrinter(HANDLE hPrinter
)
2425 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
2427 TRACE("StartPagePrinter(%p)\n", hPrinter
);
2432 dwErrorCode
= ERROR_INVALID_HANDLE
;
2439 dwErrorCode
= _RpcStartPagePrinter(pHandle
->hPrinter
);
2441 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
2443 dwErrorCode
= RpcExceptionCode();
2444 ERR("_RpcStartPagePrinter failed with exception code %lu!\n", dwErrorCode
);
2449 SetLastError(dwErrorCode
);
2450 return (dwErrorCode
== ERROR_SUCCESS
);
2454 WritePrinter(HANDLE hPrinter
, PVOID pBuf
, DWORD cbBuf
, PDWORD pcWritten
)
2457 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
2459 TRACE("WritePrinter(%p, %p, %lu, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2464 dwErrorCode
= ERROR_INVALID_HANDLE
;
2468 if (!pHandle
->bStartedDoc
)
2470 dwErrorCode
= ERROR_SPL_NO_STARTDOC
;
2474 if (pHandle
->hSPLFile
!= INVALID_HANDLE_VALUE
)
2476 // Write to the spool file. This doesn't need an RPC request.
2477 if (!WriteFile(pHandle
->hSPLFile
, pBuf
, cbBuf
, pcWritten
, NULL
))
2479 dwErrorCode
= GetLastError();
2480 ERR("WriteFile failed with error %lu!\n", dwErrorCode
);
2484 dwErrorCode
= ERROR_SUCCESS
;
2488 // TODO: This case (for direct printing or remote printing) has bad performance if multiple small-sized WritePrinter calls are performed.
2489 // We may increase performance by writing into a buffer and only doing a single RPC call when the buffer is full.
2494 dwErrorCode
= _RpcWritePrinter(pHandle
->hPrinter
, pBuf
, cbBuf
, pcWritten
);
2496 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
2498 dwErrorCode
= RpcExceptionCode();
2499 ERR("_RpcWritePrinter failed with exception code %lu!\n", dwErrorCode
);
2505 SetLastError(dwErrorCode
);
2506 return (dwErrorCode
== ERROR_SUCCESS
);
2510 XcvDataW(HANDLE hXcv
, PCWSTR pszDataName
, PBYTE pInputData
, DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
, PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
2512 TRACE("XcvDataW(%p, %S, %p, %lu, %p, %lu, %p, %p)\n", hXcv
, pszDataName
, pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);