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>
13 extern HINSTANCE hinstWinSpool
;
15 // See winddiui.h, ReactOS version is limited.
16 // Loading from XyzUI.dll part of XyzDRV.dll set. example TTYUI.DLL or UniDrvUI.DLL.
18 typedef DWORD (WINAPI
*DEVICECAPABILITIES
) (HANDLE
,PWSTR
,WORD
,PVOID
,PDEVMODEW
);
19 static DEVICECAPABILITIES fpDeviceCapabilities
;
21 typedef LONG (WINAPI
*DEVICEPROPERTYSHEETS
) (PPROPSHEETUI_INFO
,LPARAM
);
22 static DEVICEPROPERTYSHEETS fpDevicePropertySheets
;
23 typedef LONG (WINAPI
*DOCUMENTPROPERTYSHEETS
) (PPROPSHEETUI_INFO
,LPARAM
);
24 static DOCUMENTPROPERTYSHEETS fpDocumentPropertySheets
;
26 typedef LONG (WINAPI
*COMMONPROPERTYSHEETUIW
) (HWND
,PFNPROPSHEETUI
,LPARAM
,LPDWORD
);
27 static COMMONPROPERTYSHEETUIW fpCommonPropertySheetUIW
;
29 typedef LONG (WINAPI
*QUERYCOLORPROFILE
) (HANDLE
,PDEVMODEW
,ULONG
,PVOID
,ULONG
*,FLONG
*);
30 static QUERYCOLORPROFILE fpQueryColorProfile
;
32 typedef BOOL (WINAPI
*SPOOLERPRINTEREVENT
) (LPWSTR
,int,DWORD
,LPARAM
);
33 static SPOOLERPRINTEREVENT fpPrinterEvent
;
35 typedef BOOL (WINAPI
*DEVQUERYPRINT
) (HANDLE
,LPDEVMODEW
,DWORD
*);
36 static DEVQUERYPRINT fpDevQueryPrint
;
38 typedef BOOL (WINAPI
*DEVQUERYPRINTEX
) (PDEVQUERYPRINT_INFO
);
39 static DEVQUERYPRINTEX fpDevQueryPrintEx
;
44 LONG WINAPI
ConstructPrinterFriendlyName( PWSTR
, PVOID
, LPDWORD Size
);
45 typedef LONG (WINAPI
*CONSTRUCTPRINTERFRIENDLYNAME
) (PWSTR
,PVOID
,LPDWORD
);
46 static CONSTRUCTPRINTERFRIENDLYNAME fpConstructPrinterFriendlyName
;
51 typedef struct _COMPUI_USERDATA
54 LPWSTR pszPrinterName
;
55 } COMPUI_USERDATA
, *PCOMPUI_USERDATA
;
59 /** And the award for the most confusingly named setting goes to "Device", for storing the default printer of the current user.
60 Ok, I admit that this has historical reasons. It's still not straightforward in any way though! */
61 static const WCHAR wszWindowsKey
[] = L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows";
62 static const WCHAR wszDeviceValue
[] = L
"Device";
65 _StartDocPrinterSpooled(PSPOOLER_HANDLE pHandle
, PDOC_INFO_1W pDocInfo1
, PADDJOB_INFO_1W pAddJobInfo1
)
69 PJOB_INFO_1W pJobInfo1
= NULL
;
71 // Create the spool file.
72 pHandle
->hSPLFile
= CreateFileW(pAddJobInfo1
->Path
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, CREATE_ALWAYS
, 0, NULL
);
73 if (pHandle
->hSPLFile
== INVALID_HANDLE_VALUE
)
75 dwErrorCode
= GetLastError();
76 ERR("CreateFileW failed for \"%S\" with error %lu!\n", pAddJobInfo1
->Path
, dwErrorCode
);
80 // Get the size of the job information.
81 GetJobW((HANDLE
)pHandle
, pAddJobInfo1
->JobId
, 1, NULL
, 0, &cbNeeded
);
82 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
84 dwErrorCode
= GetLastError();
85 ERR("GetJobW failed with error %lu!\n", dwErrorCode
);
89 // Allocate enough memory for the returned job information.
90 pJobInfo1
= HeapAlloc(hProcessHeap
, 0, cbNeeded
);
93 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
94 ERR("HeapAlloc failed!\n");
98 // Get the job information.
99 if (!GetJobW((HANDLE
)pHandle
, pAddJobInfo1
->JobId
, 1, (PBYTE
)pJobInfo1
, cbNeeded
, &cbNeeded
))
101 dwErrorCode
= GetLastError();
102 ERR("GetJobW failed with error %lu!\n", dwErrorCode
);
106 // Add our document information.
107 if (pDocInfo1
->pDatatype
)
108 pJobInfo1
->pDatatype
= pDocInfo1
->pDatatype
;
110 pJobInfo1
->pDocument
= pDocInfo1
->pDocName
;
112 // Set the new job information.
113 if (!SetJobW((HANDLE
)pHandle
, pAddJobInfo1
->JobId
, 1, (PBYTE
)pJobInfo1
, 0))
115 dwErrorCode
= GetLastError();
116 ERR("SetJobW failed with error %lu!\n", dwErrorCode
);
120 // We were successful!
121 pHandle
->dwJobID
= pAddJobInfo1
->JobId
;
122 dwErrorCode
= ERROR_SUCCESS
;
126 HeapFree(hProcessHeap
, 0, pJobInfo1
);
132 _StartDocPrinterWithRPC(PSPOOLER_HANDLE pHandle
, PDOC_INFO_1W pDocInfo1
)
135 WINSPOOL_DOC_INFO_CONTAINER DocInfoContainer
;
137 DocInfoContainer
.Level
= 1;
138 DocInfoContainer
.DocInfo
.pDocInfo1
= (WINSPOOL_DOC_INFO_1
*)pDocInfo1
;
142 dwErrorCode
= _RpcStartDocPrinter(pHandle
->hPrinter
, &DocInfoContainer
, &pHandle
->dwJobID
);
144 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
146 dwErrorCode
= RpcExceptionCode();
147 ERR("_RpcStartDocPrinter failed with exception code %lu!\n", dwErrorCode
);
155 AbortPrinter(HANDLE hPrinter
)
158 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
160 TRACE("AbortPrinter(%p)\n", hPrinter
);
165 dwErrorCode
= ERROR_INVALID_HANDLE
;
169 pHandle
->bTrayIcon
= pHandle
->bStartedDoc
= FALSE
;
171 if ( pHandle
->hSPLFile
!= INVALID_HANDLE_VALUE
&& pHandle
->bJob
)
173 // Close any open file handle.
174 CloseHandle( pHandle
->hSPLFile
);
175 pHandle
->hSPLFile
= INVALID_HANDLE_VALUE
;
177 SetJobW( hPrinter
, pHandle
->dwJobID
, 0, NULL
, JOB_CONTROL_DELETE
);
179 return ScheduleJob( hPrinter
, pHandle
->dwJobID
);
185 dwErrorCode
= _RpcAbortPrinter(&pHandle
->hPrinter
);
187 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
189 dwErrorCode
= RpcExceptionCode();
190 ERR("_RpcAbortPrinter failed with exception code %lu!\n", dwErrorCode
);
195 SetLastError(dwErrorCode
);
196 return (dwErrorCode
== ERROR_SUCCESS
);
200 AddPrinterA(PSTR pName
, DWORD Level
, PBYTE pPrinter
)
202 UNICODE_STRING pNameW
, usBuffer
;
204 PRINTER_INFO_2W
*ppi2w
= (PRINTER_INFO_2W
*)pPrinter
;
205 PRINTER_INFO_2A
*ppi2a
= (PRINTER_INFO_2A
*)pPrinter
;
207 PWSTR pwszPrinterName
= NULL
;
208 PWSTR pwszServerName
= NULL
;
209 PWSTR pwszShareName
= NULL
;
210 PWSTR pwszPortName
= NULL
;
211 PWSTR pwszDriverName
= NULL
;
212 PWSTR pwszComment
= NULL
;
213 PWSTR pwszLocation
= NULL
;
214 PWSTR pwszSepFile
= NULL
;
215 PWSTR pwszPrintProcessor
= NULL
;
216 PWSTR pwszDatatype
= NULL
;
217 PWSTR pwszParameters
= NULL
;
218 PDEVMODEW pdmw
= NULL
;
220 TRACE("AddPrinterA(%s, %d, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
224 ERR("Level = %d, unsupported!\n", Level
);
225 SetLastError(ERROR_INVALID_LEVEL
);
229 pwstrNameW
= AsciiToUnicode(&pNameW
,pName
);
231 if (ppi2a
->pShareName
)
233 pwszShareName
= AsciiToUnicode(&usBuffer
, ppi2a
->pShareName
);
234 if (!(ppi2w
->pShareName
= pwszShareName
)) goto Cleanup
;
236 if (ppi2a
->pPortName
)
238 pwszPortName
= AsciiToUnicode(&usBuffer
, ppi2a
->pPortName
);
239 if (!(ppi2w
->pPortName
= pwszPortName
)) goto Cleanup
;
241 if (ppi2a
->pDriverName
)
243 pwszDriverName
= AsciiToUnicode(&usBuffer
, ppi2a
->pDriverName
);
244 if (!(ppi2w
->pDriverName
= pwszDriverName
)) goto Cleanup
;
248 pwszComment
= AsciiToUnicode(&usBuffer
, ppi2a
->pComment
);
249 if (!(ppi2w
->pComment
= pwszComment
)) goto Cleanup
;
251 if (ppi2a
->pLocation
)
253 pwszLocation
= AsciiToUnicode(&usBuffer
, ppi2a
->pLocation
);
254 if (!(ppi2w
->pLocation
= pwszLocation
)) goto Cleanup
;
258 pwszSepFile
= AsciiToUnicode(&usBuffer
, ppi2a
->pSepFile
);
259 if (!(ppi2w
->pSepFile
= pwszSepFile
)) goto Cleanup
;
261 if (ppi2a
->pServerName
)
263 pwszPrintProcessor
= AsciiToUnicode(&usBuffer
, ppi2a
->pPrintProcessor
);
264 if (!(ppi2w
->pPrintProcessor
= pwszPrintProcessor
)) goto Cleanup
;
266 if (ppi2a
->pDatatype
)
268 pwszDatatype
= AsciiToUnicode(&usBuffer
, ppi2a
->pDatatype
);
269 if (!(ppi2w
->pDatatype
= pwszDatatype
)) goto Cleanup
;
271 if (ppi2a
->pParameters
)
273 pwszParameters
= AsciiToUnicode(&usBuffer
, ppi2a
->pParameters
);
274 if (!(ppi2w
->pParameters
= pwszParameters
)) goto Cleanup
;
276 if ( ppi2a
->pDevMode
)
278 RosConvertAnsiDevModeToUnicodeDevmode( ppi2a
->pDevMode
, &pdmw
);
279 ppi2w
->pDevMode
= pdmw
;
281 if (ppi2a
->pServerName
)
283 pwszServerName
= AsciiToUnicode(&usBuffer
, ppi2a
->pServerName
);
284 if (!(ppi2w
->pPrinterName
= pwszServerName
)) goto Cleanup
;
286 if (ppi2a
->pPrinterName
)
288 pwszPrinterName
= AsciiToUnicode(&usBuffer
, ppi2a
->pPrinterName
);
289 if (!(ppi2w
->pPrinterName
= pwszPrinterName
)) goto Cleanup
;
292 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)ppi2w
);
295 if (pdmw
) HeapFree(hProcessHeap
, 0, pdmw
);
296 if (pwszPrinterName
) HeapFree(hProcessHeap
, 0, pwszPrinterName
);
297 if (pwszServerName
) HeapFree(hProcessHeap
, 0, pwszServerName
);
298 if (pwszShareName
) HeapFree(hProcessHeap
, 0, pwszShareName
);
299 if (pwszPortName
) HeapFree(hProcessHeap
, 0, pwszPortName
);
300 if (pwszDriverName
) HeapFree(hProcessHeap
, 0, pwszDriverName
);
301 if (pwszComment
) HeapFree(hProcessHeap
, 0, pwszComment
);
302 if (pwszLocation
) HeapFree(hProcessHeap
, 0, pwszLocation
);
303 if (pwszSepFile
) HeapFree(hProcessHeap
, 0, pwszSepFile
);
304 if (pwszPrintProcessor
) HeapFree(hProcessHeap
, 0, pwszPrintProcessor
);
305 if (pwszDatatype
) HeapFree(hProcessHeap
, 0, pwszDatatype
);
306 if (pwszParameters
) HeapFree(hProcessHeap
, 0, pwszParameters
);
308 RtlFreeUnicodeString(&pNameW
);
313 AddPrinterW(PWSTR pName
, DWORD Level
, PBYTE pPrinter
)
316 WINSPOOL_PRINTER_CONTAINER PrinterContainer
;
317 WINSPOOL_DEVMODE_CONTAINER DevModeContainer
;
318 WINSPOOL_SECURITY_CONTAINER SecurityContainer
;
319 SECURITY_DESCRIPTOR
*sd
= NULL
;
321 HANDLE hPrinter
= NULL
, hHandle
= NULL
;
322 PSPOOLER_HANDLE pHandle
= NULL
;
324 TRACE("AddPrinterW(%S, %lu, %p)\n", pName
, Level
, pPrinter
);
326 DevModeContainer
.cbBuf
= 0;
327 DevModeContainer
.pDevMode
= NULL
;
329 SecurityContainer
.cbBuf
= 0;
330 SecurityContainer
.pSecurity
= NULL
;
334 FIXME( "Unsupported level %d\n", Level
);
335 SetLastError( ERROR_INVALID_LEVEL
);
340 PPRINTER_INFO_2W pi2w
= (PPRINTER_INFO_2W
)pPrinter
;
343 if ( pi2w
->pDevMode
)
345 if ( IsValidDevmodeNoSizeW( pi2w
->pDevMode
) )
347 DevModeContainer
.cbBuf
= pi2w
->pDevMode
->dmSize
+ pi2w
->pDevMode
->dmDriverExtra
;
348 DevModeContainer
.pDevMode
= (PBYTE
)pi2w
->pDevMode
;
352 if ( pi2w
->pSecurityDescriptor
)
354 sd
= get_sd( pi2w
->pSecurityDescriptor
, &size
);
357 SecurityContainer
.cbBuf
= size
;
358 SecurityContainer
.pSecurity
= (PBYTE
)sd
;
364 SetLastError(ERROR_INVALID_PARAMETER
);
369 PrinterContainer
.PrinterInfo
.pPrinterInfo1
= (WINSPOOL_PRINTER_INFO_1
*)pPrinter
;
370 PrinterContainer
.Level
= Level
;
375 dwErrorCode
= _RpcAddPrinter( pName
, &PrinterContainer
, &DevModeContainer
, &SecurityContainer
, &hPrinter
);
377 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
379 dwErrorCode
= RpcExceptionCode();
385 // Create a new SPOOLER_HANDLE structure.
386 pHandle
= HeapAlloc(hProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(SPOOLER_HANDLE
));
389 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
390 ERR("HeapAlloc failed!\n");
391 _RpcDeletePrinter(hPrinter
);
392 _RpcClosePrinter(hPrinter
);
396 pHandle
->Sig
= SPOOLER_HANDLE_SIG
;
397 pHandle
->hPrinter
= hPrinter
;
398 pHandle
->hSPLFile
= INVALID_HANDLE_VALUE
;
399 pHandle
->hSpoolFileHandle
= INVALID_HANDLE_VALUE
;
400 hHandle
= (HANDLE
)pHandle
;
404 if ( sd
) HeapFree( GetProcessHeap(), 0, sd
);
406 SetLastError(dwErrorCode
);
411 ClosePrinter(HANDLE hPrinter
)
414 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
416 TRACE("ClosePrinter(%p)\n", hPrinter
);
419 if ( IntProtectHandle( hPrinter
, TRUE
) )
421 dwErrorCode
= ERROR_INVALID_HANDLE
;
428 dwErrorCode
= _RpcClosePrinter(&pHandle
->hPrinter
);
430 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
432 dwErrorCode
= RpcExceptionCode();
433 ERR("_RpcClosePrinter failed with exception code %lu!\n", dwErrorCode
);
437 // Close any open file handle.
438 if (pHandle
->hSPLFile
!= INVALID_HANDLE_VALUE
)
439 CloseHandle(pHandle
->hSPLFile
);
443 // Free the memory for the handle.
444 HeapFree(hProcessHeap
, 0, pHandle
);
447 SetLastError(dwErrorCode
);
448 return (dwErrorCode
== ERROR_SUCCESS
);
452 DeletePrinter(HANDLE hPrinter
)
455 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
457 TRACE("DeletePrinter(%p)\n", hPrinter
);
462 dwErrorCode
= ERROR_INVALID_HANDLE
;
469 dwErrorCode
= _RpcDeletePrinter(&pHandle
->hPrinter
);
471 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
473 dwErrorCode
= RpcExceptionCode();
474 ERR("_RpcDeletePrinter failed with exception code %lu!\n", dwErrorCode
);
479 SetLastError(dwErrorCode
);
480 return (dwErrorCode
== ERROR_SUCCESS
);
484 // Based on GDI32:printdrv.c:IntGetPrinterDriver.
488 LoadPrinterDriver( HANDLE hspool
)
491 DWORD Size
= (sizeof(WCHAR
) * MAX_PATH
) * 2; // DRIVER_INFO_5W + plus strings.
492 PDRIVER_INFO_5W pdi
= NULL
;
493 HMODULE hLibrary
= NULL
;
499 pdi
= RtlAllocateHeap( GetProcessHeap(), 0, Size
);
504 if ( GetPrinterDriverW(hspool
, NULL
, 5, (LPBYTE
)pdi
, Size
, &Size
) )
506 TRACE("Level 5 Size %d\n",Size
);
508 // Name and load configure library (for example, C:\DRIVERS\Pscrptui.dll). Not printui.dll!
510 hLibrary
= LoadLibrary(pdi
->pConfigFile
);
512 FIXME("IGPD : Get Printer Driver Config File : %S\n",pdi
->pConfigFile
);
514 RtlFreeHeap( GetProcessHeap(), 0, pdi
);
518 if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
521 RtlFreeHeap( GetProcessHeap(), 0, pdi
);
523 while ( iTries
< 2 );
524 ERR("No Printer Driver Error %d\n",GetLastError());
529 DeviceCapabilitiesA(LPCSTR pDevice
, LPCSTR pPort
, WORD fwCapability
, LPSTR pOutput
, const DEVMODEA
* pDevMode
)
531 PWSTR pwszDeviceName
= NULL
;
532 PDEVMODEW pdmwInput
= NULL
;
533 BOOL bReturnValue
= GDI_ERROR
;
536 FIXME("DeviceCapabilitiesA(%s, %s, %hu, %p, %p)\n", pDevice
, pPort
, fwCapability
, pOutput
, pDevMode
);
540 // Convert pName to a Unicode string pwszDeviceName.
541 cch
= strlen(pDevice
);
543 pwszDeviceName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
546 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
547 ERR("HeapAlloc failed!\n");
551 MultiByteToWideChar(CP_ACP
, 0, pDevice
, -1, pwszDeviceName
, cch
+ 1);
556 RosConvertAnsiDevModeToUnicodeDevmode((PDEVMODEA
)pDevMode
, &pdmwInput
);
559 // pPort is ignored so no need to pass it.
560 bReturnValue
= DeviceCapabilitiesW( pwszDeviceName
, NULL
, fwCapability
, (LPWSTR
)pOutput
, (const DEVMODEW
*) pdmwInput
);
564 HeapFree(hProcessHeap
, 0, pwszDeviceName
);
567 HeapFree(hProcessHeap
, 0, pdmwInput
);
573 DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
, WORD fwCapability
, LPWSTR pOutput
, const DEVMODEW
* pDevMode
)
577 DWORD iDevCap
= GDI_ERROR
;
579 FIXME("DeviceCapabilitiesW(%S, %S, %hu, %p, %p)\n", pDevice
, pPort
, fwCapability
, pOutput
, pDevMode
);
583 if (!IsValidDevmodeNoSizeW( (PDEVMODEW
)pDevMode
) )
585 ERR("DeviceCapabilitiesW : Devode Invalid");
590 if ( OpenPrinterW( (LPWSTR
)pDevice
, &hPrinter
, NULL
) )
592 hLibrary
= LoadPrinterDriver( hPrinter
);
596 fpDeviceCapabilities
= (PVOID
)GetProcAddress( hLibrary
, "DrvDeviceCapabilities" );
598 if ( fpDeviceCapabilities
)
600 iDevCap
= fpDeviceCapabilities( hPrinter
, (PWSTR
)pDevice
, fwCapability
, pOutput
, (PDEVMODE
)pDevMode
);
603 FreeLibrary(hLibrary
);
606 ClosePrinter( hPrinter
);
614 DevQueryPrint( HANDLE hPrinter
, LPDEVMODEW pDevMode
, DWORD
*pResID
)
619 hLibrary
= LoadPrinterDriver( hPrinter
);
623 fpDevQueryPrint
= (PVOID
)GetProcAddress( hLibrary
, "DevQueryPrint" );
625 if ( fpDevQueryPrint
)
627 Ret
= fpDevQueryPrint( hPrinter
, pDevMode
, pResID
);
630 FreeLibrary(hLibrary
);
636 DevQueryPrintEx( PDEVQUERYPRINT_INFO pDQPInfo
)
641 hLibrary
= LoadPrinterDriver( pDQPInfo
->hPrinter
);
645 fpDevQueryPrintEx
= (PVOID
)GetProcAddress( hLibrary
, "DevQueryPrintEx" );
647 if ( fpDevQueryPrintEx
)
649 Ret
= fpDevQueryPrintEx( pDQPInfo
);
652 FreeLibrary(hLibrary
);
658 DocumentEvent( HANDLE hPrinter
, HDC hdc
, int iEsc
, ULONG cbIn
, PVOID pvIn
, ULONG cbOut
, PVOID pvOut
)
660 FIXME("DocumentEvent(%p, %p, %lu, %lu, %p, %lu, %p)\n", hPrinter
, hdc
, iEsc
, cbIn
, pvIn
, cbOut
, pvOut
);
662 return DOCUMENTEVENT_UNSUPPORTED
;
666 DocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
, PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
, DWORD fMode
)
668 PWSTR pwszDeviceName
= NULL
;
669 PDEVMODEW pdmwInput
= NULL
;
670 PDEVMODEW pdmwOutput
= NULL
;
671 BOOL bReturnValue
= -1;
674 FIXME("DocumentPropertiesA(%p, %p, %s, %p, %p, %lu)\n", hWnd
, hPrinter
, pDeviceName
, pDevModeOutput
, pDevModeInput
, fMode
);
678 // Convert pName to a Unicode string pwszDeviceName.
679 cch
= strlen(pDeviceName
);
681 pwszDeviceName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
684 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
685 ERR("HeapAlloc failed!\n");
689 MultiByteToWideChar(CP_ACP
, 0, pDeviceName
, -1, pwszDeviceName
, cch
+ 1);
694 // Create working buffer for input to DocumentPropertiesW.
695 RosConvertAnsiDevModeToUnicodeDevmode(pDevModeInput
, &pdmwInput
);
700 // Create working buffer for output from DocumentPropertiesW.
702 // Do it RIGHT! Get the F...ing Size!
703 LONG Size
= DocumentPropertiesW( hWnd
, hPrinter
, pwszDeviceName
, NULL
, NULL
, 0 );
710 pdmwOutput
= HeapAlloc(hProcessHeap
, 0, Size
);
713 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
714 ERR("HeapAlloc failed!\n");
719 bReturnValue
= DocumentPropertiesW(hWnd
, hPrinter
, pwszDeviceName
, pdmwOutput
, pdmwInput
, fMode
);
720 FIXME("bReturnValue from DocumentPropertiesW is '%ld'.\n", bReturnValue
);
724 HeapFree(hProcessHeap
, 0, pwszDeviceName
);
727 if (bReturnValue
< 0)
729 FIXME("DocumentPropertiesW failed!\n");
735 RosConvertUnicodeDevModeToAnsiDevmode(pdmwOutput
, pDevModeOutput
);
740 HeapFree(hProcessHeap
, 0, pwszDeviceName
);
743 HeapFree(hProcessHeap
, 0, pdmwInput
);
746 HeapFree(hProcessHeap
, 0, pdmwOutput
);
751 PRINTER_INFO_9W
* get_devmodeW(HANDLE hprn
)
753 PRINTER_INFO_9W
*pi9
= NULL
;
757 res
= GetPrinterW(hprn
, 9, NULL
, 0, &needed
);
758 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
))
760 pi9
= HeapAlloc(hProcessHeap
, 0, needed
);
761 res
= GetPrinterW(hprn
, 9, (LPBYTE
)pi9
, needed
, &needed
);
767 ERR("GetPrinterW failed with %u\n", GetLastError());
768 HeapFree(hProcessHeap
, 0, pi9
);
774 CreateUIUserData( ULONG_PTR
*puserdata
, HANDLE hPrinter
)
776 PCOMPUI_USERDATA pcui_ud
= DllAllocSplMem( sizeof(COMPUI_USERDATA
) );
778 *puserdata
= (ULONG_PTR
)pcui_ud
;
779 FIXME("CreateUIUserData\n");
782 pcui_ud
->hModule
= LoadPrinterDriver( hPrinter
);
784 if ( !pcui_ud
->hModule
)
786 DllFreeSplMem( pcui_ud
);
790 return *puserdata
!= 0;
795 DestroyUIUserData( ULONG_PTR
*puserdata
)
797 PCOMPUI_USERDATA pcui_ud
= (PCOMPUI_USERDATA
)*puserdata
;
798 FIXME("DestroyUIUserData\n");
801 if ( pcui_ud
->hModule
)
803 FreeLibrary( pcui_ud
->hModule
);
804 pcui_ud
->hModule
= NULL
;
807 if ( pcui_ud
->pszPrinterName
)
809 DllFreeSplMem( pcui_ud
->pszPrinterName
);
810 pcui_ud
->pszPrinterName
= NULL
;
813 DllFreeSplMem( pcui_ud
);
820 IntFixUpDevModeNames( PDOCUMENTPROPERTYHEADER pdphdr
)
822 PRINTER_INFO_2W
*pi2
= NULL
;
826 if (!(pdphdr
->fMode
& DM_OUT_BUFFER
) ||
827 pdphdr
->fMode
& DM_NOPERMISSION
|| // Do not allow the user to modify properties on the displayed property sheet pages.
833 res
= GetPrinterW( pdphdr
->hPrinter
, 2, NULL
, 0, &needed
);
834 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
))
836 pi2
= HeapAlloc(hProcessHeap
, 0, needed
);
837 res
= GetPrinterW( pdphdr
->hPrinter
, 2, (LPBYTE
)pi2
, needed
, &needed
);
842 FIXME("IFUDMN : Get Printer Name %S\n",pi2
->pPrinterName
);
843 StringCchCopyW( pdphdr
->pdmOut
->dmDeviceName
, CCHDEVICENAME
-1, pi2
->pPrinterName
);
844 pdphdr
->pdmOut
->dmDeviceName
[CCHDEVICENAME
-1] = 0;
848 ERR("IFUDMN : GetPrinterW failed with %u\n", GetLastError());
850 HeapFree(hProcessHeap
, 0, pi2
);
856 CreatePrinterFriendlyName( PCOMPUI_USERDATA pcui_ud
, LPWSTR pszPrinterName
)
860 HMODULE hLibrary
= NULL
;
862 hLibrary
= LoadLibraryA( "printui.dll" );
866 fpConstructPrinterFriendlyName
= (PVOID
)GetProcAddress( hLibrary
, "ConstructPrinterFriendlyName" );
868 if ( fpConstructPrinterFriendlyName
)
870 if ( !fpConstructPrinterFriendlyName( pszPrinterName
, NULL
, &Size
) )
872 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
874 PWSTR pwstr
= DllAllocSplMem( (Size
+ 1) * sizeof(WCHAR
) );
876 pcui_ud
->pszPrinterName
= pwstr
;
879 Result
= fpConstructPrinterFriendlyName( pszPrinterName
, pwstr
, &Size
);
883 FreeLibrary( hLibrary
);
888 DllFreeSplMem( pcui_ud
->pszPrinterName
);
889 pcui_ud
->pszPrinterName
= AllocSplStr( pszPrinterName
);
896 // Tested with XP CompstUI as a callback and works. Fails perfectly.
900 DocumentPropertySheets( PPROPSHEETUI_INFO pCPSUIInfo
, LPARAM lparam
)
903 PDOCUMENTPROPERTYHEADER pdphdr
;
905 FIXME("DocumentPropertySheets(%p, 0x%lx)\n", pCPSUIInfo
, lparam
);
907 // If pPSUIInfo is NULL, and if either lParam -> fMode is zero or lParam -> pdmOut is NULL,
908 // this function should return the size, in bytes, of the printer's DEVMODEW structure.
909 if ( !pCPSUIInfo
&& lparam
)
911 pdphdr
= (PDOCUMENTPROPERTYHEADER
)lparam
;
913 if ( pdphdr
->cbSize
>= sizeof(PDOCUMENTPROPERTYHEADER
) &&
914 !(pdphdr
->fMode
& DM_PROMPT
) )
916 HMODULE hLibrary
= LoadPrinterDriver( pdphdr
->hPrinter
);
920 fpDocumentPropertySheets
= (PVOID
)GetProcAddress( hLibrary
, "DrvDocumentPropertySheets" );
922 if ( fpDocumentPropertySheets
)
924 Result
= fpDocumentPropertySheets( pCPSUIInfo
, lparam
);
929 // ReactOS backup!!! Currently no supporting UI driver.
931 PRINTER_INFO_9W
* pi9
= get_devmodeW( pdphdr
->hPrinter
);
934 Result
= pi9
->pDevMode
->dmSize
+ pi9
->pDevMode
->dmDriverExtra
;
935 FIXME("IDPS : Using ReactOS backup!!! DevMode Size %d\n",Result
);
936 HeapFree(hProcessHeap
, 0, pi9
);
940 FreeLibrary(hLibrary
);
944 IntFixUpDevModeNames( pdphdr
);
951 SetLastError(ERROR_INVALID_HANDLE
);
956 SetLastError(ERROR_INVALID_PARAMETER
);
965 PSETRESULT_INFO psri
;
966 PPROPSHEETUI_INFO_HEADER ppsuiihdr
;
967 PCOMPUI_USERDATA pcui_ud
;
968 pdphdr
= (PDOCUMENTPROPERTYHEADER
)pCPSUIInfo
->lParamInit
;
970 if ( pdphdr
->cbSize
< sizeof(PDOCUMENTPROPERTYHEADER
) )
972 SetLastError(ERROR_INVALID_PARAMETER
);
976 switch ( pCPSUIInfo
->Reason
)
978 case PROPSHEETUI_REASON_INIT
:
980 FIXME("DocPS : PROPSHEETUI_REASON_INIT\n");
981 if ( CreateUIUserData( &pCPSUIInfo
->UserData
, pdphdr
->hPrinter
) )
983 pcui_ud
= (PCOMPUI_USERDATA
)pCPSUIInfo
->UserData
;
985 fpDocumentPropertySheets
= (PVOID
)GetProcAddress( pcui_ud
->hModule
, "DrvDocumentPropertySheets" );
987 if ( fpDocumentPropertySheets
)
989 pCPSUIInfo
->pfnComPropSheet( pCPSUIInfo
->hComPropSheet
,
990 CPSFUNC_SET_FUSION_CONTEXT
,
991 -3, // What type of handle is this?
992 0 ); // Not used, must be zero.
994 Result
= pCPSUIInfo
->pfnComPropSheet( pCPSUIInfo
->hComPropSheet
,
995 CPSFUNC_ADD_PFNPROPSHEETUIW
,
996 (LPARAM
)fpDocumentPropertySheets
,
997 pCPSUIInfo
->lParamInit
);
1000 FIXME("DocPS : PROPSHEETUI_REASON_INIT Fail\n");
1001 DestroyUIUserData( &pCPSUIInfo
->UserData
);
1006 case PROPSHEETUI_REASON_GET_INFO_HEADER
:
1007 FIXME("DocPS : PROPSHEETUI_REASON_GET_INFO_HEADER\n");
1009 ppsuiihdr
= (PPROPSHEETUI_INFO_HEADER
)lparam
;
1011 pcui_ud
= (PCOMPUI_USERDATA
)pCPSUIInfo
->UserData
;
1013 CreatePrinterFriendlyName( pcui_ud
, pdphdr
->pszPrinterName
);
1015 ppsuiihdr
->Flags
= PSUIHDRF_NOAPPLYNOW
|PSUIHDRF_PROPTITLE
;
1016 ppsuiihdr
->pTitle
= pcui_ud
->pszPrinterName
;
1017 ppsuiihdr
->hInst
= hinstWinSpool
;
1018 ppsuiihdr
->IconID
= IDI_CPSUI_DOCUMENT
;
1023 case PROPSHEETUI_REASON_DESTROY
:
1024 FIXME("DocPS : PROPSHEETUI_REASON_DESTROY\n");
1025 DestroyUIUserData( &pCPSUIInfo
->UserData
);
1029 case PROPSHEETUI_REASON_SET_RESULT
:
1030 FIXME("DocPS : PROPSHEETUI_REASON_SET_RESULT\n");
1032 psri
= (PSETRESULT_INFO
)lparam
;
1034 pCPSUIInfo
->Result
= psri
->Result
;
1035 if ( pCPSUIInfo
->Result
> 0 )
1037 IntFixUpDevModeNames( pdphdr
);
1048 DevicePropertySheets( PPROPSHEETUI_INFO pCPSUIInfo
, LPARAM lparam
)
1051 PDEVICEPROPERTYHEADER pdphdr
;
1053 FIXME("DevicePropertySheets(%p, 0x%lx)\n", pCPSUIInfo
, lparam
);
1057 PSETRESULT_INFO psri
;
1058 PPROPSHEETUI_INFO_HEADER ppsuiihdr
;
1059 PCOMPUI_USERDATA pcui_ud
;
1060 pdphdr
= (PDEVICEPROPERTYHEADER
)pCPSUIInfo
->lParamInit
;
1062 if ( pdphdr
->cbSize
< sizeof(DEVICEPROPERTYHEADER
) )
1064 SetLastError(ERROR_INVALID_PARAMETER
);
1068 switch ( pCPSUIInfo
->Reason
)
1070 case PROPSHEETUI_REASON_INIT
:
1072 FIXME("DevPS : PROPSHEETUI_REASON_INIT\n");
1073 if ( CreateUIUserData( &pCPSUIInfo
->UserData
, pdphdr
->hPrinter
) )
1075 pcui_ud
= (PCOMPUI_USERDATA
)pCPSUIInfo
->UserData
;
1077 fpDevicePropertySheets
= (PVOID
)GetProcAddress( pcui_ud
->hModule
, "DrvDevicePropertySheets" );
1079 if ( fpDevicePropertySheets
)
1081 pCPSUIInfo
->pfnComPropSheet( pCPSUIInfo
->hComPropSheet
,
1082 CPSFUNC_SET_FUSION_CONTEXT
,
1083 -3, // What type of handle is this?
1084 0 ); // Not used, must be zero.
1086 Result
= pCPSUIInfo
->pfnComPropSheet( pCPSUIInfo
->hComPropSheet
,
1087 CPSFUNC_ADD_PFNPROPSHEETUIW
,
1088 (LPARAM
)fpDevicePropertySheets
,
1089 pCPSUIInfo
->lParamInit
);
1092 FIXME("DevPS : PROPSHEETUI_REASON_INIT Fail\n");
1093 DestroyUIUserData( &pCPSUIInfo
->UserData
);
1098 case PROPSHEETUI_REASON_GET_INFO_HEADER
:
1099 FIXME("DevPS : PROPSHEETUI_REASON_GET_INFO_HEADER\n");
1101 ppsuiihdr
= (PPROPSHEETUI_INFO_HEADER
)lparam
;
1103 pcui_ud
= (PCOMPUI_USERDATA
)pCPSUIInfo
->UserData
;
1105 CreatePrinterFriendlyName( pcui_ud
, pdphdr
->pszPrinterName
);
1107 ppsuiihdr
->Flags
= PSUIHDRF_NOAPPLYNOW
|PSUIHDRF_PROPTITLE
;
1108 ppsuiihdr
->pTitle
= pcui_ud
->pszPrinterName
;
1109 ppsuiihdr
->hInst
= hinstWinSpool
;
1110 ppsuiihdr
->IconID
= IDI_CPSUI_DOCUMENT
;
1115 case PROPSHEETUI_REASON_DESTROY
:
1116 FIXME("DevPS : PROPSHEETUI_REASON_DESTROY\n");
1117 DestroyUIUserData( &pCPSUIInfo
->UserData
);
1121 case PROPSHEETUI_REASON_SET_RESULT
:
1122 FIXME("DevPS : PROPSHEETUI_REASON_SET_RESULT\n");
1123 psri
= (PSETRESULT_INFO
)lparam
;
1124 pCPSUIInfo
->Result
= psri
->Result
;
1134 CallCommonPropertySheetUI(HWND hWnd
, PFNPROPSHEETUI pfnPropSheetUI
, LPARAM lparam
, LPDWORD pResult
)
1136 HMODULE hLibrary
= NULL
;
1137 LONG Ret
= ERR_CPSUI_GETLASTERROR
;
1139 FIXME("CallCommonPropertySheetUI(%p, %p, 0x%lx, %p)\n", hWnd
, pfnPropSheetUI
, lparam
, pResult
);
1141 if ( ( hLibrary
= LoadLibraryA( "compstui.dll" ) ) )
1143 fpCommonPropertySheetUIW
= (PVOID
) GetProcAddress(hLibrary
, "CommonPropertySheetUIW");
1145 if ( fpCommonPropertySheetUIW
)
1147 Ret
= fpCommonPropertySheetUIW( hWnd
, pfnPropSheetUI
, lparam
, pResult
);
1150 FreeLibrary(hLibrary
);
1156 DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
, PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
, DWORD fMode
)
1158 HANDLE hUseHandle
= NULL
;
1159 DOCUMENTPROPERTYHEADER docprophdr
;
1162 FIXME("DocumentPropertiesW(%p, %p, %S, %p, %p, %lu)\n", hWnd
, hPrinter
, pDeviceName
, pDevModeOutput
, pDevModeInput
, fMode
);
1166 hUseHandle
= hPrinter
;
1168 else if (!OpenPrinterW(pDeviceName
, &hUseHandle
, NULL
))
1170 ERR("No handle, and no usable printer name passed in\n");
1174 if ( !(fMode
& DM_IN_BUFFER
) ||
1175 ( ( pDevModeInput
&& !IsValidDevmodeNoSizeW( (PDEVMODEW
)pDevModeInput
) ) ) )
1177 pDevModeInput
= NULL
;
1178 fMode
&= ~DM_IN_BUFFER
;
1181 docprophdr
.cbSize
= sizeof(DOCUMENTPROPERTYHEADER
);
1182 docprophdr
.Reserved
= 0;
1183 docprophdr
.hPrinter
= hUseHandle
;
1184 docprophdr
.pszPrinterName
= pDeviceName
;
1185 docprophdr
.cbOut
= 0;
1187 if ( pDevModeOutput
)
1189 docprophdr
.pdmIn
= NULL
;
1190 docprophdr
.pdmOut
= NULL
;
1191 docprophdr
.fMode
= 0;
1192 FIXME("DPW : Call DocumentPropertySheets with pDevModeOutput %p\n",pDevModeOutput
);
1193 docprophdr
.cbOut
= DocumentPropertySheets( NULL
, (LPARAM
)&docprophdr
);
1196 docprophdr
.pdmIn
= pDevModeInput
;
1197 docprophdr
.pdmOut
= pDevModeOutput
;
1198 docprophdr
.fMode
= fMode
;
1200 if ( fMode
& DM_IN_PROMPT
)
1202 Result
= CPSUI_CANCEL
;
1205 // Now call the Property Sheet for Print > Properties.
1207 if ( CallCommonPropertySheetUI( hWnd
, (PFNPROPSHEETUI
)DocumentPropertySheets
, (LPARAM
)&docprophdr
, (LPDWORD
)&Result
) < 0 )
1209 FIXME("CallCommonPropertySheetUI return error\n");
1210 Result
= ERR_CPSUI_GETLASTERROR
;
1213 Result
= (Result
== CPSUI_OK
) ? IDOK
: IDCANCEL
;
1214 FIXME("CallCommonPropertySheetUI returned\n");
1218 FIXME("DPW : CallDocumentPropertySheets\n");
1219 Result
= DocumentPropertySheets( NULL
, (LPARAM
)&docprophdr
);
1222 if ( Result
!= ERR_CPSUI_GETLASTERROR
|| Result
!= ERR_CPSUI_ALLOCMEM_FAILED
)
1224 if ( pDevModeOutput
)
1226 if ( !IsValidDevmodeNoSizeW( pDevModeOutput
) )
1228 ERR("DPW : Improper pDevModeOutput size.\n");
1234 ERR("No pDevModeOutput\n");
1238 if (hUseHandle
&& !hPrinter
)
1239 ClosePrinter(hUseHandle
);
1245 PrinterProperties( HWND hWnd
, HANDLE hPrinter
)
1247 PRINTER_INFO_2W
*pi2
= NULL
;
1249 LONG Ret
, Result
= 0;
1251 DEVICEPROPERTYHEADER devprophdr
;
1253 FIXME("PrinterProperties(%p, %p)\n", hWnd
, hPrinter
);
1255 devprophdr
.cbSize
= sizeof(DEVICEPROPERTYHEADER
);
1256 devprophdr
.Flags
= DPS_NOPERMISSION
;
1257 devprophdr
.hPrinter
= hPrinter
;
1258 devprophdr
.pszPrinterName
= NULL
;
1260 res
= GetPrinterW( hPrinter
, 2, NULL
, 0, &needed
);
1261 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
))
1263 pi2
= HeapAlloc(hProcessHeap
, 0, needed
);
1264 res
= GetPrinterW(hPrinter
, 2, (LPBYTE
)pi2
, needed
, &needed
);
1268 // Above can fail, still process w/o printer name.
1270 if ( res
) devprophdr
.pszPrinterName
= pi2
->pPrinterName
;
1274 if ( ( SetPrinterDataW( hPrinter
, L
"PrinterPropertiesPermission", REG_DWORD
, (LPBYTE
)&needed
, sizeof(DWORD
) ) == ERROR_SUCCESS
) )
1276 devprophdr
.Flags
&= ~DPS_NOPERMISSION
;
1279 Ret
= CallCommonPropertySheetUI( hWnd
, (PFNPROPSHEETUI
)DevicePropertySheets
, (LPARAM
)&devprophdr
, (LPDWORD
)&Result
);
1285 FIXME("PrinterProperties fail ICPSUI\n");
1288 if (pi2
) HeapFree(hProcessHeap
, 0, pi2
);
1294 EndDocPrinter(HANDLE hPrinter
)
1297 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
1299 TRACE("EndDocPrinter(%p)\n", hPrinter
);
1304 dwErrorCode
= ERROR_INVALID_HANDLE
;
1308 if (pHandle
->hSPLFile
!= INVALID_HANDLE_VALUE
)
1310 // For spooled jobs, the document is finished by calling _RpcScheduleJob.
1313 dwErrorCode
= _RpcScheduleJob(pHandle
->hPrinter
, pHandle
->dwJobID
);
1315 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
1317 dwErrorCode
= RpcExceptionCode();
1318 ERR("_RpcScheduleJob failed with exception code %lu!\n", dwErrorCode
);
1322 // Close the spool file handle.
1323 CloseHandle(pHandle
->hSPLFile
);
1327 // In all other cases, just call _RpcEndDocPrinter.
1330 dwErrorCode
= _RpcEndDocPrinter(pHandle
->hPrinter
);
1332 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
1334 dwErrorCode
= RpcExceptionCode();
1335 ERR("_RpcEndDocPrinter failed with exception code %lu!\n", dwErrorCode
);
1340 // A new document can now be started again.
1341 pHandle
->bTrayIcon
= pHandle
->bJob
= pHandle
->bStartedDoc
= FALSE
;
1344 SetLastError(dwErrorCode
);
1345 return (dwErrorCode
== ERROR_SUCCESS
);
1349 EndPagePrinter(HANDLE hPrinter
)
1352 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
1354 TRACE("EndPagePrinter(%p)\n", hPrinter
);
1359 dwErrorCode
= ERROR_INVALID_HANDLE
;
1363 if (pHandle
->hSPLFile
!= INVALID_HANDLE_VALUE
)
1365 // For spooled jobs, we don't need to do anything.
1366 dwErrorCode
= ERROR_SUCCESS
;
1370 // In all other cases, just call _RpcEndPagePrinter.
1373 dwErrorCode
= _RpcEndPagePrinter(pHandle
->hPrinter
);
1375 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
1377 dwErrorCode
= RpcExceptionCode();
1378 ERR("_RpcEndPagePrinter failed with exception code %lu!\n", dwErrorCode
);
1384 SetLastError(dwErrorCode
);
1385 return (dwErrorCode
== ERROR_SUCCESS
);
1389 EnumPrintersA(DWORD Flags
, PSTR Name
, DWORD Level
, PBYTE pPrinterEnum
, DWORD cbBuf
, PDWORD pcbNeeded
, PDWORD pcReturned
)
1393 PWSTR pwszName
= NULL
;
1394 PSTR pszPrinterName
= NULL
;
1395 PSTR pszServerName
= NULL
;
1396 PSTR pszDescription
= NULL
;
1397 PSTR pszName
= NULL
;
1398 PSTR pszComment
= NULL
;
1399 PSTR pszShareName
= NULL
;
1400 PSTR pszPortName
= NULL
;
1401 PSTR pszDriverName
= NULL
;
1402 PSTR pszLocation
= NULL
;
1403 PSTR pszSepFile
= NULL
;
1404 PSTR pszPrintProcessor
= NULL
;
1405 PSTR pszDatatype
= NULL
;
1406 PSTR pszParameters
= NULL
;
1408 PPRINTER_INFO_1W ppi1w
= NULL
;
1409 PPRINTER_INFO_1A ppi1a
= NULL
;
1410 PPRINTER_INFO_2W ppi2w
= NULL
;
1411 PPRINTER_INFO_2A ppi2a
= NULL
;
1412 PPRINTER_INFO_4W ppi4w
= NULL
;
1413 PPRINTER_INFO_4A ppi4a
= NULL
;
1414 PPRINTER_INFO_5W ppi5w
= NULL
;
1415 PPRINTER_INFO_5A ppi5a
= NULL
;
1417 TRACE("EnumPrintersA(%lu, %s, %lu, %p, %lu, %p, %p)\n", Flags
, Name
, Level
, pPrinterEnum
, cbBuf
, pcbNeeded
, pcReturned
);
1419 // Check for invalid levels here for early error return. MSDN says that only 1, 2, 4, and 5 are allowable.
1420 if (Level
!= 1 && Level
!= 2 && Level
!= 4 && Level
!= 5)
1422 dwErrorCode
= ERROR_INVALID_LEVEL
;
1423 ERR("Invalid Level!\n");
1429 // Convert pName to a Unicode string pwszName.
1432 pwszName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
1435 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1436 ERR("HeapAlloc failed!\n");
1440 MultiByteToWideChar(CP_ACP
, 0, Name
, -1, pwszName
, cch
+ 1);
1443 /* Ref: https://stackoverflow.com/questions/41147180/why-enumprintersa-and-enumprintersw-request-the-same-amount-of-memory */
1444 if (!EnumPrintersW(Flags
, pwszName
, Level
, pPrinterEnum
, cbBuf
, pcbNeeded
, pcReturned
))
1446 dwErrorCode
= GetLastError();
1450 /* We are mapping multiple different pointers to the same pPrinterEnum pointer here so that */
1451 /* we can do in-place conversion. We read the Unicode response from the EnumPrintersW and */
1452 /* then we write back the ANSI conversion into the same buffer for our EnumPrintersA output */
1454 /* mapping to pPrinterEnum for Unicode (w) characters for Levels 1, 2, 4, and 5 */
1455 ppi1w
= (PPRINTER_INFO_1W
)pPrinterEnum
;
1456 ppi2w
= (PPRINTER_INFO_2W
)pPrinterEnum
;
1457 ppi4w
= (PPRINTER_INFO_4W
)pPrinterEnum
;
1458 ppi5w
= (PPRINTER_INFO_5W
)pPrinterEnum
;
1459 /* mapping to pPrinterEnum for ANSI (a) characters for Levels 1, 2, 4, and 5 */
1460 ppi1a
= (PPRINTER_INFO_1A
)pPrinterEnum
;
1461 ppi2a
= (PPRINTER_INFO_2A
)pPrinterEnum
;
1462 ppi4a
= (PPRINTER_INFO_4A
)pPrinterEnum
;
1463 ppi5a
= (PPRINTER_INFO_5A
)pPrinterEnum
;
1465 for (i
= 0; i
< *pcReturned
; i
++)
1471 if (ppi1w
[i
].pDescription
)
1473 // Convert Unicode pDescription to a ANSI string pszDescription.
1474 cch
= wcslen(ppi1w
[i
].pDescription
);
1476 pszDescription
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1477 if (!pszDescription
)
1479 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1480 ERR("HeapAlloc failed!\n");
1484 WideCharToMultiByte(CP_ACP
, 0, ppi1w
[i
].pDescription
, -1, pszDescription
, cch
+ 1, NULL
, NULL
);
1485 StringCchCopyA(ppi1a
[i
].pDescription
, cch
+ 1, pszDescription
);
1487 HeapFree(hProcessHeap
, 0, pszDescription
);
1492 // Convert Unicode pName to a ANSI string pszName.
1493 cch
= wcslen(ppi1w
[i
].pName
);
1495 pszName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1498 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1499 ERR("HeapAlloc failed!\n");
1503 WideCharToMultiByte(CP_ACP
, 0, ppi1w
[i
].pName
, -1, pszName
, cch
+ 1, NULL
, NULL
);
1504 StringCchCopyA(ppi1a
[i
].pName
, cch
+ 1, pszName
);
1506 HeapFree(hProcessHeap
, 0, pszName
);
1509 if (ppi1w
[i
].pComment
)
1511 // Convert Unicode pComment to a ANSI string pszComment.
1512 cch
= wcslen(ppi1w
[i
].pComment
);
1514 pszComment
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1517 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1518 ERR("HeapAlloc failed!\n");
1522 WideCharToMultiByte(CP_ACP
, 0, ppi1w
[i
].pComment
, -1, pszComment
, cch
+ 1, NULL
, NULL
);
1523 StringCchCopyA(ppi1a
[i
].pComment
, cch
+ 1, pszComment
);
1525 HeapFree(hProcessHeap
, 0, pszComment
);
1533 if (ppi2w
[i
].pServerName
)
1535 // Convert Unicode pServerName to a ANSI string pszServerName.
1536 cch
= wcslen(ppi2w
[i
].pServerName
);
1538 pszServerName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1541 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1542 ERR("HeapAlloc failed!\n");
1546 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pServerName
, -1, pszServerName
, cch
+ 1, NULL
, NULL
);
1547 StringCchCopyA(ppi2a
[i
].pServerName
, cch
+ 1, pszServerName
);
1549 HeapFree(hProcessHeap
, 0, pszServerName
);
1552 if (ppi2w
[i
].pPrinterName
)
1554 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
1555 cch
= wcslen(ppi2w
[i
].pPrinterName
);
1557 pszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1558 if (!pszPrinterName
)
1560 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1561 ERR("HeapAlloc failed!\n");
1565 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pPrinterName
, -1, pszPrinterName
, cch
+ 1, NULL
, NULL
);
1566 StringCchCopyA(ppi2a
[i
].pPrinterName
, cch
+ 1, pszPrinterName
);
1568 HeapFree(hProcessHeap
, 0, pszPrinterName
);
1571 if (ppi2w
[i
].pShareName
)
1573 // Convert Unicode pShareName to a ANSI string pszShareName.
1574 cch
= wcslen(ppi2w
[i
].pShareName
);
1576 pszShareName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1579 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1580 ERR("HeapAlloc failed!\n");
1584 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pShareName
, -1, pszShareName
, cch
+ 1, NULL
, NULL
);
1585 StringCchCopyA(ppi2a
[i
].pShareName
, cch
+ 1, pszShareName
);
1587 HeapFree(hProcessHeap
, 0, pszShareName
);
1590 if (ppi2w
[i
].pPortName
)
1592 // Convert Unicode pPortName to a ANSI string pszPortName.
1593 cch
= wcslen(ppi2w
[i
].pPortName
);
1595 pszPortName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1598 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1599 ERR("HeapAlloc failed!\n");
1603 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pPortName
, -1, pszPortName
, cch
+ 1, NULL
, NULL
);
1604 StringCchCopyA(ppi2a
[i
].pPortName
, cch
+ 1, pszPortName
);
1606 HeapFree(hProcessHeap
, 0, pszPortName
);
1609 if (ppi2w
[i
].pDriverName
)
1611 // Convert Unicode pDriverName to a ANSI string pszDriverName.
1612 cch
= wcslen(ppi2w
[i
].pDriverName
);
1614 pszDriverName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1617 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1618 ERR("HeapAlloc failed!\n");
1622 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pDriverName
, -1, pszDriverName
, cch
+ 1, NULL
, NULL
);
1623 StringCchCopyA(ppi2a
[i
].pDriverName
, cch
+ 1, pszDriverName
);
1625 HeapFree(hProcessHeap
, 0, pszDriverName
);
1628 if (ppi2w
[i
].pComment
)
1630 // Convert Unicode pComment to a ANSI string pszComment.
1631 cch
= wcslen(ppi2w
[i
].pComment
);
1633 pszComment
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1636 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1637 ERR("HeapAlloc failed!\n");
1641 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pComment
, -1, pszComment
, cch
+ 1, NULL
, NULL
);
1642 StringCchCopyA(ppi2a
[i
].pComment
, cch
+ 1, pszComment
);
1644 HeapFree(hProcessHeap
, 0, pszComment
);
1647 if (ppi2w
[i
].pLocation
)
1649 // Convert Unicode pLocation to a ANSI string pszLocation.
1650 cch
= wcslen(ppi2w
[i
].pLocation
);
1652 pszLocation
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1655 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1656 ERR("HeapAlloc failed!\n");
1660 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pLocation
, -1, pszLocation
, cch
+ 1, NULL
, NULL
);
1661 StringCchCopyA(ppi2a
[i
].pLocation
, cch
+ 1, pszLocation
);
1663 HeapFree(hProcessHeap
, 0, pszLocation
);
1667 if (ppi2w
[i
].pSepFile
)
1669 // Convert Unicode pSepFile to a ANSI string pszSepFile.
1670 cch
= wcslen(ppi2w
[i
].pSepFile
);
1672 pszSepFile
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1675 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1676 ERR("HeapAlloc failed!\n");
1680 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pSepFile
, -1, pszSepFile
, cch
+ 1, NULL
, NULL
);
1681 StringCchCopyA(ppi2a
[i
].pSepFile
, cch
+ 1, pszSepFile
);
1683 HeapFree(hProcessHeap
, 0, pszSepFile
);
1686 if (ppi2w
[i
].pPrintProcessor
)
1688 // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor.
1689 cch
= wcslen(ppi2w
[i
].pPrintProcessor
);
1691 pszPrintProcessor
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1692 if (!pszPrintProcessor
)
1694 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1695 ERR("HeapAlloc failed!\n");
1699 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pPrintProcessor
, -1, pszPrintProcessor
, cch
+ 1, NULL
, NULL
);
1700 StringCchCopyA(ppi2a
[i
].pPrintProcessor
, cch
+ 1, pszPrintProcessor
);
1702 HeapFree(hProcessHeap
, 0, pszPrintProcessor
);
1706 if (ppi2w
[i
].pDatatype
)
1708 // Convert Unicode pDatatype to a ANSI string pszDatatype.
1709 cch
= wcslen(ppi2w
[i
].pDatatype
);
1711 pszDatatype
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1714 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1715 ERR("HeapAlloc failed!\n");
1719 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pDatatype
, -1, pszDatatype
, cch
+ 1, NULL
, NULL
);
1720 StringCchCopyA(ppi2a
[i
].pDatatype
, cch
+ 1, pszDatatype
);
1722 HeapFree(hProcessHeap
, 0, pszDatatype
);
1725 if (ppi2w
[i
].pParameters
)
1727 // Convert Unicode pParameters to a ANSI string pszParameters.
1728 cch
= wcslen(ppi2w
[i
].pParameters
);
1730 pszParameters
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1733 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1734 ERR("HeapAlloc failed!\n");
1738 WideCharToMultiByte(CP_ACP
, 0, ppi2w
[i
].pParameters
, -1, pszParameters
, cch
+ 1, NULL
, NULL
);
1739 StringCchCopyA(ppi2a
[i
].pParameters
, cch
+ 1, pszParameters
);
1741 HeapFree(hProcessHeap
, 0, pszParameters
);
1743 if ( ppi2w
[i
].pDevMode
)
1745 RosConvertUnicodeDevModeToAnsiDevmode( ppi2w
[i
].pDevMode
, ppi2a
[i
].pDevMode
);
1752 if (ppi4w
[i
].pPrinterName
)
1754 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
1755 cch
= wcslen(ppi4w
[i
].pPrinterName
);
1757 pszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1758 if (!pszPrinterName
)
1760 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1761 ERR("HeapAlloc failed!\n");
1765 WideCharToMultiByte(CP_ACP
, 0, ppi4w
[i
].pPrinterName
, -1, pszPrinterName
, cch
+ 1, NULL
, NULL
);
1766 StringCchCopyA(ppi4a
[i
].pPrinterName
, cch
+ 1, pszPrinterName
);
1768 HeapFree(hProcessHeap
, 0, pszPrinterName
);
1771 if (ppi4w
[i
].pServerName
)
1773 // Convert Unicode pServerName to a ANSI string pszServerName.
1774 cch
= wcslen(ppi4w
[i
].pServerName
);
1776 pszServerName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1779 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1780 ERR("HeapAlloc failed!\n");
1784 WideCharToMultiByte(CP_ACP
, 0, ppi4w
[i
].pServerName
, -1, pszServerName
, cch
+ 1, NULL
, NULL
);
1785 StringCchCopyA(ppi4a
[i
].pServerName
, cch
+ 1, pszServerName
);
1787 HeapFree(hProcessHeap
, 0, pszServerName
);
1794 if (ppi5w
[i
].pPrinterName
)
1796 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
1797 cch
= wcslen(ppi5w
[i
].pPrinterName
);
1799 pszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1800 if (!pszPrinterName
)
1802 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1803 ERR("HeapAlloc failed!\n");
1807 WideCharToMultiByte(CP_ACP
, 0, ppi5w
[i
].pPrinterName
, -1, pszPrinterName
, cch
+ 1, NULL
, NULL
);
1808 StringCchCopyA(ppi5a
[i
].pPrinterName
, cch
+ 1, pszPrinterName
);
1810 HeapFree(hProcessHeap
, 0, pszPrinterName
);
1813 if (ppi5w
[i
].pPortName
)
1815 // Convert Unicode pPortName to a ANSI string pszPortName.
1816 cch
= wcslen(ppi5w
[i
].pPortName
);
1818 pszPortName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
1821 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1822 ERR("HeapAlloc failed!\n");
1826 WideCharToMultiByte(CP_ACP
, 0, ppi5w
[i
].pPortName
, -1, pszPortName
, cch
+ 1, NULL
, NULL
);
1827 StringCchCopyA(ppi5a
[i
].pPortName
, cch
+ 1, pszPortName
);
1829 HeapFree(hProcessHeap
, 0, pszPortName
);
1837 dwErrorCode
= ERROR_SUCCESS
;
1842 HeapFree(hProcessHeap
, 0, pwszName
);
1845 SetLastError(dwErrorCode
);
1846 return (dwErrorCode
== ERROR_SUCCESS
);
1850 EnumPrintersW(DWORD Flags
, PWSTR Name
, DWORD Level
, PBYTE pPrinterEnum
, DWORD cbBuf
, PDWORD pcbNeeded
, PDWORD pcReturned
)
1854 TRACE("EnumPrintersW(%lu, %S, %lu, %p, %lu, %p, %p)\n", Flags
, Name
, Level
, pPrinterEnum
, cbBuf
, pcbNeeded
, pcReturned
);
1856 // Dismiss invalid levels already at this point.
1857 if (Level
== 3 || Level
> 5)
1859 dwErrorCode
= ERROR_INVALID_LEVEL
;
1863 if (cbBuf
&& pPrinterEnum
)
1864 ZeroMemory(pPrinterEnum
, cbBuf
);
1869 dwErrorCode
= _RpcEnumPrinters(Flags
, Name
, Level
, pPrinterEnum
, cbBuf
, pcbNeeded
, pcReturned
);
1871 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
1873 dwErrorCode
= RpcExceptionCode();
1874 ERR("_RpcEnumPrinters failed with exception code %lu!\n", dwErrorCode
);
1878 if (dwErrorCode
== ERROR_SUCCESS
)
1880 // Replace relative offset addresses in the output by absolute pointers.
1882 MarshallUpStructuresArray(cbBuf
, pPrinterEnum
, *pcReturned
, pPrinterInfoMarshalling
[Level
]->pInfo
, pPrinterInfoMarshalling
[Level
]->cbStructureSize
, TRUE
);
1886 SetLastError(dwErrorCode
);
1887 return (dwErrorCode
== ERROR_SUCCESS
);
1891 FlushPrinter(HANDLE hPrinter
, PVOID pBuf
, DWORD cbBuf
, PDWORD pcWritten
, DWORD cSleep
)
1893 TRACE("FlushPrinter(%p, %p, %lu, %p, %lu)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
, cSleep
);
1899 GetDefaultPrinterA(LPSTR pszBuffer
, LPDWORD pcchBuffer
)
1902 PWSTR pwszBuffer
= NULL
;
1904 TRACE("GetDefaultPrinterA(%p, %p)\n", pszBuffer
, pcchBuffer
);
1909 dwErrorCode
= ERROR_INVALID_PARAMETER
;
1913 // Check if an ANSI buffer was given and if so, allocate a Unicode buffer of the same size.
1914 if (pszBuffer
&& *pcchBuffer
)
1916 pwszBuffer
= HeapAlloc(hProcessHeap
, 0, *pcchBuffer
* sizeof(WCHAR
));
1919 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1920 ERR("HeapAlloc failed!\n");
1925 if (!GetDefaultPrinterW(pwszBuffer
, pcchBuffer
))
1927 dwErrorCode
= GetLastError();
1931 // We successfully got a string in pwszBuffer, so convert the Unicode string to ANSI.
1932 WideCharToMultiByte(CP_ACP
, 0, pwszBuffer
, -1, pszBuffer
, *pcchBuffer
, NULL
, NULL
);
1934 dwErrorCode
= ERROR_SUCCESS
;
1938 HeapFree(hProcessHeap
, 0, pwszBuffer
);
1940 SetLastError(dwErrorCode
);
1941 return (dwErrorCode
== ERROR_SUCCESS
);
1945 GetDefaultPrinterW(LPWSTR pszBuffer
, LPDWORD pcchBuffer
)
1948 DWORD cchInputBuffer
;
1950 HKEY hWindowsKey
= NULL
;
1951 PWSTR pwszDevice
= NULL
;
1954 TRACE("GetDefaultPrinterW(%p, %p)\n", pszBuffer
, pcchBuffer
);
1959 dwErrorCode
= ERROR_INVALID_PARAMETER
;
1963 cchInputBuffer
= *pcchBuffer
;
1965 // Open the registry key where the default printer for the current user is stored.
1966 dwErrorCode
= (DWORD
)RegOpenKeyExW(HKEY_CURRENT_USER
, wszWindowsKey
, 0, KEY_READ
, &hWindowsKey
);
1967 if (dwErrorCode
!= ERROR_SUCCESS
)
1969 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode
);
1973 // Determine the size of the required buffer.
1974 dwErrorCode
= (DWORD
)RegQueryValueExW(hWindowsKey
, wszDeviceValue
, NULL
, NULL
, NULL
, &cbNeeded
);
1975 if (dwErrorCode
!= ERROR_SUCCESS
)
1977 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode
);
1982 pwszDevice
= HeapAlloc(hProcessHeap
, 0, cbNeeded
);
1985 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1986 ERR("HeapAlloc failed!\n");
1990 // Now get the actual value.
1991 dwErrorCode
= RegQueryValueExW(hWindowsKey
, wszDeviceValue
, NULL
, NULL
, (PBYTE
)pwszDevice
, &cbNeeded
);
1992 if (dwErrorCode
!= ERROR_SUCCESS
)
1994 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode
);
1998 // We get a string "<Printer Name>,winspool,<Port>:".
1999 // Extract the printer name from it.
2000 pwszComma
= wcschr(pwszDevice
, L
',');
2003 ERR("Found no or invalid default printer: %S!\n", pwszDevice
);
2004 dwErrorCode
= ERROR_INVALID_NAME
;
2008 // Store the length of the Printer Name (including the terminating NUL character!) in *pcchBuffer.
2009 *pcchBuffer
= pwszComma
- pwszDevice
+ 1;
2011 // Check if the supplied buffer is large enough.
2012 if ( !pszBuffer
|| cchInputBuffer
< *pcchBuffer
)
2014 dwErrorCode
= ERROR_INSUFFICIENT_BUFFER
;
2018 // Copy the default printer.
2020 CopyMemory(pszBuffer
, pwszDevice
, *pcchBuffer
* sizeof(WCHAR
));
2022 dwErrorCode
= ERROR_SUCCESS
;
2026 RegCloseKey(hWindowsKey
);
2029 HeapFree(hProcessHeap
, 0, pwszDevice
);
2031 SetLastError(dwErrorCode
);
2032 return (dwErrorCode
== ERROR_SUCCESS
);
2036 GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2039 PPRINTER_INFO_1A ppi1a
= (PPRINTER_INFO_1A
)pPrinter
;
2040 PPRINTER_INFO_1W ppi1w
= (PPRINTER_INFO_1W
)pPrinter
;
2041 PPRINTER_INFO_2A ppi2a
= (PPRINTER_INFO_2A
)pPrinter
;
2042 PPRINTER_INFO_2W ppi2w
= (PPRINTER_INFO_2W
)pPrinter
;
2043 PPRINTER_INFO_4A ppi4a
= (PPRINTER_INFO_4A
)pPrinter
;
2044 PPRINTER_INFO_4W ppi4w
= (PPRINTER_INFO_4W
)pPrinter
;
2045 PPRINTER_INFO_5A ppi5a
= (PPRINTER_INFO_5A
)pPrinter
;
2046 PPRINTER_INFO_5W ppi5w
= (PPRINTER_INFO_5W
)pPrinter
;
2047 PPRINTER_INFO_7A ppi7a
= (PPRINTER_INFO_7A
)pPrinter
;
2048 PPRINTER_INFO_7W ppi7w
= (PPRINTER_INFO_7W
)pPrinter
;
2049 PPRINTER_INFO_9A ppi9a
= (PPRINTER_INFO_9A
)pPrinter
;
2050 PPRINTER_INFO_9W ppi9w
= (PPRINTER_INFO_9W
)pPrinter
;
2053 TRACE("GetPrinterA(%p, %lu, %p, %lu, %p)\n", hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
);
2055 // Check for invalid levels here for early error return. Should be 1-9.
2056 if (Level
< 1 || Level
> 9)
2058 dwErrorCode
= ERROR_INVALID_LEVEL
;
2059 ERR("Invalid Level!\n");
2063 if (!GetPrinterW(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
))
2065 dwErrorCode
= GetLastError();
2073 if (ppi1w
->pDescription
)
2075 PSTR pszDescription
;
2077 // Convert Unicode pDescription to a ANSI string pszDescription.
2078 cch
= wcslen(ppi1w
->pDescription
);
2080 pszDescription
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
2081 if (!pszDescription
)
2083 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2084 ERR("HeapAlloc failed!\n");
2088 WideCharToMultiByte(CP_ACP
, 0, ppi1w
->pDescription
, -1, pszDescription
, cch
+ 1, NULL
, NULL
);
2089 StringCchCopyA(ppi1a
->pDescription
, cch
+ 1, pszDescription
);
2091 HeapFree(hProcessHeap
, 0, pszDescription
);
2098 // Convert Unicode pName to a ANSI string pszName.
2099 cch
= wcslen(ppi1w
->pName
);
2101 pszName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
2104 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2105 ERR("HeapAlloc failed!\n");
2109 WideCharToMultiByte(CP_ACP
, 0, ppi1w
->pName
, -1, pszName
, cch
+ 1, NULL
, NULL
);
2110 StringCchCopyA(ppi1a
->pName
, cch
+ 1, pszName
);
2112 HeapFree(hProcessHeap
, 0, pszName
);
2115 if (ppi1w
->pComment
)
2119 // Convert Unicode pComment to a ANSI string pszComment.
2120 cch
= wcslen(ppi1w
->pComment
);
2122 pszComment
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
2125 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2126 ERR("HeapAlloc failed!\n");
2130 WideCharToMultiByte(CP_ACP
, 0, ppi1w
->pComment
, -1, pszComment
, cch
+ 1, NULL
, NULL
);
2131 StringCchCopyA(ppi1a
->pComment
, cch
+ 1, pszComment
);
2133 HeapFree(hProcessHeap
, 0, pszComment
);
2140 if (ppi2w
->pServerName
)
2144 // Convert Unicode pServerName to a ANSI string pszServerName.
2145 cch
= wcslen(ppi2w
->pServerName
);
2147 pszServerName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
2150 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2151 ERR("HeapAlloc failed!\n");
2155 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pServerName
, -1, pszServerName
, cch
+ 1, NULL
, NULL
);
2156 StringCchCopyA(ppi2a
->pServerName
, cch
+ 1, pszServerName
);
2158 HeapFree(hProcessHeap
, 0, pszServerName
);
2161 if (ppi2w
->pPrinterName
)
2163 PSTR pszPrinterName
;
2165 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
2166 cch
= wcslen(ppi2w
->pPrinterName
);
2168 pszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
2169 if (!pszPrinterName
)
2171 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2172 ERR("HeapAlloc failed!\n");
2176 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pPrinterName
, -1, pszPrinterName
, cch
+ 1, NULL
, NULL
);
2177 StringCchCopyA(ppi2a
->pPrinterName
, cch
+ 1, pszPrinterName
);
2179 HeapFree(hProcessHeap
, 0, pszPrinterName
);
2182 if (ppi2w
->pShareName
)
2186 // Convert Unicode pShareName to a ANSI string pszShareName.
2187 cch
= wcslen(ppi2w
->pShareName
);
2189 pszShareName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
2192 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2193 ERR("HeapAlloc failed!\n");
2197 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pShareName
, -1, pszShareName
, cch
+ 1, NULL
, NULL
);
2198 StringCchCopyA(ppi2a
->pShareName
, cch
+ 1, pszShareName
);
2200 HeapFree(hProcessHeap
, 0, pszShareName
);
2203 if (ppi2w
->pPortName
)
2207 // Convert Unicode pPortName to a ANSI string pszPortName.
2208 cch
= wcslen(ppi2w
->pPortName
);
2210 pszPortName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
2213 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2214 ERR("HeapAlloc failed!\n");
2218 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pPortName
, -1, pszPortName
, cch
+ 1, NULL
, NULL
);
2219 StringCchCopyA(ppi2a
->pPortName
, cch
+ 1, pszPortName
);
2221 HeapFree(hProcessHeap
, 0, pszPortName
);
2224 if (ppi2w
->pDriverName
)
2228 // Convert Unicode pDriverName to a ANSI string pszDriverName.
2229 cch
= wcslen(ppi2w
->pDriverName
);
2231 pszDriverName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
2234 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2235 ERR("HeapAlloc failed!\n");
2239 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pDriverName
, -1, pszDriverName
, cch
+ 1, NULL
, NULL
);
2240 StringCchCopyA(ppi2a
->pDriverName
, cch
+ 1, pszDriverName
);
2242 HeapFree(hProcessHeap
, 0, pszDriverName
);
2245 if (ppi2w
->pComment
)
2249 // Convert Unicode pComment to a ANSI string pszComment.
2250 cch
= wcslen(ppi2w
->pComment
);
2252 pszComment
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
2255 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2256 ERR("HeapAlloc failed!\n");
2260 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pComment
, -1, pszComment
, cch
+ 1, NULL
, NULL
);
2261 StringCchCopyA(ppi2a
->pComment
, cch
+ 1, pszComment
);
2263 HeapFree(hProcessHeap
, 0, pszComment
);
2266 if (ppi2w
->pLocation
)
2270 // Convert Unicode pLocation to a ANSI string pszLocation.
2271 cch
= wcslen(ppi2w
->pLocation
);
2273 pszLocation
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
2276 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2277 ERR("HeapAlloc failed!\n");
2281 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pLocation
, -1, pszLocation
, cch
+ 1, NULL
, NULL
);
2282 StringCchCopyA(ppi2a
->pLocation
, cch
+ 1, pszLocation
);
2284 HeapFree(hProcessHeap
, 0, pszLocation
);
2287 if (ppi2w
->pSepFile
)
2291 // Convert Unicode pSepFile to a ANSI string pszSepFile.
2292 cch
= wcslen(ppi2w
->pSepFile
);
2294 pszSepFile
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
2297 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2298 ERR("HeapAlloc failed!\n");
2302 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pSepFile
, -1, pszSepFile
, cch
+ 1, NULL
, NULL
);
2303 StringCchCopyA(ppi2a
->pSepFile
, cch
+ 1, pszSepFile
);
2305 HeapFree(hProcessHeap
, 0, pszSepFile
);
2308 if (ppi2w
->pPrintProcessor
)
2310 PSTR pszPrintProcessor
;
2312 // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor.
2313 cch
= wcslen(ppi2w
->pPrintProcessor
);
2315 pszPrintProcessor
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
2316 if (!pszPrintProcessor
)
2318 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2319 ERR("HeapAlloc failed!\n");
2323 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pPrintProcessor
, -1, pszPrintProcessor
, cch
+ 1, NULL
, NULL
);
2324 StringCchCopyA(ppi2a
->pPrintProcessor
, cch
+ 1, pszPrintProcessor
);
2326 HeapFree(hProcessHeap
, 0, pszPrintProcessor
);
2329 if (ppi2w
->pDatatype
)
2333 // Convert Unicode pDatatype to a ANSI string pszDatatype.
2334 cch
= wcslen(ppi2w
->pDatatype
);
2336 pszDatatype
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
2339 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2340 ERR("HeapAlloc failed!\n");
2344 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pDatatype
, -1, pszDatatype
, cch
+ 1, NULL
, NULL
);
2345 StringCchCopyA(ppi2a
->pDatatype
, cch
+ 1, pszDatatype
);
2347 HeapFree(hProcessHeap
, 0, pszDatatype
);
2350 if (ppi2w
->pParameters
)
2354 // Convert Unicode pParameters to a ANSI string pszParameters.
2355 cch
= wcslen(ppi2w
->pParameters
);
2357 pszParameters
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
2360 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2361 ERR("HeapAlloc failed!\n");
2365 WideCharToMultiByte(CP_ACP
, 0, ppi2w
->pParameters
, -1, pszParameters
, cch
+ 1, NULL
, NULL
);
2366 StringCchCopyA(ppi2a
->pParameters
, cch
+ 1, pszParameters
);
2368 HeapFree(hProcessHeap
, 0, pszParameters
);
2370 if ( ppi2w
->pDevMode
)
2372 RosConvertUnicodeDevModeToAnsiDevmode( ppi2w
->pDevMode
, ppi2a
->pDevMode
);
2379 if (ppi4w
->pPrinterName
)
2381 PSTR pszPrinterName
;
2383 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
2384 cch
= wcslen(ppi4w
->pPrinterName
);
2386 pszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
2387 if (!pszPrinterName
)
2389 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2390 ERR("HeapAlloc failed!\n");
2394 WideCharToMultiByte(CP_ACP
, 0, ppi4w
->pPrinterName
, -1, pszPrinterName
, cch
+ 1, NULL
, NULL
);
2395 StringCchCopyA(ppi4a
->pPrinterName
, cch
+ 1, pszPrinterName
);
2397 HeapFree(hProcessHeap
, 0, pszPrinterName
);
2400 if (ppi4w
->pServerName
)
2404 // Convert Unicode pServerName to a ANSI string pszServerName.
2405 cch
= wcslen(ppi4w
->pServerName
);
2407 pszServerName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
2410 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2411 ERR("HeapAlloc failed!\n");
2415 WideCharToMultiByte(CP_ACP
, 0, ppi4w
->pServerName
, -1, pszServerName
, cch
+ 1, NULL
, NULL
);
2416 StringCchCopyA(ppi4a
->pServerName
, cch
+ 1, pszServerName
);
2418 HeapFree(hProcessHeap
, 0, pszServerName
);
2425 if (ppi5w
->pPrinterName
)
2427 PSTR pszPrinterName
;
2429 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
2430 cch
= wcslen(ppi5w
->pPrinterName
);
2432 pszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
2433 if (!pszPrinterName
)
2435 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2436 ERR("HeapAlloc failed!\n");
2440 WideCharToMultiByte(CP_ACP
, 0, ppi5w
->pPrinterName
, -1, pszPrinterName
, cch
+ 1, NULL
, NULL
);
2441 StringCchCopyA(ppi5a
->pPrinterName
, cch
+ 1, pszPrinterName
);
2443 HeapFree(hProcessHeap
, 0, pszPrinterName
);
2446 if (ppi5w
->pPortName
)
2450 // Convert Unicode pPortName to a ANSI string pszPortName.
2451 cch
= wcslen(ppi5w
->pPortName
);
2453 pszPortName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
2456 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2457 ERR("HeapAlloc failed!\n");
2461 WideCharToMultiByte(CP_ACP
, 0, ppi5w
->pPortName
, -1, pszPortName
, cch
+ 1, NULL
, NULL
);
2462 StringCchCopyA(ppi5a
->pPortName
, cch
+ 1, pszPortName
);
2464 HeapFree(hProcessHeap
, 0, pszPortName
);
2471 if (ppi7w
->pszObjectGUID
)
2473 PSTR pszaObjectGUID
;
2475 // Convert Unicode pszObjectGUID to a ANSI string pszaObjectGUID.
2476 cch
= wcslen(ppi7w
->pszObjectGUID
);
2478 pszaObjectGUID
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(CHAR
));
2479 if (!pszaObjectGUID
)
2481 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2482 ERR("HeapAlloc failed!\n");
2486 WideCharToMultiByte(CP_ACP
, 0, ppi7w
->pszObjectGUID
, -1, pszaObjectGUID
, cch
+ 1, NULL
, NULL
);
2487 StringCchCopyA(ppi7a
->pszObjectGUID
, cch
+ 1, pszaObjectGUID
);
2489 HeapFree(hProcessHeap
, 0, pszaObjectGUID
);
2495 RosConvertUnicodeDevModeToAnsiDevmode(ppi9w
->pDevMode
, ppi9a
->pDevMode
);
2499 dwErrorCode
= ERROR_SUCCESS
;
2502 SetLastError(dwErrorCode
);
2503 return (dwErrorCode
== ERROR_SUCCESS
);
2507 GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2510 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
2512 TRACE("GetPrinterW(%p, %lu, %p, %lu, %p)\n", hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
);
2517 dwErrorCode
= ERROR_INVALID_HANDLE
;
2521 // Dismiss invalid levels already at this point.
2524 dwErrorCode
= ERROR_INVALID_LEVEL
;
2528 if (cbBuf
&& pPrinter
)
2529 ZeroMemory(pPrinter
, cbBuf
);
2534 dwErrorCode
= _RpcGetPrinter(pHandle
->hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
);
2536 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
2538 dwErrorCode
= RpcExceptionCode();
2539 ERR("_RpcGetPrinter failed with exception code %lu!\n", dwErrorCode
);
2543 if (dwErrorCode
== ERROR_SUCCESS
)
2545 // Replace relative offset addresses in the output by absolute pointers.
2547 MarshallUpStructure(cbBuf
, pPrinter
, pPrinterInfoMarshalling
[Level
]->pInfo
, pPrinterInfoMarshalling
[Level
]->cbStructureSize
, TRUE
);
2551 SetLastError(dwErrorCode
);
2552 return (dwErrorCode
== ERROR_SUCCESS
);
2556 OpenPrinterA(LPSTR pPrinterName
, LPHANDLE phPrinter
, LPPRINTER_DEFAULTSA pDefault
)
2558 BOOL bReturnValue
= FALSE
;
2560 PWSTR pwszPrinterName
= NULL
;
2561 PRINTER_DEFAULTSW wDefault
= { 0 };
2563 TRACE("OpenPrinterA(%s, %p, %p)\n", pPrinterName
, phPrinter
, pDefault
);
2567 // Convert pPrinterName to a Unicode string pwszPrinterName
2568 cch
= strlen(pPrinterName
);
2570 pwszPrinterName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
2571 if (!pwszPrinterName
)
2573 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2574 ERR("HeapAlloc failed!\n");
2578 MultiByteToWideChar(CP_ACP
, 0, pPrinterName
, -1, pwszPrinterName
, cch
+ 1);
2583 wDefault
.DesiredAccess
= pDefault
->DesiredAccess
;
2585 if (pDefault
->pDatatype
)
2587 // Convert pDefault->pDatatype to a Unicode string wDefault.pDatatype
2588 cch
= strlen(pDefault
->pDatatype
);
2590 wDefault
.pDatatype
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
2591 if (!wDefault
.pDatatype
)
2593 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2594 ERR("HeapAlloc failed!\n");
2598 MultiByteToWideChar(CP_ACP
, 0, pDefault
->pDatatype
, -1, wDefault
.pDatatype
, cch
+ 1);
2601 if (pDefault
->pDevMode
)
2602 wDefault
.pDevMode
= GdiConvertToDevmodeW(pDefault
->pDevMode
);
2605 bReturnValue
= OpenPrinterW(pwszPrinterName
, phPrinter
, &wDefault
);
2609 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)*phPrinter
;
2610 pHandle
->bAnsi
= TRUE
;
2614 if (wDefault
.pDatatype
)
2615 HeapFree(hProcessHeap
, 0, wDefault
.pDatatype
);
2617 if (wDefault
.pDevMode
)
2618 HeapFree(hProcessHeap
, 0, wDefault
.pDevMode
);
2620 if (pwszPrinterName
)
2621 HeapFree(hProcessHeap
, 0, pwszPrinterName
);
2623 return bReturnValue
;
2627 OpenPrinterW(LPWSTR pPrinterName
, LPHANDLE phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2631 PSPOOLER_HANDLE pHandle
;
2632 PWSTR pDatatype
= NULL
;
2633 WINSPOOL_DEVMODE_CONTAINER DevModeContainer
= { 0 };
2634 ACCESS_MASK AccessRequired
= 0;
2636 TRACE("OpenPrinterW(%S, %p, %p)\n", pPrinterName
, phPrinter
, pDefault
);
2641 dwErrorCode
= ERROR_INVALID_PARAMETER
;
2645 // Prepare the additional parameters in the format required by _RpcOpenPrinter
2648 pDatatype
= pDefault
->pDatatype
;
2649 DevModeContainer
.cbBuf
= sizeof(DEVMODEW
);
2650 DevModeContainer
.pDevMode
= (BYTE
*)pDefault
->pDevMode
;
2651 AccessRequired
= pDefault
->DesiredAccess
;
2657 dwErrorCode
= _RpcOpenPrinter(pPrinterName
, &hPrinter
, pDatatype
, &DevModeContainer
, AccessRequired
);
2659 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
2661 dwErrorCode
= RpcExceptionCode();
2662 ERR("_RpcOpenPrinter failed with exception code %lu!\n", dwErrorCode
);
2666 if (dwErrorCode
== ERROR_SUCCESS
)
2668 // Create a new SPOOLER_HANDLE structure.
2669 pHandle
= HeapAlloc(hProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(SPOOLER_HANDLE
));
2672 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2673 ERR("HeapAlloc failed!\n");
2677 pHandle
->Sig
= SPOOLER_HANDLE_SIG
;
2678 pHandle
->hPrinter
= hPrinter
;
2679 pHandle
->hSPLFile
= INVALID_HANDLE_VALUE
;
2680 pHandle
->hSpoolFileHandle
= INVALID_HANDLE_VALUE
;
2682 // Return it as phPrinter.
2683 *phPrinter
= (HANDLE
)pHandle
;
2687 SetLastError(dwErrorCode
);
2688 return (dwErrorCode
== ERROR_SUCCESS
);
2695 PrinterMessageBoxA(HANDLE hPrinter
, DWORD Error
, HWND hWnd
, LPSTR pText
, LPSTR pCaption
, DWORD dwType
)
2701 PrinterMessageBoxW(HANDLE hPrinter
, DWORD Error
, HWND hWnd
, LPWSTR pText
, LPWSTR pCaption
, DWORD dwType
)
2711 VOID
*pvProfileData
,
2712 ULONG
*pcbProfileData
,
2713 FLONG
*pflProfileData
)
2715 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
2719 FIXME("QueryColorProfile(%p, %p, %l, %p, %p, %p)\n", hPrinter
, pdevmode
, ulQueryMode
, pvProfileData
, pcbProfileData
, pflProfileData
);
2721 if ( pHandle
->bNoColorProfile
)
2723 Ret
= (BOOL
)SP_ERROR
;
2730 if (!IsValidDevmodeNoSizeW( pdevmode
) )
2732 ERR("DeviceCapabilitiesW : Devode Invalid");
2737 hLibrary
= LoadPrinterDriver( hPrinter
);
2741 fpQueryColorProfile
= (PVOID
)GetProcAddress( hLibrary
, "DrvQueryColorProfile" );
2743 if ( fpQueryColorProfile
)
2745 Ret
= fpQueryColorProfile( hPrinter
, pdevmode
, ulQueryMode
, pvProfileData
, pcbProfileData
, pflProfileData
);
2749 pHandle
->bNoColorProfile
= TRUE
;
2750 Ret
= (BOOL
)SP_ERROR
;
2753 FreeLibrary(hLibrary
);
2759 // Note from GDI32:printdrv.c
2762 // BOOL return TRUE if successful.
2763 // dlFont 0x0001 for Downloading fonts. 0x0002 unknown XPS_PASS?.
2764 // dwVersion is version of EMFSPOOL. Must be 0x00010000. See [MS-EMFSPOOL] page 18.
2767 #define QSM_DOWNLOADINGFONTS 0x0001
2770 Note from MSDN : "V4 print drivers using RAW mode to send PCL/Postscript have 0 byte spool file"
2772 Use XPS_PASS instead of RAW to pass information directly to the print filter pipeline in
2773 v4 and v3 XPSDrv drivers. Here's how to proceed with Windows 8:
2775 Call GetPrinterDriver to retrieve the DRIVER_INFO_8 structure.
2776 Check DRIVER_INFO_8::dwPrinterDriverAttributes for the PRINTER_DRIVER_XPS flag.
2777 Choose your datatype based on the presence or absence of the flag:
2778 If the flag is set, use XPS_PASS.
2779 If the flag isn't set, use RAW.
2782 #define QSM_XPS_PASS 0x0002 // Guessing. PRINTER_DRIVER_XPS?
2785 QuerySpoolMode( HANDLE hPrinter
, PDWORD downloadFontsFlags
, PDWORD dwVersion
)
2787 PRINTER_INFO_2W
*pi2
= NULL
;
2791 FIXME("QuerySpoolMode(%p, %p, %p)\n", hPrinter
, downloadFontsFlags
, dwVersion
);
2793 res
= GetPrinterW( hPrinter
, 2, NULL
, 0, &needed
);
2794 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
))
2796 pi2
= HeapAlloc(hProcessHeap
, 0, needed
);
2797 res
= GetPrinterW(hPrinter
, 2, (LPBYTE
)pi2
, needed
, &needed
);
2802 *dwVersion
= 0x10000;
2803 *downloadFontsFlags
= 0;
2805 if ( pi2
->pServerName
)
2807 *downloadFontsFlags
|= QSM_DOWNLOADINGFONTS
;
2812 // To do : Add GetPrinterDriver for DRIVER_INFO_8, test PRINTER_DRIVER_XPS flag,
2813 // to set *downloadFontsFlags |= QSM_XPS_PASS;
2815 // Vista+ looks for QSM_XPS_PASS to be set in GDI32.
2817 HeapFree(hProcessHeap
, 0, pi2
);
2822 // This requires IC support.
2825 QueryRemoteFonts( HANDLE hPrinter
, PUNIVERSAL_FONT_ID pufi
, ULONG NumberOfUFIs
)
2828 DWORD Result
= -1, cOut
, cIn
= 0;
2831 FIXME("QueryRemoteFonts(%p, %p, %lu)\n", hPrinter
, pufi
, NumberOfUFIs
);
2833 hIC
= CreatePrinterIC( hPrinter
, NULL
);
2836 cOut
= (NumberOfUFIs
* sizeof(UNIVERSAL_FONT_ID
)) + sizeof(DWORD
); // Include "DWORD" first part to return size.
2838 pOut
= HeapAlloc( hProcessHeap
, 0, cOut
);
2841 if ( PlayGdiScriptOnPrinterIC( hIC
, (LPBYTE
)&cIn
, sizeof(DWORD
), pOut
, cOut
, 0 ) )
2843 cIn
= *((PDWORD
)pOut
); // Fisrt part is the size of the UFID object.
2845 Result
= cIn
; // Return the required size.
2847 if( NumberOfUFIs
< cIn
)
2851 // Copy whole object back to GDI32, exclude first DWORD part.
2852 memcpy( pufi
, pOut
+ sizeof(DWORD
), cIn
* sizeof(UNIVERSAL_FONT_ID
) );
2854 HeapFree( hProcessHeap
, 0, pOut
);
2856 DeletePrinterIC( hIC
);
2862 ReadPrinter(HANDLE hPrinter
, PVOID pBuf
, DWORD cbBuf
, PDWORD pNoBytesRead
)
2865 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
2867 TRACE("ReadPrinter(%p, %p, %lu, %p)\n", hPrinter
, pBuf
, cbBuf
, pNoBytesRead
);
2872 dwErrorCode
= ERROR_INVALID_HANDLE
;
2879 dwErrorCode
= _RpcReadPrinter(pHandle
->hPrinter
, pBuf
, cbBuf
, pNoBytesRead
);
2881 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
2883 dwErrorCode
= RpcExceptionCode();
2884 ERR("_RpcReadPrinter failed with exception code %lu!\n", dwErrorCode
);
2889 SetLastError(dwErrorCode
);
2890 return (dwErrorCode
== ERROR_SUCCESS
);
2894 ResetPrinterA(HANDLE hPrinter
, PPRINTER_DEFAULTSA pDefault
)
2897 UNICODE_STRING pNameW
;
2898 PDEVMODEW pdmw
= NULL
;
2899 PPRINTER_DEFAULTSW pdw
= (PPRINTER_DEFAULTSW
)pDefault
;
2901 TRACE("ResetPrinterA(%p, %p)\n", hPrinter
, pDefault
);
2903 if ( pDefault
->pDatatype
== (LPSTR
)-1 )
2905 pdw
->pDatatype
= (LPWSTR
)-1;
2909 pdw
->pDatatype
= AsciiToUnicode( &pNameW
, pDefault
->pDatatype
);
2911 if ( pDefault
->pDevMode
== (LPDEVMODEA
)-1)
2913 pdw
->pDevMode
= (LPDEVMODEW
)-1;
2917 if ( pDefault
->pDevMode
)//&& IsValidDevmodeNoSizeW( pDefault->pDevMode ) )
2919 RosConvertAnsiDevModeToUnicodeDevmode( pDefault
->pDevMode
, &pdmw
);
2920 pdw
->pDevMode
= pdmw
;
2924 ret
= ResetPrinterW( hPrinter
, pdw
);
2926 if (pdmw
) HeapFree(hProcessHeap
, 0, pdmw
);
2928 RtlFreeUnicodeString( &pNameW
);
2934 ResetPrinterW(HANDLE hPrinter
, PPRINTER_DEFAULTSW pDefault
)
2936 TRACE("ResetPrinterW(%p, %p)\n", hPrinter
, pDefault
);
2942 SeekPrinter( HANDLE hPrinter
, LARGE_INTEGER liDistanceToMove
, PLARGE_INTEGER pliNewPointer
, DWORD dwMoveMethod
, BOOL bWrite
)
2945 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
2947 FIXME("SeekPrinter(%p, %I64u, %p, %lu, %d)\n", hPrinter
, liDistanceToMove
.QuadPart
, pliNewPointer
, dwMoveMethod
, bWrite
);
2952 dwErrorCode
= ERROR_INVALID_HANDLE
;
2959 dwErrorCode
= _RpcSeekPrinter(pHandle
->hPrinter
, liDistanceToMove
, pliNewPointer
, dwMoveMethod
, bWrite
);
2961 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
2963 dwErrorCode
= RpcExceptionCode();
2964 ERR("_RpcSeekPrinter failed with exception code %lu!\n", dwErrorCode
);
2969 SetLastError(dwErrorCode
);
2970 return (dwErrorCode
== ERROR_SUCCESS
);
2974 SetDefaultPrinterA(LPCSTR pszPrinter
)
2976 BOOL bReturnValue
= FALSE
;
2978 PWSTR pwszPrinter
= NULL
;
2980 TRACE("SetDefaultPrinterA(%s)\n", pszPrinter
);
2984 // Convert pszPrinter to a Unicode string pwszPrinter
2985 cch
= strlen(pszPrinter
);
2987 pwszPrinter
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
2990 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2991 ERR("HeapAlloc failed!\n");
2995 MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, pwszPrinter
, cch
+ 1);
2998 bReturnValue
= SetDefaultPrinterW(pwszPrinter
);
3002 HeapFree(hProcessHeap
, 0, pwszPrinter
);
3004 return bReturnValue
;
3008 SetDefaultPrinterW(LPCWSTR pszPrinter
)
3010 const WCHAR wszDevicesKey
[] = L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Devices";
3012 DWORD cbDeviceValueData
;
3013 DWORD cbPrinterValueData
= 0;
3016 HKEY hDevicesKey
= NULL
;
3017 HKEY hWindowsKey
= NULL
;
3018 PWSTR pwszDeviceValueData
= NULL
;
3019 WCHAR wszPrinter
[MAX_PRINTER_NAME
+ 1];
3021 TRACE("SetDefaultPrinterW(%S)\n", pszPrinter
);
3023 // Open the Devices registry key.
3024 dwErrorCode
= (DWORD
)RegOpenKeyExW(HKEY_CURRENT_USER
, wszDevicesKey
, 0, KEY_READ
, &hDevicesKey
);
3025 if (dwErrorCode
!= ERROR_SUCCESS
)
3027 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode
);
3031 // Did the caller give us a printer to set as default?
3032 if (pszPrinter
&& *pszPrinter
)
3034 // Check if the given printer exists and query the value data size.
3035 dwErrorCode
= (DWORD
)RegQueryValueExW(hDevicesKey
, pszPrinter
, NULL
, NULL
, NULL
, &cbPrinterValueData
);
3036 if (dwErrorCode
== ERROR_FILE_NOT_FOUND
)
3038 dwErrorCode
= ERROR_INVALID_PRINTER_NAME
;
3041 else if (dwErrorCode
!= ERROR_SUCCESS
)
3043 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode
);
3047 cchPrinter
= wcslen(pszPrinter
);
3051 // If there is already a default printer, we're done!
3052 cchPrinter
= _countof(wszPrinter
);
3053 if (GetDefaultPrinterW(wszPrinter
, &cchPrinter
))
3055 dwErrorCode
= ERROR_SUCCESS
;
3059 // Otherwise, get us the first printer from the "Devices" key to later set it as default and query the value data size.
3060 cchPrinter
= _countof(wszPrinter
);
3061 dwErrorCode
= (DWORD
)RegEnumValueW(hDevicesKey
, 0, wszPrinter
, &cchPrinter
, NULL
, NULL
, NULL
, &cbPrinterValueData
);
3062 if (dwErrorCode
!= ERROR_MORE_DATA
)
3065 pszPrinter
= wszPrinter
;
3068 // We now need to query the value data, which has the format "winspool,<Port>:"
3069 // and make "<Printer Name>,winspool,<Port>:" out of it.
3070 // Allocate a buffer large enough for the final data.
3071 cbDeviceValueData
= (cchPrinter
+ 1) * sizeof(WCHAR
) + cbPrinterValueData
;
3072 pwszDeviceValueData
= HeapAlloc(hProcessHeap
, 0, cbDeviceValueData
);
3073 if (!pwszDeviceValueData
)
3075 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
3076 ERR("HeapAlloc failed!\n");
3080 // Copy the Printer Name and a comma into it.
3081 CopyMemory(pwszDeviceValueData
, pszPrinter
, cchPrinter
* sizeof(WCHAR
));
3082 pwszDeviceValueData
[cchPrinter
] = L
',';
3084 // Append the value data, which has the format "winspool,<Port>:"
3085 dwErrorCode
= (DWORD
)RegQueryValueExW(hDevicesKey
, pszPrinter
, NULL
, NULL
, (PBYTE
)&pwszDeviceValueData
[cchPrinter
+ 1], &cbPrinterValueData
);
3086 if (dwErrorCode
!= ERROR_SUCCESS
)
3089 // Open the Windows registry key.
3090 dwErrorCode
= (DWORD
)RegOpenKeyExW(HKEY_CURRENT_USER
, wszWindowsKey
, 0, KEY_SET_VALUE
, &hWindowsKey
);
3091 if (dwErrorCode
!= ERROR_SUCCESS
)
3093 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode
);
3097 // Store our new default printer.
3098 dwErrorCode
= (DWORD
)RegSetValueExW(hWindowsKey
, wszDeviceValue
, 0, REG_SZ
, (PBYTE
)pwszDeviceValueData
, cbDeviceValueData
);
3099 if (dwErrorCode
!= ERROR_SUCCESS
)
3101 ERR("RegSetValueExW failed with status %lu!\n", dwErrorCode
);
3107 RegCloseKey(hDevicesKey
);
3110 RegCloseKey(hWindowsKey
);
3112 if (pwszDeviceValueData
)
3113 HeapFree(hProcessHeap
, 0, pwszDeviceValueData
);
3115 SetLastError(dwErrorCode
);
3116 return (dwErrorCode
== ERROR_SUCCESS
);
3120 SetPrinterA(HANDLE hPrinter
, DWORD Level
, PBYTE pPrinter
, DWORD Command
)
3123 UNICODE_STRING usBuffer
;
3124 PPRINTER_INFO_STRESS ppisa
= (PPRINTER_INFO_STRESS
)pPrinter
;
3125 PPRINTER_INFO_STRESS ppisw
= (PPRINTER_INFO_STRESS
)pPrinter
;
3126 PPRINTER_INFO_2A ppi2a
= (PPRINTER_INFO_2A
)pPrinter
;
3127 PPRINTER_INFO_2W ppi2w
= (PPRINTER_INFO_2W
)pPrinter
;
3128 PPRINTER_INFO_7A ppi7a
= (PPRINTER_INFO_7A
)pPrinter
;
3129 PPRINTER_INFO_7W ppi7w
= (PPRINTER_INFO_7W
)pPrinter
;
3130 PPRINTER_INFO_9A ppi9a
= (PPRINTER_INFO_9A
)pPrinter
;
3131 PPRINTER_INFO_9W ppi9w
= (PPRINTER_INFO_9W
)pPrinter
;
3132 PWSTR pwszPrinterName
= NULL
;
3133 PWSTR pwszServerName
= NULL
;
3134 PWSTR pwszShareName
= NULL
;
3135 PWSTR pwszPortName
= NULL
;
3136 PWSTR pwszDriverName
= NULL
;
3137 PWSTR pwszComment
= NULL
;
3138 PWSTR pwszLocation
= NULL
;
3139 PWSTR pwszSepFile
= NULL
;
3140 PWSTR pwszPrintProcessor
= NULL
;
3141 PWSTR pwszDatatype
= NULL
;
3142 PWSTR pwszParameters
= NULL
;
3143 PDEVMODEW pdmw
= NULL
;
3145 FIXME("SetPrinterA(%p, %lu, %p, %lu)\n", hPrinter
, Level
, pPrinter
, Command
);
3152 if (ppisa
->pPrinterName
)
3154 pwszPrinterName
= AsciiToUnicode(&usBuffer
, (LPCSTR
)ppisa
->pPrinterName
);
3155 if (!(ppisw
->pPrinterName
= pwszPrinterName
)) goto Cleanup
;
3157 if (ppisa
->pServerName
)
3159 pwszServerName
= AsciiToUnicode(&usBuffer
, (LPCSTR
)ppisa
->pServerName
);
3160 if (!(ppisw
->pPrinterName
= pwszServerName
)) goto Cleanup
;
3163 if ( Command
== PRINTER_CONTROL_SET_STATUS
)
3165 // Set the pPrinter parameter to a pointer to a DWORD value that specifies the new printer status.
3167 pi6
.dwStatus
= (DWORD_PTR
)pPrinter
;
3168 pPrinter
= (LPBYTE
)&pi6
;
3175 if (ppi2a
->pShareName
)
3177 pwszShareName
= AsciiToUnicode(&usBuffer
, ppi2a
->pShareName
);
3178 if (!(ppi2w
->pShareName
= pwszShareName
)) goto Cleanup
;
3180 if (ppi2a
->pPortName
)
3182 pwszPortName
= AsciiToUnicode(&usBuffer
, ppi2a
->pPortName
);
3183 if (!(ppi2w
->pPortName
= pwszPortName
)) goto Cleanup
;
3185 if (ppi2a
->pDriverName
)
3187 pwszDriverName
= AsciiToUnicode(&usBuffer
, ppi2a
->pDriverName
);
3188 if (!(ppi2w
->pDriverName
= pwszDriverName
)) goto Cleanup
;
3190 if (ppi2a
->pComment
)
3192 pwszComment
= AsciiToUnicode(&usBuffer
, ppi2a
->pComment
);
3193 if (!(ppi2w
->pComment
= pwszComment
)) goto Cleanup
;
3195 if (ppi2a
->pLocation
)
3197 pwszLocation
= AsciiToUnicode(&usBuffer
, ppi2a
->pLocation
);
3198 if (!(ppi2w
->pLocation
= pwszLocation
)) goto Cleanup
;
3200 if (ppi2a
->pSepFile
)
3202 pwszSepFile
= AsciiToUnicode(&usBuffer
, ppi2a
->pSepFile
);
3203 if (!(ppi2w
->pSepFile
= pwszSepFile
)) goto Cleanup
;
3205 if (ppi2a
->pServerName
)
3207 pwszPrintProcessor
= AsciiToUnicode(&usBuffer
, ppi2a
->pPrintProcessor
);
3208 if (!(ppi2w
->pPrintProcessor
= pwszPrintProcessor
)) goto Cleanup
;
3210 if (ppi2a
->pDatatype
)
3212 pwszDatatype
= AsciiToUnicode(&usBuffer
, ppi2a
->pDatatype
);
3213 if (!(ppi2w
->pDatatype
= pwszDatatype
)) goto Cleanup
;
3215 if (ppi2a
->pParameters
)
3217 pwszParameters
= AsciiToUnicode(&usBuffer
, ppi2a
->pParameters
);
3218 if (!(ppi2w
->pParameters
= pwszParameters
)) goto Cleanup
;
3221 if ( ppi2a
->pDevMode
)
3223 RosConvertAnsiDevModeToUnicodeDevmode( ppi2a
->pDevMode
, &pdmw
);
3224 ppi2w
->pDevMode
= pdmw
;
3228 // These two strings are relitive and common to these three Levels.
3234 if (ppi2a
->pServerName
) // 4 & 5 : pPrinterName.
3236 pwszServerName
= AsciiToUnicode(&usBuffer
, ppi2a
->pServerName
);
3237 if (!(ppi2w
->pPrinterName
= pwszServerName
)) goto Cleanup
;
3239 if (ppi2a
->pPrinterName
) // 4 : pServerName, 5 : pPortName.
3241 pwszPrinterName
= AsciiToUnicode(&usBuffer
, ppi2a
->pPrinterName
);
3242 if (!(ppi2w
->pPrinterName
= pwszPrinterName
)) goto Cleanup
;
3251 if (ppi7a
->pszObjectGUID
)
3253 pwszPrinterName
= AsciiToUnicode(&usBuffer
, ppi7a
->pszObjectGUID
);
3254 if (!(ppi7w
->pszObjectGUID
= pwszPrinterName
)) goto Cleanup
;
3260 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
3261 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3265 RosConvertAnsiDevModeToUnicodeDevmode( ppi9a
->pDevMode
, &pdmw
);
3266 ppi9w
->pDevMode
= pdmw
;
3271 FIXME( "Unsupported level %d\n", Level
);
3272 SetLastError( ERROR_INVALID_LEVEL
);
3275 Ret
= SetPrinterW( hPrinter
, Level
, pPrinter
, Command
);
3278 if (pdmw
) HeapFree(hProcessHeap
, 0, pdmw
);
3279 if (pwszPrinterName
) HeapFree(hProcessHeap
, 0, pwszPrinterName
);
3280 if (pwszServerName
) HeapFree(hProcessHeap
, 0, pwszServerName
);
3281 if (pwszShareName
) HeapFree(hProcessHeap
, 0, pwszShareName
);
3282 if (pwszPortName
) HeapFree(hProcessHeap
, 0, pwszPortName
);
3283 if (pwszDriverName
) HeapFree(hProcessHeap
, 0, pwszDriverName
);
3284 if (pwszComment
) HeapFree(hProcessHeap
, 0, pwszComment
);
3285 if (pwszLocation
) HeapFree(hProcessHeap
, 0, pwszLocation
);
3286 if (pwszSepFile
) HeapFree(hProcessHeap
, 0, pwszSepFile
);
3287 if (pwszPrintProcessor
) HeapFree(hProcessHeap
, 0, pwszPrintProcessor
);
3288 if (pwszDatatype
) HeapFree(hProcessHeap
, 0, pwszDatatype
);
3289 if (pwszParameters
) HeapFree(hProcessHeap
, 0, pwszParameters
);
3294 SetPrinterW(HANDLE hPrinter
, DWORD Level
, PBYTE pPrinter
, DWORD Command
)
3297 WINSPOOL_PRINTER_CONTAINER PrinterContainer
;
3298 WINSPOOL_DEVMODE_CONTAINER DevModeContainer
;
3299 WINSPOOL_SECURITY_CONTAINER SecurityContainer
;
3300 SECURITY_DESCRIPTOR
*sd
= NULL
;
3302 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
3304 FIXME("SetPrinterW(%p, %lu, %p, %lu)\n", hPrinter
, Level
, pPrinter
, Command
);
3308 return ERROR_INVALID_HANDLE
;
3310 DevModeContainer
.cbBuf
= 0;
3311 DevModeContainer
.pDevMode
= NULL
;
3313 SecurityContainer
.cbBuf
= 0;
3314 SecurityContainer
.pSecurity
= NULL
;
3319 if ( Command
== PRINTER_CONTROL_SET_STATUS
)
3321 // Set the pPrinter parameter to a pointer to a DWORD value that specifies the new printer status.
3323 pi6
.dwStatus
= (DWORD_PTR
)pPrinter
;
3324 pPrinter
= (LPBYTE
)&pi6
;
3331 PPRINTER_INFO_2W pi2w
= (PPRINTER_INFO_2W
)pPrinter
;
3334 if ( pi2w
->pDevMode
)
3336 if ( IsValidDevmodeNoSizeW( pi2w
->pDevMode
) )
3338 DevModeContainer
.cbBuf
= pi2w
->pDevMode
->dmSize
+ pi2w
->pDevMode
->dmDriverExtra
;
3339 DevModeContainer
.pDevMode
= (PBYTE
)pi2w
->pDevMode
;
3343 if ( pi2w
->pSecurityDescriptor
)
3345 sd
= get_sd( pi2w
->pSecurityDescriptor
, &size
);
3348 SecurityContainer
.cbBuf
= size
;
3349 SecurityContainer
.pSecurity
= (PBYTE
)sd
;
3355 SetLastError(ERROR_INVALID_PARAMETER
);
3362 PPRINTER_INFO_3 pi3
= (PPRINTER_INFO_3
)pPrinter
;
3365 if ( pi3
->pSecurityDescriptor
)
3367 sd
= get_sd( pi3
->pSecurityDescriptor
, &size
);
3370 SecurityContainer
.cbBuf
= size
;
3371 SecurityContainer
.pSecurity
= (PBYTE
)sd
;
3377 SetLastError(ERROR_INVALID_PARAMETER
);
3387 if ( pPrinter
== NULL
)
3389 SetLastError(ERROR_INVALID_PARAMETER
);
3395 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
3396 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3400 PPRINTER_INFO_9W pi9w
= (PPRINTER_INFO_9W
)pPrinter
;
3403 if ( pi9w
->pDevMode
)
3405 if ( IsValidDevmodeNoSizeW( pi9w
->pDevMode
) )
3407 DevModeContainer
.cbBuf
= pi9w
->pDevMode
->dmSize
+ pi9w
->pDevMode
->dmDriverExtra
;
3408 DevModeContainer
.pDevMode
= (LPBYTE
)pi9w
->pDevMode
;
3416 FIXME( "Unsupported level %d\n", Level
);
3417 SetLastError( ERROR_INVALID_LEVEL
);
3421 PrinterContainer
.PrinterInfo
.pPrinterInfo1
= (WINSPOOL_PRINTER_INFO_1
*)pPrinter
;
3422 PrinterContainer
.Level
= Level
;
3427 dwErrorCode
= _RpcSetPrinter(pHandle
->hPrinter
, &PrinterContainer
, &DevModeContainer
, &SecurityContainer
, Command
);
3429 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
3431 dwErrorCode
= RpcExceptionCode();
3435 if ( sd
) HeapFree( GetProcessHeap(), 0, sd
);
3437 SetLastError(dwErrorCode
);
3438 return (dwErrorCode
== ERROR_SUCCESS
);
3442 SplDriverUnloadComplete(LPWSTR pDriverFile
)
3444 TRACE("DriverUnloadComplete(%S)\n", pDriverFile
);
3446 return TRUE
; // return true for now.
3450 SpoolerPrinterEvent( LPWSTR pPrinterName
, INT DriverEvent
, DWORD Flags
, LPARAM lParam
)
3456 if ( OpenPrinterW( pPrinterName
, &hPrinter
, NULL
) )
3458 hLibrary
= LoadPrinterDriver( hPrinter
);
3462 fpPrinterEvent
= (PVOID
)GetProcAddress( hLibrary
, "DrvPrinterEvent" );
3464 if ( fpPrinterEvent
)
3466 Ret
= fpPrinterEvent( pPrinterName
, DriverEvent
, Flags
, lParam
);
3469 FreeLibrary(hLibrary
);
3472 ClosePrinter( hPrinter
);
3478 INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
3485 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
3489 if(HIWORD(wparam
) == BN_CLICKED
)
3491 if(LOWORD(wparam
) == IDOK
)
3494 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
3497 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
3498 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
3500 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
3502 WCHAR caption
[200], message
[200];
3505 LoadStringW(hinstWinSpool
, IDS_CAPTION
, caption
, ARRAYSIZE(caption
));
3506 LoadStringW(hinstWinSpool
, IDS_FILE_EXISTS
, message
, ARRAYSIZE(message
));
3507 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
3508 if(mb_ret
== IDCANCEL
)
3510 HeapFree(GetProcessHeap(), 0, filename
);
3514 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3515 if(hf
== INVALID_HANDLE_VALUE
)
3517 WCHAR caption
[200], message
[200];
3519 LoadStringW(hinstWinSpool
, IDS_CAPTION
, caption
, ARRAYSIZE(caption
));
3520 LoadStringW(hinstWinSpool
, IDS_CANNOT_OPEN
, message
, ARRAYSIZE(message
));
3521 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
3522 HeapFree(GetProcessHeap(), 0, filename
);
3526 DeleteFileW(filename
);
3527 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
3529 EndDialog(hwnd
, IDOK
);
3532 if(LOWORD(wparam
) == IDCANCEL
)
3534 EndDialog(hwnd
, IDCANCEL
);
3543 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
3546 StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
3549 DWORD len
, attr
, retDlg
;
3551 FIXME("StartDocDlgW(%p, %p)\n", hPrinter
, doc
);
3553 if (doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
3555 PRINTER_INFO_5W
*pi5
;
3556 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
3557 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
3559 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
3560 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
3561 if (!pi5
->pPortName
|| wcsicmp(pi5
->pPortName
, FILE_Port
))
3563 HeapFree(GetProcessHeap(), 0, pi5
);
3566 HeapFree(GetProcessHeap(), 0, pi5
);
3569 if (doc
->lpszOutput
== NULL
|| !wcsicmp(doc
->lpszOutput
, FILE_Port
))
3573 retDlg
= DialogBoxParamW( hinstWinSpool
,
3574 MAKEINTRESOURCEW(FILENAME_DIALOG
),
3575 GetForegroundWindow(),
3579 if ( retDlg
== IDOK
)
3581 if (!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
3583 HeapFree(GetProcessHeap(), 0, name
);
3586 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3587 GetFullPathNameW(name
, len
, ret
, NULL
);
3588 HeapFree(GetProcessHeap(), 0, name
);
3590 else if ( retDlg
== 0 ) // FALSE, some type of error occurred.
3592 ret
= (LPWSTR
)SP_ERROR
;
3594 else if ( retDlg
== IDCANCEL
)
3596 SetLastError( ERROR_CANCELLED
);
3597 ret
= (LPWSTR
)SP_APPABORT
;
3602 if (!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
3605 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3606 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
3608 attr
= GetFileAttributesW(ret
);
3609 if (attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
3611 HeapFree(GetProcessHeap(), 0, ret
);
3618 StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
3620 UNICODE_STRING usBuffer
;
3621 DOCINFOW docW
= { 0 };
3623 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
3626 docW
.cbSize
= sizeof(docW
);
3627 if (doc
->lpszDocName
)
3629 docnameW
= AsciiToUnicode(&usBuffer
, doc
->lpszDocName
);
3630 if (!(docW
.lpszDocName
= docnameW
)) goto failed
;
3632 if (doc
->lpszOutput
)
3634 outputW
= AsciiToUnicode(&usBuffer
, doc
->lpszOutput
);
3635 if (!(docW
.lpszOutput
= outputW
)) goto failed
;
3637 if (doc
->lpszDatatype
)
3639 datatypeW
= AsciiToUnicode(&usBuffer
, doc
->lpszDatatype
);
3640 if (!(docW
.lpszDatatype
= datatypeW
)) goto failed
;
3642 docW
.fwType
= doc
->fwType
;
3644 retW
= StartDocDlgW(hPrinter
, &docW
);
3648 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
3649 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
3650 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
3651 HeapFree(GetProcessHeap(), 0, retW
);
3655 if (datatypeW
) HeapFree(GetProcessHeap(), 0, datatypeW
);
3656 if (outputW
) HeapFree(GetProcessHeap(), 0, outputW
);
3657 if (docnameW
) HeapFree(GetProcessHeap(), 0, docnameW
);
3663 StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, PBYTE pDocInfo
)
3665 DOC_INFO_1W wDocInfo1
= { 0 };
3668 DWORD dwReturnValue
= 0;
3669 PDOC_INFO_1A pDocInfo1
= (PDOC_INFO_1A
)pDocInfo
;
3671 TRACE("StartDocPrinterA(%p, %lu, %p)\n", hPrinter
, Level
, pDocInfo
);
3673 // Only check the minimum required for accessing pDocInfo.
3674 // Additional sanity checks are done in StartDocPrinterW.
3677 dwErrorCode
= ERROR_INVALID_PARAMETER
;
3683 ERR("Level = %d, unsupported!\n", Level
);
3684 dwErrorCode
= ERROR_INVALID_LEVEL
;
3688 if (pDocInfo1
->pDatatype
)
3690 // Convert pDocInfo1->pDatatype to a Unicode string wDocInfo1.pDatatype
3691 cch
= strlen(pDocInfo1
->pDatatype
);
3693 wDocInfo1
.pDatatype
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
3694 if (!wDocInfo1
.pDatatype
)
3696 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
3697 ERR("HeapAlloc failed!\n");
3701 MultiByteToWideChar(CP_ACP
, 0, pDocInfo1
->pDatatype
, -1, wDocInfo1
.pDatatype
, cch
+ 1);
3704 if (pDocInfo1
->pDocName
)
3706 // Convert pDocInfo1->pDocName to a Unicode string wDocInfo1.pDocName
3707 cch
= strlen(pDocInfo1
->pDocName
);
3709 wDocInfo1
.pDocName
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
3710 if (!wDocInfo1
.pDocName
)
3712 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
3713 ERR("HeapAlloc failed!\n");
3717 MultiByteToWideChar(CP_ACP
, 0, pDocInfo1
->pDocName
, -1, wDocInfo1
.pDocName
, cch
+ 1);
3720 if (pDocInfo1
->pOutputFile
)
3722 // Convert pDocInfo1->pOutputFile to a Unicode string wDocInfo1.pOutputFile
3723 cch
= strlen(pDocInfo1
->pOutputFile
);
3725 wDocInfo1
.pOutputFile
= HeapAlloc(hProcessHeap
, 0, (cch
+ 1) * sizeof(WCHAR
));
3726 if (!wDocInfo1
.pOutputFile
)
3728 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
3729 ERR("HeapAlloc failed!\n");
3733 MultiByteToWideChar(CP_ACP
, 0, pDocInfo1
->pOutputFile
, -1, wDocInfo1
.pOutputFile
, cch
+ 1);
3736 dwReturnValue
= StartDocPrinterW(hPrinter
, Level
, (PBYTE
)&wDocInfo1
);
3737 dwErrorCode
= GetLastError();
3740 if (wDocInfo1
.pDatatype
)
3741 HeapFree(hProcessHeap
, 0, wDocInfo1
.pDatatype
);
3743 if (wDocInfo1
.pDocName
)
3744 HeapFree(hProcessHeap
, 0, wDocInfo1
.pDocName
);
3746 if (wDocInfo1
.pOutputFile
)
3747 HeapFree(hProcessHeap
, 0, wDocInfo1
.pOutputFile
);
3749 SetLastError(dwErrorCode
);
3750 return dwReturnValue
;
3754 StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, PBYTE pDocInfo
)
3756 DWORD cbAddJobInfo1
;
3759 DWORD dwReturnValue
= 0;
3760 PADDJOB_INFO_1W pAddJobInfo1
= NULL
;
3761 PDOC_INFO_1W pDocInfo1
= (PDOC_INFO_1W
)pDocInfo
;
3762 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
3764 TRACE("StartDocPrinterW(%p, %lu, %p)\n", hPrinter
, Level
, pDocInfo
);
3769 dwErrorCode
= ERROR_INVALID_HANDLE
;
3775 dwErrorCode
= ERROR_INVALID_PARAMETER
;
3781 ERR("Level = %d, unsupported!\n", Level
);
3782 dwErrorCode
= ERROR_INVALID_LEVEL
;
3786 if (pHandle
->bStartedDoc
)
3788 dwErrorCode
= ERROR_INVALID_PRINTER_STATE
;
3792 // Check if we want to redirect output into a file.
3793 if (pDocInfo1
->pOutputFile
)
3795 // Do a StartDocPrinter RPC call in this case.
3796 dwErrorCode
= _StartDocPrinterWithRPC(pHandle
, pDocInfo1
);
3800 // Allocate memory for the ADDJOB_INFO_1W structure and a path.
3801 cbAddJobInfo1
= sizeof(ADDJOB_INFO_1W
) + MAX_PATH
* sizeof(WCHAR
);
3802 pAddJobInfo1
= HeapAlloc(hProcessHeap
, 0, cbAddJobInfo1
);
3805 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
3806 ERR("HeapAlloc failed!\n");
3810 // Try to add a new job.
3811 // This only succeeds if the printer is set to do spooled printing.
3812 if (AddJobW((HANDLE
)pHandle
, 1, (PBYTE
)pAddJobInfo1
, cbAddJobInfo1
, &cbNeeded
))
3814 // Do spooled printing.
3815 dwErrorCode
= _StartDocPrinterSpooled(pHandle
, pDocInfo1
, pAddJobInfo1
);
3817 else if (GetLastError() == ERROR_INVALID_ACCESS
)
3819 // ERROR_INVALID_ACCESS is returned when the printer is set to do direct printing.
3820 // In this case, we do a StartDocPrinter RPC call.
3821 dwErrorCode
= _StartDocPrinterWithRPC(pHandle
, pDocInfo1
);
3825 dwErrorCode
= GetLastError();
3826 ERR("AddJobW failed with error %lu!\n", dwErrorCode
);
3831 if (dwErrorCode
== ERROR_SUCCESS
)
3833 pHandle
->bStartedDoc
= TRUE
;
3834 dwReturnValue
= pHandle
->dwJobID
;
3835 if ( !pHandle
->bTrayIcon
)
3837 UpdateTrayIcon( hPrinter
, pHandle
->dwJobID
);
3843 HeapFree(hProcessHeap
, 0, pAddJobInfo1
);
3845 SetLastError(dwErrorCode
);
3846 return dwReturnValue
;
3850 StartPagePrinter(HANDLE hPrinter
)
3853 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
3855 TRACE("StartPagePrinter(%p)\n", hPrinter
);
3860 dwErrorCode
= ERROR_INVALID_HANDLE
;
3867 dwErrorCode
= _RpcStartPagePrinter(pHandle
->hPrinter
);
3869 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
3871 dwErrorCode
= RpcExceptionCode();
3872 ERR("_RpcStartPagePrinter failed with exception code %lu!\n", dwErrorCode
);
3877 SetLastError(dwErrorCode
);
3878 return (dwErrorCode
== ERROR_SUCCESS
);
3882 WritePrinter(HANDLE hPrinter
, PVOID pBuf
, DWORD cbBuf
, PDWORD pcWritten
)
3885 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hPrinter
;
3887 TRACE("WritePrinter(%p, %p, %lu, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
3892 dwErrorCode
= ERROR_INVALID_HANDLE
;
3896 if (!pHandle
->bStartedDoc
)
3898 dwErrorCode
= ERROR_SPL_NO_STARTDOC
;
3902 if (pHandle
->hSPLFile
!= INVALID_HANDLE_VALUE
)
3904 // Write to the spool file. This doesn't need an RPC request.
3905 if (!WriteFile(pHandle
->hSPLFile
, pBuf
, cbBuf
, pcWritten
, NULL
))
3907 dwErrorCode
= GetLastError();
3908 ERR("WriteFile failed with error %lu!\n", dwErrorCode
);
3912 dwErrorCode
= ERROR_SUCCESS
;
3916 // TODO: This case (for direct printing or remote printing) has bad performance if multiple small-sized WritePrinter calls are performed.
3917 // We may increase performance by writing into a buffer and only doing a single RPC call when the buffer is full.
3922 dwErrorCode
= _RpcWritePrinter(pHandle
->hPrinter
, pBuf
, cbBuf
, pcWritten
);
3924 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
3926 dwErrorCode
= RpcExceptionCode();
3927 ERR("_RpcWritePrinter failed with exception code %lu!\n", dwErrorCode
);
3933 SetLastError(dwErrorCode
);
3934 return (dwErrorCode
== ERROR_SUCCESS
);
3938 XcvDataW(HANDLE hXcv
, PCWSTR pszDataName
, PBYTE pInputData
, DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
, PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
3940 DWORD dwErrorCode
, Bogus
= 0;
3941 PSPOOLER_HANDLE pHandle
= (PSPOOLER_HANDLE
)hXcv
;
3943 TRACE("XcvDataW(%p, %S, %p, %lu, %p, %lu, %p, %p)\n", hXcv
, pszDataName
, pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
3945 if ( pcbOutputNeeded
== NULL
)
3947 dwErrorCode
= ERROR_INVALID_PARAMETER
;
3952 if (!pHandle
) // ( IntProtectHandle( hXcv, FALSE ) )
3954 dwErrorCode
= ERROR_INVALID_HANDLE
;
3961 if ( pInputData
== NULL
)
3965 pInputData
= (PBYTE
)&Bogus
;
3969 if ( pOutputData
== NULL
)
3971 if ( !cbOutputData
)
3973 pOutputData
= (PBYTE
)&Bogus
;
3980 dwErrorCode
= _RpcXcvData( pHandle
->hPrinter
,
3989 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
3991 dwErrorCode
= RpcExceptionCode();
3992 ERR("_RpcXcvData failed with exception code %lu!\n", dwErrorCode
);
3996 //IntUnprotectHandle( hXcv );
3999 SetLastError(dwErrorCode
);
4000 return (dwErrorCode
== ERROR_SUCCESS
);