1 /*
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)
6 */
7
8 #include "precomp.h"
9 #include <marshalling/printers.h>
10 //#include <marshalling/printerdrivers.h>
11 #include <strsafe.h>
12
13 extern HINSTANCE hinstWinSpool;
14 //
15 // See winddiui.h, ReactOS version is limited.
16 // Loading from XyzUI.dll part of XyzDRV.dll set. example TTYUI.DLL or UniDrvUI.DLL.
17 //
18 typedef DWORD (WINAPI *DEVICECAPABILITIES) (HANDLE,PWSTR,WORD,PVOID,PDEVMODEW);
19 static DEVICECAPABILITIES fpDeviceCapabilities;
20
21 typedef LONG (WINAPI *DEVICEPROPERTYSHEETS) (PPROPSHEETUI_INFO,LPARAM);
22 static DEVICEPROPERTYSHEETS fpDevicePropertySheets;
23 typedef LONG (WINAPI *DOCUMENTPROPERTYSHEETS) (PPROPSHEETUI_INFO,LPARAM);
24 static DOCUMENTPROPERTYSHEETS fpDocumentPropertySheets;
25
26 typedef LONG (WINAPI *COMMONPROPERTYSHEETUIW) (HWND,PFNPROPSHEETUI,LPARAM,LPDWORD);
27 static COMMONPROPERTYSHEETUIW fpCommonPropertySheetUIW;
28
29 typedef LONG (WINAPI *QUERYCOLORPROFILE) (HANDLE,PDEVMODEW,ULONG,PVOID,ULONG*,FLONG*);
30 static QUERYCOLORPROFILE fpQueryColorProfile;
31
32 typedef BOOL (WINAPI *SPOOLERPRINTEREVENT) (LPWSTR,int,DWORD,LPARAM);
33 static SPOOLERPRINTEREVENT fpPrinterEvent;
34
35 typedef BOOL (WINAPI *DEVQUERYPRINT) (HANDLE,LPDEVMODEW,DWORD*);
36 static DEVQUERYPRINT fpDevQueryPrint;
37
38 typedef BOOL (WINAPI *DEVQUERYPRINTEX) (PDEVQUERYPRINT_INFO);
39 static DEVQUERYPRINTEX fpDevQueryPrintEx;
40
41 //
42 // PrintUI.dll
43 //
44 LONG WINAPI ConstructPrinterFriendlyName( PWSTR, PVOID, LPDWORD Size );
45 typedef LONG (WINAPI *CONSTRUCTPRINTERFRIENDLYNAME) (PWSTR,PVOID,LPDWORD);
46 static CONSTRUCTPRINTERFRIENDLYNAME fpConstructPrinterFriendlyName;
47
48 //
49 // CompstUI User Data
50 //
51 typedef struct _COMPUI_USERDATA
52 {
53 HMODULE hModule;
54 LPWSTR pszPrinterName;
55 } COMPUI_USERDATA, *PCOMPUI_USERDATA;
56
57 // Local Constants
58
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";
63
64 static DWORD
_StartDocPrinterSpooled(PSPOOLER_HANDLE pHandle,PDOC_INFO_1W pDocInfo1,PADDJOB_INFO_1W pAddJobInfo1)65 _StartDocPrinterSpooled(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1, PADDJOB_INFO_1W pAddJobInfo1)
66 {
67 DWORD cbNeeded;
68 DWORD dwErrorCode;
69 PJOB_INFO_1W pJobInfo1 = NULL;
70
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)
74 {
75 dwErrorCode = GetLastError();
76 ERR("CreateFileW failed for \"%S\" with error %lu!\n", pAddJobInfo1->Path, dwErrorCode);
77 goto Cleanup;
78 }
79
80 // Get the size of the job information.
81 GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, NULL, 0, &cbNeeded);
82 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
83 {
84 dwErrorCode = GetLastError();
85 ERR("GetJobW failed with error %lu!\n", dwErrorCode);
86 goto Cleanup;
87 }
88
89 // Allocate enough memory for the returned job information.
90 pJobInfo1 = HeapAlloc(hProcessHeap, 0, cbNeeded);
91 if (!pJobInfo1)
92 {
93 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
94 ERR("HeapAlloc failed!\n");
95 goto Cleanup;
96 }
97
98 // Get the job information.
99 if (!GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, cbNeeded, &cbNeeded))
100 {
101 dwErrorCode = GetLastError();
102 ERR("GetJobW failed with error %lu!\n", dwErrorCode);
103 goto Cleanup;
104 }
105
106 // Add our document information.
107 if (pDocInfo1->pDatatype)
108 pJobInfo1->pDatatype = pDocInfo1->pDatatype;
109
110 pJobInfo1->pDocument = pDocInfo1->pDocName;
111
112 // Set the new job information.
113 if (!SetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, 0))
114 {
115 dwErrorCode = GetLastError();
116 ERR("SetJobW failed with error %lu!\n", dwErrorCode);
117 goto Cleanup;
118 }
119
120 // We were successful!
121 pHandle->dwJobID = pAddJobInfo1->JobId;
122 dwErrorCode = ERROR_SUCCESS;
123
124 Cleanup:
125 if (pJobInfo1)
126 HeapFree(hProcessHeap, 0, pJobInfo1);
127
128 return dwErrorCode;
129 }
130
131 static DWORD
_StartDocPrinterWithRPC(PSPOOLER_HANDLE pHandle,PDOC_INFO_1W pDocInfo1)132 _StartDocPrinterWithRPC(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1)
133 {
134 DWORD dwErrorCode;
135 WINSPOOL_DOC_INFO_CONTAINER DocInfoContainer;
136
137 DocInfoContainer.Level = 1;
138 DocInfoContainer.DocInfo.pDocInfo1 = (WINSPOOL_DOC_INFO_1*)pDocInfo1;
139
140 RpcTryExcept
141 {
142 dwErrorCode = _RpcStartDocPrinter(pHandle->hPrinter, &DocInfoContainer, &pHandle->dwJobID);
143 }
144 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
145 {
146 dwErrorCode = RpcExceptionCode();
147 ERR("_RpcStartDocPrinter failed with exception code %lu!\n", dwErrorCode);
148 }
149 RpcEndExcept;
150
151 return dwErrorCode;
152 }
153
154 BOOL WINAPI
AbortPrinter(HANDLE hPrinter)155 AbortPrinter(HANDLE hPrinter)
156 {
157 DWORD dwErrorCode;
158 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
159
160 TRACE("AbortPrinter(%p)\n", hPrinter);
161
162 // Sanity checks.
163 if (!pHandle)
164 {
165 dwErrorCode = ERROR_INVALID_HANDLE;
166 goto Cleanup;
167 }
168
169 pHandle->bTrayIcon = pHandle->bStartedDoc = FALSE;
170
171 if ( pHandle->hSPLFile != INVALID_HANDLE_VALUE && pHandle->bJob )
172 {
173 // Close any open file handle.
174 CloseHandle( pHandle->hSPLFile );
175 pHandle->hSPLFile = INVALID_HANDLE_VALUE;
176
177 SetJobW( hPrinter, pHandle->dwJobID, 0, NULL, JOB_CONTROL_DELETE );
178
179 return ScheduleJob( hPrinter, pHandle->dwJobID );
180 }
181
182 // Do the RPC call.
183 RpcTryExcept
184 {
185 dwErrorCode = _RpcAbortPrinter(&pHandle->hPrinter);
186 }
187 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
188 {
189 dwErrorCode = RpcExceptionCode();
190 ERR("_RpcAbortPrinter failed with exception code %lu!\n", dwErrorCode);
191 }
192 RpcEndExcept;
193
194 Cleanup:
195 SetLastError(dwErrorCode);
196 return (dwErrorCode == ERROR_SUCCESS);
197 }
198
199 HANDLE WINAPI
AddPrinterA(PSTR pName,DWORD Level,PBYTE pPrinter)200 AddPrinterA(PSTR pName, DWORD Level, PBYTE pPrinter)
201 {
202 UNICODE_STRING pNameW, usBuffer;
203 PWSTR pwstrNameW;
204 PRINTER_INFO_2W *ppi2w = (PRINTER_INFO_2W*)pPrinter;
205 PRINTER_INFO_2A *ppi2a = (PRINTER_INFO_2A*)pPrinter;
206 HANDLE ret = NULL;
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;
219
220 TRACE("AddPrinterA(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
221
222 if(Level != 2)
223 {
224 ERR("Level = %d, unsupported!\n", Level);
225 SetLastError(ERROR_INVALID_LEVEL);
226 return NULL;
227 }
228
229 pwstrNameW = AsciiToUnicode(&pNameW,pName);
230
231 if (ppi2a->pShareName)
232 {
233 pwszShareName = AsciiToUnicode(&usBuffer, ppi2a->pShareName);
234 if (!(ppi2w->pShareName = pwszShareName)) goto Cleanup;
235 }
236 if (ppi2a->pPortName)
237 {
238 pwszPortName = AsciiToUnicode(&usBuffer, ppi2a->pPortName);
239 if (!(ppi2w->pPortName = pwszPortName)) goto Cleanup;
240 }
241 if (ppi2a->pDriverName)
242 {
243 pwszDriverName = AsciiToUnicode(&usBuffer, ppi2a->pDriverName);
244 if (!(ppi2w->pDriverName = pwszDriverName)) goto Cleanup;
245 }
246 if (ppi2a->pComment)
247 {
248 pwszComment = AsciiToUnicode(&usBuffer, ppi2a->pComment);
249 if (!(ppi2w->pComment = pwszComment)) goto Cleanup;
250 }
251 if (ppi2a->pLocation)
252 {
253 pwszLocation = AsciiToUnicode(&usBuffer, ppi2a->pLocation);
254 if (!(ppi2w->pLocation = pwszLocation)) goto Cleanup;
255 }
256 if (ppi2a->pSepFile)
257 {
258 pwszSepFile = AsciiToUnicode(&usBuffer, ppi2a->pSepFile);
259 if (!(ppi2w->pSepFile = pwszSepFile)) goto Cleanup;
260 }
261 if (ppi2a->pServerName)
262 {
263 pwszPrintProcessor = AsciiToUnicode(&usBuffer, ppi2a->pPrintProcessor);
264 if (!(ppi2w->pPrintProcessor = pwszPrintProcessor)) goto Cleanup;
265 }
266 if (ppi2a->pDatatype)
267 {
268 pwszDatatype = AsciiToUnicode(&usBuffer, ppi2a->pDatatype);
269 if (!(ppi2w->pDatatype = pwszDatatype)) goto Cleanup;
270 }
271 if (ppi2a->pParameters)
272 {
273 pwszParameters = AsciiToUnicode(&usBuffer, ppi2a->pParameters);
274 if (!(ppi2w->pParameters = pwszParameters)) goto Cleanup;
275 }
276 if ( ppi2a->pDevMode )
277 {
278 RosConvertAnsiDevModeToUnicodeDevmode( ppi2a->pDevMode, &pdmw );
279 ppi2w->pDevMode = pdmw;
280 }
281 if (ppi2a->pServerName)
282 {
283 pwszServerName = AsciiToUnicode(&usBuffer, ppi2a->pServerName);
284 if (!(ppi2w->pPrinterName = pwszServerName)) goto Cleanup;
285 }
286 if (ppi2a->pPrinterName)
287 {
288 pwszPrinterName = AsciiToUnicode(&usBuffer, ppi2a->pPrinterName);
289 if (!(ppi2w->pPrinterName = pwszPrinterName)) goto Cleanup;
290 }
291
292 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)ppi2w);
293
294 Cleanup:
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);
307
308 RtlFreeUnicodeString(&pNameW);
309 return ret;
310 }
311
312 HANDLE WINAPI
AddPrinterW(PWSTR pName,DWORD Level,PBYTE pPrinter)313 AddPrinterW(PWSTR pName, DWORD Level, PBYTE pPrinter)
314 {
315 DWORD dwErrorCode;
316 WINSPOOL_PRINTER_CONTAINER PrinterContainer;
317 WINSPOOL_DEVMODE_CONTAINER DevModeContainer;
318 WINSPOOL_SECURITY_CONTAINER SecurityContainer;
319 SECURITY_DESCRIPTOR *sd = NULL;
320 DWORD size;
321 HANDLE hPrinter = NULL, hHandle = NULL;
322 PSPOOLER_HANDLE pHandle = NULL;
323
324 TRACE("AddPrinterW(%S, %lu, %p)\n", pName, Level, pPrinter);
325
326 DevModeContainer.cbBuf = 0;
327 DevModeContainer.pDevMode = NULL;
328
329 SecurityContainer.cbBuf = 0;
330 SecurityContainer.pSecurity = NULL;
331
332 if ( Level != 2 )
333 {
334 FIXME( "Unsupported level %d\n", Level );
335 SetLastError( ERROR_INVALID_LEVEL );
336 return hHandle;
337 }
338 else
339 {
340 PPRINTER_INFO_2W pi2w = (PPRINTER_INFO_2W)pPrinter;
341 if ( pi2w )
342 {
343 if ( pi2w->pDevMode )
344 {
345 if ( IsValidDevmodeNoSizeW( pi2w->pDevMode ) )
346 {
347 DevModeContainer.cbBuf = pi2w->pDevMode->dmSize + pi2w->pDevMode->dmDriverExtra;
348 DevModeContainer.pDevMode = (PBYTE)pi2w->pDevMode;
349 }
350 }
351
352 if ( pi2w->pSecurityDescriptor )
353 {
354 sd = get_sd( pi2w->pSecurityDescriptor, &size );
355 if ( sd )
356 {
357 SecurityContainer.cbBuf = size;
358 SecurityContainer.pSecurity = (PBYTE)sd;
359 }
360 }
361 }
362 else
363 {
364 SetLastError(ERROR_INVALID_PARAMETER);
365 return hHandle;
366 }
367 }
368
369 PrinterContainer.PrinterInfo.pPrinterInfo1 = (WINSPOOL_PRINTER_INFO_1*)pPrinter;
370 PrinterContainer.Level = Level;
371
372 // Do the RPC call
373 RpcTryExcept
374 {
375 dwErrorCode = _RpcAddPrinter( pName, &PrinterContainer, &DevModeContainer, &SecurityContainer, &hPrinter );
376 }
377 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
378 {
379 dwErrorCode = RpcExceptionCode();
380 }
381 RpcEndExcept;
382
383 if (hPrinter)
384 {
385 // Create a new SPOOLER_HANDLE structure.
386 pHandle = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(SPOOLER_HANDLE));
387 if (!pHandle)
388 {
389 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
390 ERR("HeapAlloc failed!\n");
391 _RpcDeletePrinter(hPrinter);
392 _RpcClosePrinter(hPrinter);
393 goto Cleanup;
394 }
395
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;
401 }
402
403 Cleanup:
404 if ( sd ) HeapFree( GetProcessHeap(), 0, sd );
405
406 SetLastError(dwErrorCode);
407 return hHandle;
408 }
409
410 BOOL WINAPI
ClosePrinter(HANDLE hPrinter)411 ClosePrinter(HANDLE hPrinter)
412 {
413 DWORD dwErrorCode;
414 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
415
416 TRACE("ClosePrinter(%p)\n", hPrinter);
417
418 // Sanity checks.
419 if ( IntProtectHandle( hPrinter, TRUE ) )
420 {
421 dwErrorCode = ERROR_INVALID_HANDLE;
422 goto Cleanup;
423 }
424
425 // Do the RPC call.
426 RpcTryExcept
427 {
428 dwErrorCode = _RpcClosePrinter(&pHandle->hPrinter);
429 }
430 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
431 {
432 dwErrorCode = RpcExceptionCode();
433 ERR("_RpcClosePrinter failed with exception code %lu!\n", dwErrorCode);
434 }
435 RpcEndExcept;
436
437 // Close any open file handle.
438 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
439 CloseHandle(pHandle->hSPLFile);
440
441 pHandle->Sig = -1;
442
443 // Free the memory for the handle.
444 HeapFree(hProcessHeap, 0, pHandle);
445
446 Cleanup:
447 SetLastError(dwErrorCode);
448 return (dwErrorCode == ERROR_SUCCESS);
449 }
450
451 BOOL WINAPI
DeletePrinter(HANDLE hPrinter)452 DeletePrinter(HANDLE hPrinter)
453 {
454 DWORD dwErrorCode;
455 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
456
457 TRACE("DeletePrinter(%p)\n", hPrinter);
458
459 // Sanity checks.
460 if (!pHandle)
461 {
462 dwErrorCode = ERROR_INVALID_HANDLE;
463 goto Cleanup;
464 }
465
466 // Do the RPC call.
467 RpcTryExcept
468 {
469 dwErrorCode = _RpcDeletePrinter(&pHandle->hPrinter);
470 }
471 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
472 {
473 dwErrorCode = RpcExceptionCode();
474 ERR("_RpcDeletePrinter failed with exception code %lu!\n", dwErrorCode);
475 }
476 RpcEndExcept;
477
478 Cleanup:
479 SetLastError(dwErrorCode);
480 return (dwErrorCode == ERROR_SUCCESS);
481 }
482
483 //
484 // Based on GDI32:printdrv.c:IntGetPrinterDriver.
485 //
486 HMODULE
487 WINAPI
LoadPrinterDriver(HANDLE hspool)488 LoadPrinterDriver( HANDLE hspool )
489 {
490 INT iTries = 0;
491 DWORD Size = (sizeof(WCHAR) * MAX_PATH) * 2; // DRIVER_INFO_5W + plus strings.
492 PDRIVER_INFO_5W pdi = NULL;
493 HMODULE hLibrary = NULL;
494
495 do
496 {
497 ++iTries;
498
499 pdi = RtlAllocateHeap( GetProcessHeap(), 0, Size);
500
501 if ( !pdi )
502 break;
503
504 if ( GetPrinterDriverW(hspool, NULL, 5, (LPBYTE)pdi, Size, &Size) )
505 {
506 TRACE("Level 5 Size %d\n",Size);
507
508 // Name and load configure library (for example, C:\DRIVERS\Pscrptui.dll). Not printui.dll!
509
510 hLibrary = LoadLibrary(pdi->pConfigFile);
511
512 FIXME("IGPD : Get Printer Driver Config File : %S\n",pdi->pConfigFile);
513
514 RtlFreeHeap( GetProcessHeap(), 0, pdi);
515 return hLibrary;
516 }
517
518 if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
519 ++iTries;
520
521 RtlFreeHeap( GetProcessHeap(), 0, pdi);
522 }
523 while ( iTries < 2 );
524 ERR("No Printer Driver Error %d\n",GetLastError());
525 return NULL;
526 }
527
528 DWORD WINAPI
DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort,WORD fwCapability,LPSTR pOutput,const DEVMODEA * pDevMode)529 DeviceCapabilitiesA(LPCSTR pDevice, LPCSTR pPort, WORD fwCapability, LPSTR pOutput, const DEVMODEA* pDevMode)
530 {
531 PWSTR pwszDeviceName = NULL;
532 PDEVMODEW pdmwInput = NULL;
533 BOOL bReturnValue = GDI_ERROR;
534 DWORD cch;
535
536 FIXME("DeviceCapabilitiesA(%s, %s, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode);
537
538 if (pDevice)
539 {
540 // Convert pName to a Unicode string pwszDeviceName.
541 cch = strlen(pDevice);
542
543 pwszDeviceName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
544 if (!pwszDeviceName)
545 {
546 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
547 ERR("HeapAlloc failed!\n");
548 goto Cleanup;
549 }
550
551 MultiByteToWideChar(CP_ACP, 0, pDevice, -1, pwszDeviceName, cch + 1);
552 }
553
554 if (pDevMode)
555 {
556 RosConvertAnsiDevModeToUnicodeDevmode((PDEVMODEA)pDevMode, &pdmwInput);
557 }
558
559 // pPort is ignored so no need to pass it.
560 bReturnValue = DeviceCapabilitiesW( pwszDeviceName, NULL, fwCapability, (LPWSTR)pOutput, (const DEVMODEW*) pdmwInput );
561
562 Cleanup:
563 if(pwszDeviceName)
564 HeapFree(hProcessHeap, 0, pwszDeviceName);
565
566 if (pdmwInput)
567 HeapFree(hProcessHeap, 0, pdmwInput);
568
569 return bReturnValue;
570 }
571
572 DWORD WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice,LPCWSTR pPort,WORD fwCapability,LPWSTR pOutput,const DEVMODEW * pDevMode)573 DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort, WORD fwCapability, LPWSTR pOutput, const DEVMODEW* pDevMode)
574 {
575 HANDLE hPrinter;
576 HMODULE hLibrary;
577 DWORD iDevCap = GDI_ERROR;
578
579 FIXME("DeviceCapabilitiesW(%S, %S, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode);
580
581 if ( pDevMode )
582 {
583 if (!IsValidDevmodeNoSizeW( (PDEVMODEW)pDevMode ) )
584 {
585 ERR("DeviceCapabilitiesW : Devode Invalid\n");
586 return -1;
587 }
588 }
589
590 if ( OpenPrinterW( (LPWSTR)pDevice, &hPrinter, NULL ) )
591 {
592 hLibrary = LoadPrinterDriver( hPrinter );
593
594 if ( hLibrary )
595 {
596 fpDeviceCapabilities = (PVOID)GetProcAddress( hLibrary, "DrvDeviceCapabilities" );
597
598 if ( fpDeviceCapabilities )
599 {
600 iDevCap = fpDeviceCapabilities( hPrinter, (PWSTR)pDevice, fwCapability, pOutput, (PDEVMODE)pDevMode );
601 }
602
603 FreeLibrary(hLibrary);
604 }
605
606 ClosePrinter( hPrinter );
607 }
608
609 return iDevCap;
610 }
611
612 BOOL
613 WINAPI
DevQueryPrint(HANDLE hPrinter,LPDEVMODEW pDevMode,DWORD * pResID)614 DevQueryPrint( HANDLE hPrinter, LPDEVMODEW pDevMode, DWORD *pResID)
615 {
616 HMODULE hLibrary;
617 BOOL Ret = FALSE;
618
619 hLibrary = LoadPrinterDriver( hPrinter );
620
621 if ( hLibrary )
622 {
623 fpDevQueryPrint = (PVOID)GetProcAddress( hLibrary, "DevQueryPrint" );
624
625 if ( fpDevQueryPrint )
626 {
627 Ret = fpDevQueryPrint( hPrinter, pDevMode, pResID );
628 }
629
630 FreeLibrary(hLibrary);
631 }
632 return Ret;
633 }
634
635 BOOL WINAPI
DevQueryPrintEx(PDEVQUERYPRINT_INFO pDQPInfo)636 DevQueryPrintEx( PDEVQUERYPRINT_INFO pDQPInfo )
637 {
638 HMODULE hLibrary;
639 BOOL Ret = FALSE;
640
641 hLibrary = LoadPrinterDriver( pDQPInfo->hPrinter );
642
643 if ( hLibrary )
644 {
645 fpDevQueryPrintEx = (PVOID)GetProcAddress( hLibrary, "DevQueryPrintEx" );
646
647 if ( fpDevQueryPrintEx )
648 {
649 Ret = fpDevQueryPrintEx( pDQPInfo );
650 }
651
652 FreeLibrary(hLibrary);
653 }
654 return Ret;
655 }
656
657 INT WINAPI
DocumentEvent(HANDLE hPrinter,HDC hdc,int iEsc,ULONG cbIn,PVOID pvIn,ULONG cbOut,PVOID pvOut)658 DocumentEvent( HANDLE hPrinter, HDC hdc, int iEsc, ULONG cbIn, PVOID pvIn, ULONG cbOut, PVOID pvOut)
659 {
660 FIXME("DocumentEvent(%p, %p, %lu, %lu, %p, %lu, %p)\n", hPrinter, hdc, iEsc, cbIn, pvIn, cbOut, pvOut);
661 UNIMPLEMENTED;
662 return DOCUMENTEVENT_UNSUPPORTED;
663 }
664
665 LONG WINAPI
DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,LPSTR pDeviceName,PDEVMODEA pDevModeOutput,PDEVMODEA pDevModeInput,DWORD fMode)666 DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput, DWORD fMode)
667 {
668 PWSTR pwszDeviceName = NULL;
669 PDEVMODEW pdmwInput = NULL;
670 PDEVMODEW pdmwOutput = NULL;
671 LONG lReturnValue = -1;
672 DWORD cch;
673
674 FIXME("DocumentPropertiesA(%p, %p, %s, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode);
675
676 if (pDeviceName)
677 {
678 // Convert pName to a Unicode string pwszDeviceName.
679 cch = strlen(pDeviceName);
680
681 pwszDeviceName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
682 if (!pwszDeviceName)
683 {
684 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
685 ERR("HeapAlloc failed!\n");
686 goto Cleanup;
687 }
688
689 MultiByteToWideChar(CP_ACP, 0, pDeviceName, -1, pwszDeviceName, cch + 1);
690 }
691
692 if (pDevModeInput)
693 {
694 // Create working buffer for input to DocumentPropertiesW.
695 RosConvertAnsiDevModeToUnicodeDevmode(pDevModeInput, &pdmwInput);
696 }
697
698 if (pDevModeOutput)
699 {
700 // Create working buffer for output from DocumentPropertiesW.
701
702 // Do it RIGHT! Get the F...ing Size!
703 LONG Size = DocumentPropertiesW( hWnd, hPrinter, pwszDeviceName, NULL, NULL, 0 );
704
705 if ( Size < 0 )
706 {
707 goto Cleanup;
708 }
709
710 pdmwOutput = HeapAlloc(hProcessHeap, 0, Size);
711 if (!pdmwOutput)
712 {
713 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
714 ERR("HeapAlloc failed!\n");
715 goto Cleanup;
716 }
717 }
718
719 lReturnValue = DocumentPropertiesW(hWnd, hPrinter, pwszDeviceName, pdmwOutput, pdmwInput, fMode);
720 FIXME("lReturnValue from DocumentPropertiesW is '%ld'.\n", lReturnValue);
721
722 if (lReturnValue < 0)
723 {
724 FIXME("DocumentPropertiesW failed!\n");
725 goto Cleanup;
726 }
727
728 if (pdmwOutput)
729 {
730 RosConvertUnicodeDevModeToAnsiDevmode(pdmwOutput, pDevModeOutput);
731 }
732
733 Cleanup:
734 if(pwszDeviceName)
735 HeapFree(hProcessHeap, 0, pwszDeviceName);
736
737 if (pdmwInput)
738 HeapFree(hProcessHeap, 0, pdmwInput);
739
740 if (pdmwOutput)
741 HeapFree(hProcessHeap, 0, pdmwOutput);
742
743 return lReturnValue;
744 }
745
get_devmodeW(HANDLE hprn)746 PRINTER_INFO_9W * get_devmodeW(HANDLE hprn)
747 {
748 PRINTER_INFO_9W *pi9 = NULL;
749 DWORD needed = 0;
750 BOOL res;
751
752 res = GetPrinterW(hprn, 9, NULL, 0, &needed);
753 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
754 {
755 pi9 = HeapAlloc(hProcessHeap, 0, needed);
756 if (!pi9)
757 {
758 ERR("Failed to allocate PRINTER_INFO_9W of %u bytes\n", needed);
759 return NULL;
760 }
761 res = GetPrinterW(hprn, 9, (LPBYTE)pi9, needed, &needed);
762 }
763
764 if (res)
765 return pi9;
766
767 ERR("GetPrinterW failed with %u\n", GetLastError());
768 HeapFree(hProcessHeap, 0, pi9);
769 return NULL;
770 }
771
772 BOOL
773 FASTCALL
CreateUIUserData(ULONG_PTR * puserdata,HANDLE hPrinter)774 CreateUIUserData( ULONG_PTR *puserdata, HANDLE hPrinter )
775 {
776 PCOMPUI_USERDATA pcui_ud = DllAllocSplMem( sizeof(COMPUI_USERDATA) );
777
778 *puserdata = (ULONG_PTR)pcui_ud;
779 FIXME("CreateUIUserData\n");
780 if ( pcui_ud )
781 {
782 pcui_ud->hModule = LoadPrinterDriver( hPrinter );
783
784 if ( !pcui_ud->hModule )
785 {
786 DllFreeSplMem( pcui_ud );
787 *puserdata = 0;
788 }
789 }
790 return *puserdata != 0;
791 }
792
793 VOID
794 FASTCALL
DestroyUIUserData(ULONG_PTR * puserdata)795 DestroyUIUserData( ULONG_PTR *puserdata )
796 {
797 PCOMPUI_USERDATA pcui_ud = (PCOMPUI_USERDATA)*puserdata;
798 FIXME("DestroyUIUserData\n");
799 if ( pcui_ud )
800 {
801 if ( pcui_ud->hModule )
802 {
803 FreeLibrary( pcui_ud->hModule );
804 pcui_ud->hModule = NULL;
805 }
806
807 if ( pcui_ud->pszPrinterName )
808 {
809 DllFreeSplMem( pcui_ud->pszPrinterName );
810 pcui_ud->pszPrinterName = NULL;
811 }
812
813 DllFreeSplMem( pcui_ud );
814 *puserdata = 0;
815 }
816 }
817
818 BOOL
819 FASTCALL
IntFixUpDevModeNames(PDOCUMENTPROPERTYHEADER pdphdr)820 IntFixUpDevModeNames( PDOCUMENTPROPERTYHEADER pdphdr )
821 {
822 PRINTER_INFO_2W *pi2 = NULL;
823 DWORD needed = 0;
824 BOOL res;
825
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.
828 !pdphdr->pdmOut )
829 {
830 return FALSE;
831 }
832
833 res = GetPrinterW( pdphdr->hPrinter, 2, NULL, 0, &needed);
834 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
835 {
836 pi2 = HeapAlloc(hProcessHeap, 0, needed);
837 if (!pi2)
838 {
839 ERR("Failed to allocate PRINTER_INFO_2W of %u bytes\n", needed);
840 return FALSE;
841 }
842 res = GetPrinterW( pdphdr->hPrinter, 2, (LPBYTE)pi2, needed, &needed);
843 }
844
845 if (res)
846 {
847 /* Check if the provided buffer is large enough */
848 DWORD cbDevMode = pi2->pDevMode->dmSize + pi2->pDevMode->dmDriverExtra;
849 if (pdphdr->cbOut < cbDevMode)
850 {
851 ERR("cbOut (%lu) < cbDevMode(%u)\n", pdphdr->cbOut, cbDevMode);
852 res = FALSE;
853 goto Exit;
854 }
855
856 /* Copy the devmode */
857 RtlCopyMemory(pdphdr->pdmOut, pi2->pDevMode, cbDevMode);
858
859 TRACE("IFUDMN : Get Printer Name %S\n", pi2->pPrinterName);
860 StringCchCopyW( pdphdr->pdmOut->dmDeviceName, CCHDEVICENAME-1, pi2->pPrinterName );
861 pdphdr->pdmOut->dmDeviceName[CCHDEVICENAME-1] = 0;
862 }
863 else
864 {
865 ERR("IFUDMN : GetPrinterW failed with %u\n", GetLastError());
866 }
867
868 Exit:
869 HeapFree(hProcessHeap, 0, pi2);
870 return res;
871 }
872
873 LONG
874 WINAPI
CreatePrinterFriendlyName(PCOMPUI_USERDATA pcui_ud,LPWSTR pszPrinterName)875 CreatePrinterFriendlyName( PCOMPUI_USERDATA pcui_ud, LPWSTR pszPrinterName )
876 {
877 LONG Result = 0;
878 DWORD Size = 0;
879 HMODULE hLibrary = NULL;
880
881 hLibrary = LoadLibraryA( "printui.dll" );
882
883 if ( hLibrary )
884 {
885 fpConstructPrinterFriendlyName = (PVOID)GetProcAddress( hLibrary, "ConstructPrinterFriendlyName" );
886
887 if ( fpConstructPrinterFriendlyName )
888 {
889 if ( !fpConstructPrinterFriendlyName( pszPrinterName, NULL, &Size ) )
890 {
891 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
892 {
893 PWSTR pwstr = DllAllocSplMem( (Size + 1) * sizeof(WCHAR) );
894
895 pcui_ud->pszPrinterName = pwstr;
896
897 if ( pwstr )
898 Result = fpConstructPrinterFriendlyName( pszPrinterName, pwstr, &Size );
899 }
900 }
901 }
902 FreeLibrary( hLibrary );
903 }
904
905 if ( !Result )
906 {
907 DllFreeSplMem( pcui_ud->pszPrinterName );
908 pcui_ud->pszPrinterName = AllocSplStr( pszPrinterName );
909 }
910
911 return Result;
912 }
913
914 //
915 // Tested with XP CompstUI as a callback and works. Fails perfectly.
916 //
917 LONG
918 WINAPI
DocumentPropertySheets(PPROPSHEETUI_INFO pCPSUIInfo,LPARAM lparam)919 DocumentPropertySheets( PPROPSHEETUI_INFO pCPSUIInfo, LPARAM lparam )
920 {
921 LONG Result = -1;
922 PDOCUMENTPROPERTYHEADER pdphdr;
923
924 FIXME("DocumentPropertySheets(%p, 0x%lx)\n", pCPSUIInfo, lparam);
925
926 // If pPSUIInfo is NULL, and if either lParam -> fMode is zero or lParam -> pdmOut is NULL,
927 // this function should return the size, in bytes, of the printer's DEVMODEW structure.
928 if ( !pCPSUIInfo && lparam )
929 {
930 pdphdr = (PDOCUMENTPROPERTYHEADER)lparam;
931
932 if ( pdphdr->cbSize >= sizeof(PDOCUMENTPROPERTYHEADER) &&
933 !(pdphdr->fMode & DM_PROMPT) )
934 {
935 HMODULE hLibrary = LoadPrinterDriver( pdphdr->hPrinter );
936
937 if ( hLibrary )
938 {
939 fpDocumentPropertySheets = (PVOID)GetProcAddress( hLibrary, "DrvDocumentPropertySheets" );
940
941 if ( fpDocumentPropertySheets )
942 {
943 FIXME("DPS : fpDocumentPropertySheets(%p, 0x%lx) pdmOut %p\n", pCPSUIInfo, lparam, pdphdr->pdmOut);
944 Result = fpDocumentPropertySheets( pCPSUIInfo, lparam );
945 FIXME("DPS : fpDocumentPropertySheets result %d cbOut %d\n",Result, pdphdr->cbOut);
946 }
947 else
948 {
949 //
950 // ReactOS backup!!! Currently no supporting UI driver.
951 //
952 PRINTER_INFO_9W * pi9 = get_devmodeW( pdphdr->hPrinter );
953 if ( pi9 )
954 {
955 Result = pi9->pDevMode->dmSize + pi9->pDevMode->dmDriverExtra;
956 FIXME("IDPS : Using ReactOS backup!!! DevMode Size %d\n",Result);
957 HeapFree(hProcessHeap, 0, pi9);
958 }
959 }
960
961 FreeLibrary(hLibrary);
962
963 if ( Result > 0 )
964 {
965 IntFixUpDevModeNames( pdphdr );
966 }
967
968 return Result;
969 }
970 else
971 {
972 SetLastError(ERROR_INVALID_HANDLE);
973 }
974 }
975 else
976 {
977 SetLastError(ERROR_INVALID_PARAMETER);
978 }
979 return Result;
980 }
981
982 Result = 0;
983
984 if ( pCPSUIInfo )
985 {
986 PSETRESULT_INFO psri;
987 PPROPSHEETUI_INFO_HEADER ppsuiihdr;
988 PCOMPUI_USERDATA pcui_ud;
989 pdphdr = (PDOCUMENTPROPERTYHEADER)pCPSUIInfo->lParamInit;
990
991 if ( pdphdr->cbSize < sizeof(PDOCUMENTPROPERTYHEADER) )
992 {
993 SetLastError(ERROR_INVALID_PARAMETER);
994 return Result;
995 }
996
997 switch ( pCPSUIInfo->Reason )
998 {
999 case PROPSHEETUI_REASON_INIT:
1000 {
1001 FIXME("DocPS : PROPSHEETUI_REASON_INIT\n");
1002 if ( CreateUIUserData( &pCPSUIInfo->UserData, pdphdr->hPrinter ) )
1003 {
1004 pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData;
1005
1006 fpDocumentPropertySheets = (PVOID)GetProcAddress( pcui_ud->hModule, "DrvDocumentPropertySheets" );
1007
1008 if ( fpDocumentPropertySheets )
1009 {
1010 pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet,
1011 CPSFUNC_SET_FUSION_CONTEXT,
1012 -3, // What type of handle is this?
1013 0 ); // Not used, must be zero.
1014
1015 Result = pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet,
1016 CPSFUNC_ADD_PFNPROPSHEETUIW,
1017 (LPARAM)fpDocumentPropertySheets,
1018 pCPSUIInfo->lParamInit );
1019 break;
1020 }
1021 FIXME("DocPS : PROPSHEETUI_REASON_INIT Fail\n");
1022 DestroyUIUserData( &pCPSUIInfo->UserData );
1023 }
1024 }
1025 break;
1026
1027 case PROPSHEETUI_REASON_GET_INFO_HEADER:
1028 FIXME("DocPS : PROPSHEETUI_REASON_GET_INFO_HEADER\n");
1029
1030 ppsuiihdr = (PPROPSHEETUI_INFO_HEADER)lparam;
1031
1032 pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData;
1033
1034 CreatePrinterFriendlyName( pcui_ud, pdphdr->pszPrinterName );
1035
1036 ppsuiihdr->Flags = PSUIHDRF_NOAPPLYNOW|PSUIHDRF_PROPTITLE;
1037 ppsuiihdr->pTitle = pcui_ud->pszPrinterName;
1038 ppsuiihdr->hInst = hinstWinSpool;
1039 ppsuiihdr->IconID = IDI_CPSUI_DOCUMENT;
1040
1041 Result = CPSUI_OK;
1042 break;
1043
1044 case PROPSHEETUI_REASON_DESTROY:
1045 FIXME("DocPS : PROPSHEETUI_REASON_DESTROY\n");
1046 DestroyUIUserData( &pCPSUIInfo->UserData );
1047 Result = CPSUI_OK;
1048 break;
1049
1050 case PROPSHEETUI_REASON_SET_RESULT:
1051 FIXME("DocPS : PROPSHEETUI_REASON_SET_RESULT\n");
1052
1053 psri = (PSETRESULT_INFO)lparam;
1054
1055 pCPSUIInfo->Result = psri->Result;
1056 if ( pCPSUIInfo->Result > 0 )
1057 {
1058 IntFixUpDevModeNames( pdphdr );
1059 }
1060 Result = CPSUI_OK;
1061 break;
1062 }
1063 }
1064 return Result;
1065 }
1066
1067 LONG
1068 WINAPI
DevicePropertySheets(PPROPSHEETUI_INFO pCPSUIInfo,LPARAM lparam)1069 DevicePropertySheets( PPROPSHEETUI_INFO pCPSUIInfo, LPARAM lparam )
1070 {
1071 LONG Result = 0;
1072 PDEVICEPROPERTYHEADER pdphdr;
1073
1074 FIXME("DevicePropertySheets(%p, 0x%lx)\n", pCPSUIInfo, lparam);
1075
1076 if ( pCPSUIInfo )
1077 {
1078 PSETRESULT_INFO psri;
1079 PPROPSHEETUI_INFO_HEADER ppsuiihdr;
1080 PCOMPUI_USERDATA pcui_ud;
1081 pdphdr = (PDEVICEPROPERTYHEADER)pCPSUIInfo->lParamInit;
1082
1083 if ( pdphdr->cbSize < sizeof(DEVICEPROPERTYHEADER) )
1084 {
1085 SetLastError(ERROR_INVALID_PARAMETER);
1086 return Result;
1087 }
1088
1089 switch ( pCPSUIInfo->Reason )
1090 {
1091 case PROPSHEETUI_REASON_INIT:
1092 {
1093 FIXME("DevPS : PROPSHEETUI_REASON_INIT\n");
1094 if ( CreateUIUserData( &pCPSUIInfo->UserData, pdphdr->hPrinter ) )
1095 {
1096 pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData;
1097
1098 fpDevicePropertySheets = (PVOID)GetProcAddress( pcui_ud->hModule, "DrvDevicePropertySheets" );
1099
1100 if ( fpDevicePropertySheets )
1101 {
1102 pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet,
1103 CPSFUNC_SET_FUSION_CONTEXT,
1104 -3, // What type of handle is this?
1105 0 ); // Not used, must be zero.
1106
1107 Result = pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet,
1108 CPSFUNC_ADD_PFNPROPSHEETUIW,
1109 (LPARAM)fpDevicePropertySheets,
1110 pCPSUIInfo->lParamInit );
1111 break;
1112 }
1113 FIXME("DevPS : PROPSHEETUI_REASON_INIT Fail\n");
1114 DestroyUIUserData( &pCPSUIInfo->UserData );
1115 }
1116 }
1117 break;
1118
1119 case PROPSHEETUI_REASON_GET_INFO_HEADER:
1120 FIXME("DevPS : PROPSHEETUI_REASON_GET_INFO_HEADER\n");
1121
1122 ppsuiihdr = (PPROPSHEETUI_INFO_HEADER)lparam;
1123
1124 pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData;
1125
1126 CreatePrinterFriendlyName( pcui_ud, pdphdr->pszPrinterName );
1127
1128 ppsuiihdr->Flags = PSUIHDRF_NOAPPLYNOW|PSUIHDRF_PROPTITLE;
1129 ppsuiihdr->pTitle = pcui_ud->pszPrinterName;
1130 ppsuiihdr->hInst = hinstWinSpool;
1131 ppsuiihdr->IconID = IDI_CPSUI_DOCUMENT;
1132
1133 Result = CPSUI_OK;
1134 break;
1135
1136 case PROPSHEETUI_REASON_DESTROY:
1137 FIXME("DevPS : PROPSHEETUI_REASON_DESTROY\n");
1138 DestroyUIUserData( &pCPSUIInfo->UserData );
1139 Result = CPSUI_OK;
1140 break;
1141
1142 case PROPSHEETUI_REASON_SET_RESULT:
1143 FIXME("DevPS : PROPSHEETUI_REASON_SET_RESULT\n");
1144 psri = (PSETRESULT_INFO)lparam;
1145 pCPSUIInfo->Result = psri->Result;
1146 Result = CPSUI_OK;
1147 break;
1148 }
1149 }
1150 return Result;
1151 }
1152
1153 LONG
1154 WINAPI
CallCommonPropertySheetUI(HWND hWnd,PFNPROPSHEETUI pfnPropSheetUI,LPARAM lparam,LPDWORD pResult)1155 CallCommonPropertySheetUI(HWND hWnd, PFNPROPSHEETUI pfnPropSheetUI, LPARAM lparam, LPDWORD pResult)
1156 {
1157 HMODULE hLibrary = NULL;
1158 LONG Ret = ERR_CPSUI_GETLASTERROR;
1159
1160 FIXME("CallCommonPropertySheetUI(%p, %p, 0x%lx, %p)\n", hWnd, pfnPropSheetUI, lparam, pResult);
1161
1162 if ( ( hLibrary = LoadLibraryA( "compstui.dll" ) ) )
1163 {
1164 fpCommonPropertySheetUIW = (PVOID) GetProcAddress(hLibrary, "CommonPropertySheetUIW");
1165
1166 if ( fpCommonPropertySheetUIW )
1167 {
1168 Ret = fpCommonPropertySheetUIW( hWnd, pfnPropSheetUI, lparam, pResult );
1169 }
1170
1171 FreeLibrary(hLibrary);
1172 }
1173 return Ret;
1174 }
1175
1176 LONG WINAPI
DocumentPropertiesW(HWND hWnd,HANDLE hPrinter,LPWSTR pDeviceName,PDEVMODEW pDevModeOutput,PDEVMODEW pDevModeInput,DWORD fMode)1177 DocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput, DWORD fMode)
1178 {
1179 HANDLE hUseHandle = NULL;
1180 DOCUMENTPROPERTYHEADER docprophdr;
1181 LONG Result = IDOK;
1182
1183 FIXME("DocumentPropertiesW(%p, %p, %S, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode);
1184
1185 if (hPrinter)
1186 {
1187 hUseHandle = hPrinter;
1188 }
1189 else if (!OpenPrinterW(pDeviceName, &hUseHandle, NULL))
1190 {
1191 ERR("No handle, and no usable printer name passed in\n");
1192 return -1;
1193 }
1194
1195 if ( !(fMode & DM_IN_BUFFER ) ||
1196 ( ( pDevModeInput && !IsValidDevmodeNoSizeW( (PDEVMODEW)pDevModeInput ) ) ) )
1197 {
1198 pDevModeInput = NULL;
1199 fMode &= ~DM_IN_BUFFER;
1200 }
1201
1202 docprophdr.cbSize = sizeof(DOCUMENTPROPERTYHEADER);
1203 docprophdr.Reserved = 0;
1204 docprophdr.hPrinter = hUseHandle;
1205 docprophdr.pszPrinterName = pDeviceName;
1206 docprophdr.cbOut = 0;
1207
1208 if ( pDevModeOutput )
1209 {
1210 docprophdr.pdmIn = NULL;
1211 docprophdr.pdmOut = NULL;
1212 docprophdr.fMode = 0;
1213 FIXME("DPW : Call DocumentPropertySheets with pDevModeOutput %p\n",pDevModeOutput);
1214 docprophdr.cbOut = DocumentPropertySheets( NULL, (LPARAM)&docprophdr );
1215 }
1216
1217 docprophdr.pdmIn = pDevModeInput;
1218 docprophdr.pdmOut = pDevModeOutput;
1219 docprophdr.fMode = fMode;
1220
1221 if ( fMode & DM_IN_PROMPT )
1222 {
1223 Result = CPSUI_CANCEL;
1224
1225 //
1226 // Now call the Property Sheet for Print > Properties.
1227 //
1228 if ( CallCommonPropertySheetUI( hWnd, (PFNPROPSHEETUI)DocumentPropertySheets, (LPARAM)&docprophdr, (LPDWORD)&Result ) < 0 )
1229 {
1230 FIXME("CallCommonPropertySheetUI return error\n");
1231 Result = ERR_CPSUI_GETLASTERROR;
1232 }
1233 else
1234 Result = (Result == CPSUI_OK) ? IDOK : IDCANCEL;
1235 FIXME("CallCommonPropertySheetUI returned\n");
1236 }
1237 else
1238 {
1239 FIXME("DPW : CallDocumentPropertySheets\n");
1240 Result = DocumentPropertySheets( NULL, (LPARAM)&docprophdr );
1241 }
1242
1243 if ( Result != ERR_CPSUI_GETLASTERROR || Result != ERR_CPSUI_ALLOCMEM_FAILED )
1244 {
1245 if ( pDevModeOutput )
1246 {
1247 if ( !IsValidDevmodeNoSizeW( pDevModeOutput ) )
1248 {
1249 ERR("DPW : Improper pDevModeOutput size.\n");
1250 Result = -1;
1251 }
1252 }
1253 else
1254 {
1255 ERR("No pDevModeOutput\n");
1256 }
1257 }
1258
1259 if (hUseHandle && !hPrinter)
1260 ClosePrinter(hUseHandle);
1261 return Result;
1262 }
1263
1264 BOOL
1265 WINAPI
PrinterProperties(HWND hWnd,HANDLE hPrinter)1266 PrinterProperties( HWND hWnd, HANDLE hPrinter )
1267 {
1268 PRINTER_INFO_2W *pi2 = NULL;
1269 DWORD needed = 0;
1270 LONG Ret, Result = 0;
1271 BOOL res;
1272 DEVICEPROPERTYHEADER devprophdr;
1273
1274 FIXME("PrinterProperties(%p, %p)\n", hWnd, hPrinter);
1275
1276 devprophdr.cbSize = sizeof(DEVICEPROPERTYHEADER);
1277 devprophdr.Flags = DPS_NOPERMISSION;
1278 devprophdr.hPrinter = hPrinter;
1279 devprophdr.pszPrinterName = NULL;
1280
1281 res = GetPrinterW( hPrinter, 2, NULL, 0, &needed);
1282 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
1283 {
1284 pi2 = HeapAlloc(hProcessHeap, 0, needed);
1285 if (!pi2)
1286 {
1287 ERR("Failed to allocate PRINTER_INFO_2W of %u bytes\n", needed);
1288 return FALSE;
1289 }
1290 res = GetPrinterW(hPrinter, 2, (LPBYTE)pi2, needed, &needed);
1291 }
1292
1293 //
1294 // Above can fail, still process w/o printer name.
1295 //
1296 if ( res ) devprophdr.pszPrinterName = pi2->pPrinterName;
1297
1298 needed = 1;
1299
1300 if ( ( SetPrinterDataW( hPrinter, L"PrinterPropertiesPermission", REG_DWORD, (LPBYTE)&needed, sizeof(DWORD) ) == ERROR_SUCCESS ) )
1301 {
1302 devprophdr.Flags &= ~DPS_NOPERMISSION;
1303 }
1304
1305 Ret = CallCommonPropertySheetUI( hWnd, (PFNPROPSHEETUI)DevicePropertySheets, (LPARAM)&devprophdr, (LPDWORD)&Result );
1306
1307 res = (Ret >= 0);
1308
1309 if (!res)
1310 {
1311 FIXME("PrinterProperties fail ICPSUI\n");
1312 }
1313
1314 if (pi2) HeapFree(hProcessHeap, 0, pi2);
1315
1316 return res;
1317 }
1318
1319 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter)1320 EndDocPrinter(HANDLE hPrinter)
1321 {
1322 DWORD dwErrorCode;
1323 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
1324
1325 TRACE("EndDocPrinter(%p)\n", hPrinter);
1326
1327 // Sanity checks.
1328 if (!pHandle)
1329 {
1330 dwErrorCode = ERROR_INVALID_HANDLE;
1331 goto Cleanup;
1332 }
1333
1334 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
1335 {
1336 // For spooled jobs, the document is finished by calling _RpcScheduleJob.
1337 RpcTryExcept
1338 {
1339 dwErrorCode = _RpcScheduleJob(pHandle->hPrinter, pHandle->dwJobID);
1340 }
1341 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1342 {
1343 dwErrorCode = RpcExceptionCode();
1344 ERR("_RpcScheduleJob failed with exception code %lu!\n", dwErrorCode);
1345 }
1346 RpcEndExcept;
1347
1348 // Close the spool file handle.
1349 CloseHandle(pHandle->hSPLFile);
1350 }
1351 else
1352 {
1353 // In all other cases, just call _RpcEndDocPrinter.
1354 RpcTryExcept
1355 {
1356 dwErrorCode = _RpcEndDocPrinter(pHandle->hPrinter);
1357 }
1358 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1359 {
1360 dwErrorCode = RpcExceptionCode();
1361 ERR("_RpcEndDocPrinter failed with exception code %lu!\n", dwErrorCode);
1362 }
1363 RpcEndExcept;
1364 }
1365
1366 // A new document can now be started again.
1367 pHandle->bTrayIcon = pHandle->bJob = pHandle->bStartedDoc = FALSE;
1368
1369 Cleanup:
1370 SetLastError(dwErrorCode);
1371 return (dwErrorCode == ERROR_SUCCESS);
1372 }
1373
1374 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter)1375 EndPagePrinter(HANDLE hPrinter)
1376 {
1377 DWORD dwErrorCode;
1378 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
1379
1380 TRACE("EndPagePrinter(%p)\n", hPrinter);
1381
1382 // Sanity checks.
1383 if (!pHandle)
1384 {
1385 dwErrorCode = ERROR_INVALID_HANDLE;
1386 goto Cleanup;
1387 }
1388
1389 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
1390 {
1391 // For spooled jobs, we don't need to do anything.
1392 dwErrorCode = ERROR_SUCCESS;
1393 }
1394 else
1395 {
1396 // In all other cases, just call _RpcEndPagePrinter.
1397 RpcTryExcept
1398 {
1399 dwErrorCode = _RpcEndPagePrinter(pHandle->hPrinter);
1400 }
1401 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1402 {
1403 dwErrorCode = RpcExceptionCode();
1404 ERR("_RpcEndPagePrinter failed with exception code %lu!\n", dwErrorCode);
1405 }
1406 RpcEndExcept;
1407 }
1408
1409 Cleanup:
1410 SetLastError(dwErrorCode);
1411 return (dwErrorCode == ERROR_SUCCESS);
1412 }
1413
1414 BOOL WINAPI
EnumPrintersA(DWORD Flags,PSTR Name,DWORD Level,PBYTE pPrinterEnum,DWORD cbBuf,PDWORD pcbNeeded,PDWORD pcReturned)1415 EnumPrintersA(DWORD Flags, PSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
1416 {
1417 DWORD dwErrorCode;
1418 DWORD cch;
1419 PWSTR pwszName = NULL;
1420 PSTR pszPrinterName = NULL;
1421 PSTR pszServerName = NULL;
1422 PSTR pszDescription = NULL;
1423 PSTR pszName = NULL;
1424 PSTR pszComment = NULL;
1425 PSTR pszShareName = NULL;
1426 PSTR pszPortName = NULL;
1427 PSTR pszDriverName = NULL;
1428 PSTR pszLocation = NULL;
1429 PSTR pszSepFile = NULL;
1430 PSTR pszPrintProcessor = NULL;
1431 PSTR pszDatatype = NULL;
1432 PSTR pszParameters = NULL;
1433 DWORD i;
1434 PPRINTER_INFO_1W ppi1w = NULL;
1435 PPRINTER_INFO_1A ppi1a = NULL;
1436 PPRINTER_INFO_2W ppi2w = NULL;
1437 PPRINTER_INFO_2A ppi2a = NULL;
1438 PPRINTER_INFO_4W ppi4w = NULL;
1439 PPRINTER_INFO_4A ppi4a = NULL;
1440 PPRINTER_INFO_5W ppi5w = NULL;
1441 PPRINTER_INFO_5A ppi5a = NULL;
1442
1443 TRACE("EnumPrintersA(%lu, %s, %lu, %p, %lu, %p, %p)\n", Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
1444
1445 // Check for invalid levels here for early error return. MSDN says that only 1, 2, 4, and 5 are allowable.
1446 if (Level != 1 && Level != 2 && Level != 4 && Level != 5)
1447 {
1448 dwErrorCode = ERROR_INVALID_LEVEL;
1449 ERR("Invalid Level!\n");
1450 goto Cleanup;
1451 }
1452
1453 if (Name)
1454 {
1455 // Convert pName to a Unicode string pwszName.
1456 cch = strlen(Name);
1457
1458 pwszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
1459 if (!pwszName)
1460 {
1461 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1462 ERR("HeapAlloc failed!\n");
1463 goto Cleanup;
1464 }
1465
1466 MultiByteToWideChar(CP_ACP, 0, Name, -1, pwszName, cch + 1);
1467 }
1468
1469 /* Ref: https://stackoverflow.com/questions/41147180/why-enumprintersa-and-enumprintersw-request-the-same-amount-of-memory */
1470 if (!EnumPrintersW(Flags, pwszName, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned))
1471 {
1472 dwErrorCode = GetLastError();
1473 goto Cleanup;
1474 }
1475
1476 /* We are mapping multiple different pointers to the same pPrinterEnum pointer here so that */
1477 /* we can do in-place conversion. We read the Unicode response from the EnumPrintersW and */
1478 /* then we write back the ANSI conversion into the same buffer for our EnumPrintersA output */
1479
1480 /* mapping to pPrinterEnum for Unicode (w) characters for Levels 1, 2, 4, and 5 */
1481 ppi1w = (PPRINTER_INFO_1W)pPrinterEnum;
1482 ppi2w = (PPRINTER_INFO_2W)pPrinterEnum;
1483 ppi4w = (PPRINTER_INFO_4W)pPrinterEnum;
1484 ppi5w = (PPRINTER_INFO_5W)pPrinterEnum;
1485 /* mapping to pPrinterEnum for ANSI (a) characters for Levels 1, 2, 4, and 5 */
1486 ppi1a = (PPRINTER_INFO_1A)pPrinterEnum;
1487 ppi2a = (PPRINTER_INFO_2A)pPrinterEnum;
1488 ppi4a = (PPRINTER_INFO_4A)pPrinterEnum;
1489 ppi5a = (PPRINTER_INFO_5A)pPrinterEnum;
1490
1491 for (i = 0; i < *pcReturned; i++)
1492 {
1493 switch (Level)
1494 {
1495 case 1:
1496 {
1497 if (ppi1w[i].pDescription)
1498 {
1499 // Convert Unicode pDescription to a ANSI string pszDescription.
1500 cch = wcslen(ppi1w[i].pDescription);
1501
1502 pszDescription = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1503 if (!pszDescription)
1504 {
1505 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1506 ERR("HeapAlloc failed!\n");
1507 goto Cleanup;
1508 }
1509
1510 WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pDescription, -1, pszDescription, cch + 1, NULL, NULL);
1511 StringCchCopyA(ppi1a[i].pDescription, cch + 1, pszDescription);
1512
1513 HeapFree(hProcessHeap, 0, pszDescription);
1514 }
1515
1516 if (ppi1w[i].pName)
1517 {
1518 // Convert Unicode pName to a ANSI string pszName.
1519 cch = wcslen(ppi1w[i].pName);
1520
1521 pszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1522 if (!pszName)
1523 {
1524 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1525 ERR("HeapAlloc failed!\n");
1526 goto Cleanup;
1527 }
1528
1529 WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pName, -1, pszName, cch + 1, NULL, NULL);
1530 StringCchCopyA(ppi1a[i].pName, cch + 1, pszName);
1531
1532 HeapFree(hProcessHeap, 0, pszName);
1533 }
1534
1535 if (ppi1w[i].pComment)
1536 {
1537 // Convert Unicode pComment to a ANSI string pszComment.
1538 cch = wcslen(ppi1w[i].pComment);
1539
1540 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1541 if (!pszComment)
1542 {
1543 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1544 ERR("HeapAlloc failed!\n");
1545 goto Cleanup;
1546 }
1547
1548 WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pComment, -1, pszComment, cch + 1, NULL, NULL);
1549 StringCchCopyA(ppi1a[i].pComment, cch + 1, pszComment);
1550
1551 HeapFree(hProcessHeap, 0, pszComment);
1552 }
1553 break;
1554 }
1555
1556
1557 case 2:
1558 {
1559 if (ppi2w[i].pServerName)
1560 {
1561 // Convert Unicode pServerName to a ANSI string pszServerName.
1562 cch = wcslen(ppi2w[i].pServerName);
1563
1564 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1565 if (!pszServerName)
1566 {
1567 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1568 ERR("HeapAlloc failed!\n");
1569 goto Cleanup;
1570 }
1571
1572 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pServerName, -1, pszServerName, cch + 1, NULL, NULL);
1573 StringCchCopyA(ppi2a[i].pServerName, cch + 1, pszServerName);
1574
1575 HeapFree(hProcessHeap, 0, pszServerName);
1576 }
1577
1578 if (ppi2w[i].pPrinterName)
1579 {
1580 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
1581 cch = wcslen(ppi2w[i].pPrinterName);
1582
1583 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1584 if (!pszPrinterName)
1585 {
1586 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1587 ERR("HeapAlloc failed!\n");
1588 goto Cleanup;
1589 }
1590
1591 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
1592 StringCchCopyA(ppi2a[i].pPrinterName, cch + 1, pszPrinterName);
1593
1594 HeapFree(hProcessHeap, 0, pszPrinterName);
1595 }
1596
1597 if (ppi2w[i].pShareName)
1598 {
1599 // Convert Unicode pShareName to a ANSI string pszShareName.
1600 cch = wcslen(ppi2w[i].pShareName);
1601
1602 pszShareName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1603 if (!pszShareName)
1604 {
1605 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1606 ERR("HeapAlloc failed!\n");
1607 goto Cleanup;
1608 }
1609
1610 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pShareName, -1, pszShareName, cch + 1, NULL, NULL);
1611 StringCchCopyA(ppi2a[i].pShareName, cch + 1, pszShareName);
1612
1613 HeapFree(hProcessHeap, 0, pszShareName);
1614 }
1615
1616 if (ppi2w[i].pPortName)
1617 {
1618 // Convert Unicode pPortName to a ANSI string pszPortName.
1619 cch = wcslen(ppi2w[i].pPortName);
1620
1621 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1622 if (!pszPortName)
1623 {
1624 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1625 ERR("HeapAlloc failed!\n");
1626 goto Cleanup;
1627 }
1628
1629 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPortName, -1, pszPortName, cch + 1, NULL, NULL);
1630 StringCchCopyA(ppi2a[i].pPortName, cch + 1, pszPortName);
1631
1632 HeapFree(hProcessHeap, 0, pszPortName);
1633 }
1634
1635 if (ppi2w[i].pDriverName)
1636 {
1637 // Convert Unicode pDriverName to a ANSI string pszDriverName.
1638 cch = wcslen(ppi2w[i].pDriverName);
1639
1640 pszDriverName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1641 if (!pszDriverName)
1642 {
1643 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1644 ERR("HeapAlloc failed!\n");
1645 goto Cleanup;
1646 }
1647
1648 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pDriverName, -1, pszDriverName, cch + 1, NULL, NULL);
1649 StringCchCopyA(ppi2a[i].pDriverName, cch + 1, pszDriverName);
1650
1651 HeapFree(hProcessHeap, 0, pszDriverName);
1652 }
1653
1654 if (ppi2w[i].pComment)
1655 {
1656 // Convert Unicode pComment to a ANSI string pszComment.
1657 cch = wcslen(ppi2w[i].pComment);
1658
1659 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1660 if (!pszComment)
1661 {
1662 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1663 ERR("HeapAlloc failed!\n");
1664 goto Cleanup;
1665 }
1666
1667 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pComment, -1, pszComment, cch + 1, NULL, NULL);
1668 StringCchCopyA(ppi2a[i].pComment, cch + 1, pszComment);
1669
1670 HeapFree(hProcessHeap, 0, pszComment);
1671 }
1672
1673 if (ppi2w[i].pLocation)
1674 {
1675 // Convert Unicode pLocation to a ANSI string pszLocation.
1676 cch = wcslen(ppi2w[i].pLocation);
1677
1678 pszLocation = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1679 if (!pszLocation)
1680 {
1681 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1682 ERR("HeapAlloc failed!\n");
1683 goto Cleanup;
1684 }
1685
1686 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pLocation, -1, pszLocation, cch + 1, NULL, NULL);
1687 StringCchCopyA(ppi2a[i].pLocation, cch + 1, pszLocation);
1688
1689 HeapFree(hProcessHeap, 0, pszLocation);
1690 }
1691
1692
1693 if (ppi2w[i].pSepFile)
1694 {
1695 // Convert Unicode pSepFile to a ANSI string pszSepFile.
1696 cch = wcslen(ppi2w[i].pSepFile);
1697
1698 pszSepFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1699 if (!pszSepFile)
1700 {
1701 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1702 ERR("HeapAlloc failed!\n");
1703 goto Cleanup;
1704 }
1705
1706 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pSepFile, -1, pszSepFile, cch + 1, NULL, NULL);
1707 StringCchCopyA(ppi2a[i].pSepFile, cch + 1, pszSepFile);
1708
1709 HeapFree(hProcessHeap, 0, pszSepFile);
1710 }
1711
1712 if (ppi2w[i].pPrintProcessor)
1713 {
1714 // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor.
1715 cch = wcslen(ppi2w[i].pPrintProcessor);
1716
1717 pszPrintProcessor = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1718 if (!pszPrintProcessor)
1719 {
1720 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1721 ERR("HeapAlloc failed!\n");
1722 goto Cleanup;
1723 }
1724
1725 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPrintProcessor, -1, pszPrintProcessor, cch + 1, NULL, NULL);
1726 StringCchCopyA(ppi2a[i].pPrintProcessor, cch + 1, pszPrintProcessor);
1727
1728 HeapFree(hProcessHeap, 0, pszPrintProcessor);
1729 }
1730
1731
1732 if (ppi2w[i].pDatatype)
1733 {
1734 // Convert Unicode pDatatype to a ANSI string pszDatatype.
1735 cch = wcslen(ppi2w[i].pDatatype);
1736
1737 pszDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1738 if (!pszDatatype)
1739 {
1740 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1741 ERR("HeapAlloc failed!\n");
1742 goto Cleanup;
1743 }
1744
1745 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pDatatype, -1, pszDatatype, cch + 1, NULL, NULL);
1746 StringCchCopyA(ppi2a[i].pDatatype, cch + 1, pszDatatype);
1747
1748 HeapFree(hProcessHeap, 0, pszDatatype);
1749 }
1750
1751 if (ppi2w[i].pParameters)
1752 {
1753 // Convert Unicode pParameters to a ANSI string pszParameters.
1754 cch = wcslen(ppi2w[i].pParameters);
1755
1756 pszParameters = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1757 if (!pszParameters)
1758 {
1759 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1760 ERR("HeapAlloc failed!\n");
1761 goto Cleanup;
1762 }
1763
1764 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pParameters, -1, pszParameters, cch + 1, NULL, NULL);
1765 StringCchCopyA(ppi2a[i].pParameters, cch + 1, pszParameters);
1766
1767 HeapFree(hProcessHeap, 0, pszParameters);
1768 }
1769 if ( ppi2w[i].pDevMode )
1770 {
1771 RosConvertUnicodeDevModeToAnsiDevmode( ppi2w[i].pDevMode, ppi2a[i].pDevMode );
1772 }
1773 break;
1774 }
1775
1776 case 4:
1777 {
1778 if (ppi4w[i].pPrinterName)
1779 {
1780 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
1781 cch = wcslen(ppi4w[i].pPrinterName);
1782
1783 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1784 if (!pszPrinterName)
1785 {
1786 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1787 ERR("HeapAlloc failed!\n");
1788 goto Cleanup;
1789 }
1790
1791 WideCharToMultiByte(CP_ACP, 0, ppi4w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
1792 StringCchCopyA(ppi4a[i].pPrinterName, cch + 1, pszPrinterName);
1793
1794 HeapFree(hProcessHeap, 0, pszPrinterName);
1795 }
1796
1797 if (ppi4w[i].pServerName)
1798 {
1799 // Convert Unicode pServerName to a ANSI string pszServerName.
1800 cch = wcslen(ppi4w[i].pServerName);
1801
1802 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1803 if (!pszServerName)
1804 {
1805 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1806 ERR("HeapAlloc failed!\n");
1807 goto Cleanup;
1808 }
1809
1810 WideCharToMultiByte(CP_ACP, 0, ppi4w[i].pServerName, -1, pszServerName, cch + 1, NULL, NULL);
1811 StringCchCopyA(ppi4a[i].pServerName, cch + 1, pszServerName);
1812
1813 HeapFree(hProcessHeap, 0, pszServerName);
1814 }
1815 break;
1816 }
1817
1818 case 5:
1819 {
1820 if (ppi5w[i].pPrinterName)
1821 {
1822 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
1823 cch = wcslen(ppi5w[i].pPrinterName);
1824
1825 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1826 if (!pszPrinterName)
1827 {
1828 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1829 ERR("HeapAlloc failed!\n");
1830 goto Cleanup;
1831 }
1832
1833 WideCharToMultiByte(CP_ACP, 0, ppi5w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
1834 StringCchCopyA(ppi5a[i].pPrinterName, cch + 1, pszPrinterName);
1835
1836 HeapFree(hProcessHeap, 0, pszPrinterName);
1837 }
1838
1839 if (ppi5w[i].pPortName)
1840 {
1841 // Convert Unicode pPortName to a ANSI string pszPortName.
1842 cch = wcslen(ppi5w[i].pPortName);
1843
1844 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1845 if (!pszPortName)
1846 {
1847 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1848 ERR("HeapAlloc failed!\n");
1849 goto Cleanup;
1850 }
1851
1852 WideCharToMultiByte(CP_ACP, 0, ppi5w[i].pPortName, -1, pszPortName, cch + 1, NULL, NULL);
1853 StringCchCopyA(ppi5a[i].pPortName, cch + 1, pszPortName);
1854
1855 HeapFree(hProcessHeap, 0, pszPortName);
1856 }
1857 break;
1858 }
1859
1860 } // switch
1861 } // for
1862
1863 dwErrorCode = ERROR_SUCCESS;
1864
1865 Cleanup:
1866 if (pwszName)
1867 {
1868 HeapFree(hProcessHeap, 0, pwszName);
1869 }
1870
1871 SetLastError(dwErrorCode);
1872 return (dwErrorCode == ERROR_SUCCESS);
1873 }
1874
1875 BOOL WINAPI
EnumPrintersW(DWORD Flags,PWSTR Name,DWORD Level,PBYTE pPrinterEnum,DWORD cbBuf,PDWORD pcbNeeded,PDWORD pcReturned)1876 EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
1877 {
1878 DWORD dwErrorCode;
1879
1880 TRACE("EnumPrintersW(%lu, %S, %lu, %p, %lu, %p, %p)\n", Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
1881
1882 // Dismiss invalid levels already at this point.
1883 if (Level == 3 || Level > 5)
1884 {
1885 dwErrorCode = ERROR_INVALID_LEVEL;
1886 goto Cleanup;
1887 }
1888
1889 if (cbBuf && pPrinterEnum)
1890 ZeroMemory(pPrinterEnum, cbBuf);
1891
1892 // Do the RPC call
1893 RpcTryExcept
1894 {
1895 dwErrorCode = _RpcEnumPrinters(Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
1896 }
1897 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1898 {
1899 dwErrorCode = RpcExceptionCode();
1900 ERR("_RpcEnumPrinters failed with exception code %lu!\n", dwErrorCode);
1901 }
1902 RpcEndExcept;
1903
1904 if (dwErrorCode == ERROR_SUCCESS)
1905 {
1906 // Replace relative offset addresses in the output by absolute pointers.
1907 ASSERT(Level <= 9);
1908 MarshallUpStructuresArray(cbBuf, pPrinterEnum, *pcReturned, pPrinterInfoMarshalling[Level]->pInfo, pPrinterInfoMarshalling[Level]->cbStructureSize, TRUE);
1909 }
1910
1911 Cleanup:
1912 SetLastError(dwErrorCode);
1913 return (dwErrorCode == ERROR_SUCCESS);
1914 }
1915
1916 BOOL WINAPI
FlushPrinter(HANDLE hPrinter,PVOID pBuf,DWORD cbBuf,PDWORD pcWritten,DWORD cSleep)1917 FlushPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten, DWORD cSleep)
1918 {
1919 TRACE("FlushPrinter(%p, %p, %lu, %p, %lu)\n", hPrinter, pBuf, cbBuf, pcWritten, cSleep);
1920 UNIMPLEMENTED;
1921 return FALSE;
1922 }
1923
1924 BOOL WINAPI
GetDefaultPrinterA(LPSTR pszBuffer,LPDWORD pcchBuffer)1925 GetDefaultPrinterA(LPSTR pszBuffer, LPDWORD pcchBuffer)
1926 {
1927 DWORD dwErrorCode;
1928 PWSTR pwszBuffer = NULL;
1929
1930 TRACE("GetDefaultPrinterA(%p, %p)\n", pszBuffer, pcchBuffer);
1931
1932 // Sanity check.
1933 if (!pcchBuffer)
1934 {
1935 dwErrorCode = ERROR_INVALID_PARAMETER;
1936 goto Cleanup;
1937 }
1938
1939 // Check if an ANSI buffer was given and if so, allocate a Unicode buffer of the same size.
1940 if (pszBuffer && *pcchBuffer)
1941 {
1942 pwszBuffer = HeapAlloc(hProcessHeap, 0, *pcchBuffer * sizeof(WCHAR));
1943 if (!pwszBuffer)
1944 {
1945 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1946 ERR("HeapAlloc failed!\n");
1947 goto Cleanup;
1948 }
1949 }
1950
1951 if (!GetDefaultPrinterW(pwszBuffer, pcchBuffer))
1952 {
1953 dwErrorCode = GetLastError();
1954 goto Cleanup;
1955 }
1956
1957 // We successfully got a string in pwszBuffer, so convert the Unicode string to ANSI.
1958 WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, *pcchBuffer, NULL, NULL);
1959
1960 dwErrorCode = ERROR_SUCCESS;
1961
1962 Cleanup:
1963 if (pwszBuffer)
1964 HeapFree(hProcessHeap, 0, pwszBuffer);
1965
1966 SetLastError(dwErrorCode);
1967 return (dwErrorCode == ERROR_SUCCESS);
1968 }
1969
1970 BOOL WINAPI
GetDefaultPrinterW(LPWSTR pszBuffer,LPDWORD pcchBuffer)1971 GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer)
1972 {
1973 DWORD cbNeeded;
1974 DWORD cchInputBuffer;
1975 DWORD dwErrorCode;
1976 HKEY hWindowsKey = NULL;
1977 PWSTR pwszDevice = NULL;
1978 PWSTR pwszComma;
1979
1980 TRACE("GetDefaultPrinterW(%p, %p)\n", pszBuffer, pcchBuffer);
1981
1982 // Sanity check.
1983 if (!pcchBuffer)
1984 {
1985 dwErrorCode = ERROR_INVALID_PARAMETER;
1986 goto Cleanup;
1987 }
1988
1989 cchInputBuffer = *pcchBuffer;
1990
1991 // Open the registry key where the default printer for the current user is stored.
1992 dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_READ, &hWindowsKey);
1993 if (dwErrorCode != ERROR_SUCCESS)
1994 {
1995 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
1996 goto Cleanup;
1997 }
1998
1999 // Determine the size of the required buffer.
2000 dwErrorCode = (DWORD)RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, NULL, &cbNeeded);
2001 if (dwErrorCode != ERROR_SUCCESS)
2002 {
2003 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
2004 goto Cleanup;
2005 }
2006
2007 // Allocate it.
2008 pwszDevice = HeapAlloc(hProcessHeap, 0, cbNeeded);
2009 if (!pwszDevice)
2010 {
2011 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2012 ERR("HeapAlloc failed!\n");
2013 goto Cleanup;
2014 }
2015
2016 // Now get the actual value.
2017 dwErrorCode = RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, (PBYTE)pwszDevice, &cbNeeded);
2018 if (dwErrorCode != ERROR_SUCCESS)
2019 {
2020 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
2021 goto Cleanup;
2022 }
2023
2024 // We get a string "<Printer Name>,winspool,<Port>:".
2025 // Extract the printer name from it.
2026 pwszComma = wcschr(pwszDevice, L',');
2027 if (!pwszComma)
2028 {
2029 ERR("Found no or invalid default printer: %S!\n", pwszDevice);
2030 dwErrorCode = ERROR_INVALID_NAME;
2031 goto Cleanup;
2032 }
2033
2034 // Store the length of the Printer Name (including the terminating NUL character!) in *pcchBuffer.
2035 *pcchBuffer = pwszComma - pwszDevice + 1;
2036
2037 // Check if the supplied buffer is large enough.
2038 if ( !pszBuffer || cchInputBuffer < *pcchBuffer)
2039 {
2040 dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
2041 goto Cleanup;
2042 }
2043
2044 // Copy the default printer.
2045 *pwszComma = 0;
2046 CopyMemory(pszBuffer, pwszDevice, *pcchBuffer * sizeof(WCHAR));
2047
2048 dwErrorCode = ERROR_SUCCESS;
2049
2050 Cleanup:
2051 if (hWindowsKey)
2052 RegCloseKey(hWindowsKey);
2053
2054 if (pwszDevice)
2055 HeapFree(hProcessHeap, 0, pwszDevice);
2056
2057 SetLastError(dwErrorCode);
2058 return (dwErrorCode == ERROR_SUCCESS);
2059 }
2060
2061 BOOL WINAPI
GetPrinterA(HANDLE hPrinter,DWORD Level,LPBYTE pPrinter,DWORD cbBuf,LPDWORD pcbNeeded)2062 GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
2063 {
2064 DWORD dwErrorCode;
2065 PPRINTER_INFO_1A ppi1a = (PPRINTER_INFO_1A)pPrinter;
2066 PPRINTER_INFO_1W ppi1w = (PPRINTER_INFO_1W)pPrinter;
2067 PPRINTER_INFO_2A ppi2a = (PPRINTER_INFO_2A)pPrinter;
2068 PPRINTER_INFO_2W ppi2w = (PPRINTER_INFO_2W)pPrinter;
2069 PPRINTER_INFO_4A ppi4a = (PPRINTER_INFO_4A)pPrinter;
2070 PPRINTER_INFO_4W ppi4w = (PPRINTER_INFO_4W)pPrinter;
2071 PPRINTER_INFO_5A ppi5a = (PPRINTER_INFO_5A)pPrinter;
2072 PPRINTER_INFO_5W ppi5w = (PPRINTER_INFO_5W)pPrinter;
2073 PPRINTER_INFO_7A ppi7a = (PPRINTER_INFO_7A)pPrinter;
2074 PPRINTER_INFO_7W ppi7w = (PPRINTER_INFO_7W)pPrinter;
2075 PPRINTER_INFO_9A ppi9a = (PPRINTER_INFO_9A)pPrinter;
2076 PPRINTER_INFO_9W ppi9w = (PPRINTER_INFO_9W)pPrinter;
2077 DWORD cch;
2078
2079 TRACE("GetPrinterA(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
2080
2081 // Check for invalid levels here for early error return. Should be 1-9.
2082 if (Level < 1 || Level > 9)
2083 {
2084 dwErrorCode = ERROR_INVALID_LEVEL;
2085 ERR("Invalid Level!\n");
2086 goto Cleanup;
2087 }
2088
2089 if (!GetPrinterW(hPrinter, Level, pPrinter, cbBuf, pcbNeeded))
2090 {
2091 dwErrorCode = GetLastError();
2092 goto Cleanup;
2093 }
2094
2095 switch (Level)
2096 {
2097 case 1:
2098 {
2099 if (ppi1w->pDescription)
2100 {
2101 PSTR pszDescription;
2102
2103 // Convert Unicode pDescription to a ANSI string pszDescription.
2104 cch = wcslen(ppi1w->pDescription);
2105
2106 pszDescription = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2107 if (!pszDescription)
2108 {
2109 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2110 ERR("HeapAlloc failed!\n");
2111 goto Cleanup;
2112 }
2113
2114 WideCharToMultiByte(CP_ACP, 0, ppi1w->pDescription, -1, pszDescription, cch + 1, NULL, NULL);
2115 StringCchCopyA(ppi1a->pDescription, cch + 1, pszDescription);
2116
2117 HeapFree(hProcessHeap, 0, pszDescription);
2118 }
2119
2120 if (ppi1w->pName)
2121 {
2122 PSTR pszName;
2123
2124 // Convert Unicode pName to a ANSI string pszName.
2125 cch = wcslen(ppi1w->pName);
2126
2127 pszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2128 if (!pszName)
2129 {
2130 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2131 ERR("HeapAlloc failed!\n");
2132 goto Cleanup;
2133 }
2134
2135 WideCharToMultiByte(CP_ACP, 0, ppi1w->pName, -1, pszName, cch + 1, NULL, NULL);
2136 StringCchCopyA(ppi1a->pName, cch + 1, pszName);
2137
2138 HeapFree(hProcessHeap, 0, pszName);
2139 }
2140
2141 if (ppi1w->pComment)
2142 {
2143 PSTR pszComment;
2144
2145 // Convert Unicode pComment to a ANSI string pszComment.
2146 cch = wcslen(ppi1w->pComment);
2147
2148 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2149 if (!pszComment)
2150 {
2151 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2152 ERR("HeapAlloc failed!\n");
2153 goto Cleanup;
2154 }
2155
2156 WideCharToMultiByte(CP_ACP, 0, ppi1w->pComment, -1, pszComment, cch + 1, NULL, NULL);
2157 StringCchCopyA(ppi1a->pComment, cch + 1, pszComment);
2158
2159 HeapFree(hProcessHeap, 0, pszComment);
2160 }
2161 break;
2162 }
2163
2164 case 2:
2165 {
2166 if (ppi2w->pServerName)
2167 {
2168 PSTR pszServerName;
2169
2170 // Convert Unicode pServerName to a ANSI string pszServerName.
2171 cch = wcslen(ppi2w->pServerName);
2172
2173 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2174 if (!pszServerName)
2175 {
2176 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2177 ERR("HeapAlloc failed!\n");
2178 goto Cleanup;
2179 }
2180
2181 WideCharToMultiByte(CP_ACP, 0, ppi2w->pServerName, -1, pszServerName, cch + 1, NULL, NULL);
2182 StringCchCopyA(ppi2a->pServerName, cch + 1, pszServerName);
2183
2184 HeapFree(hProcessHeap, 0, pszServerName);
2185 }
2186
2187 if (ppi2w->pPrinterName)
2188 {
2189 PSTR pszPrinterName;
2190
2191 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
2192 cch = wcslen(ppi2w->pPrinterName);
2193
2194 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2195 if (!pszPrinterName)
2196 {
2197 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2198 ERR("HeapAlloc failed!\n");
2199 goto Cleanup;
2200 }
2201
2202 WideCharToMultiByte(CP_ACP, 0, ppi2w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
2203 StringCchCopyA(ppi2a->pPrinterName, cch + 1, pszPrinterName);
2204
2205 HeapFree(hProcessHeap, 0, pszPrinterName);
2206 }
2207
2208 if (ppi2w->pShareName)
2209 {
2210 PSTR pszShareName;
2211
2212 // Convert Unicode pShareName to a ANSI string pszShareName.
2213 cch = wcslen(ppi2w->pShareName);
2214
2215 pszShareName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2216 if (!pszShareName)
2217 {
2218 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2219 ERR("HeapAlloc failed!\n");
2220 goto Cleanup;
2221 }
2222
2223 WideCharToMultiByte(CP_ACP, 0, ppi2w->pShareName, -1, pszShareName, cch + 1, NULL, NULL);
2224 StringCchCopyA(ppi2a->pShareName, cch + 1, pszShareName);
2225
2226 HeapFree(hProcessHeap, 0, pszShareName);
2227 }
2228
2229 if (ppi2w->pPortName)
2230 {
2231 PSTR pszPortName;
2232
2233 // Convert Unicode pPortName to a ANSI string pszPortName.
2234 cch = wcslen(ppi2w->pPortName);
2235
2236 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2237 if (!pszPortName)
2238 {
2239 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2240 ERR("HeapAlloc failed!\n");
2241 goto Cleanup;
2242 }
2243
2244 WideCharToMultiByte(CP_ACP, 0, ppi2w->pPortName, -1, pszPortName, cch + 1, NULL, NULL);
2245 StringCchCopyA(ppi2a->pPortName, cch + 1, pszPortName);
2246
2247 HeapFree(hProcessHeap, 0, pszPortName);
2248 }
2249
2250 if (ppi2w->pDriverName)
2251 {
2252 PSTR pszDriverName;
2253
2254 // Convert Unicode pDriverName to a ANSI string pszDriverName.
2255 cch = wcslen(ppi2w->pDriverName);
2256
2257 pszDriverName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2258 if (!pszDriverName)
2259 {
2260 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2261 ERR("HeapAlloc failed!\n");
2262 goto Cleanup;
2263 }
2264
2265 WideCharToMultiByte(CP_ACP, 0, ppi2w->pDriverName, -1, pszDriverName, cch + 1, NULL, NULL);
2266 StringCchCopyA(ppi2a->pDriverName, cch + 1, pszDriverName);
2267
2268 HeapFree(hProcessHeap, 0, pszDriverName);
2269 }
2270
2271 if (ppi2w->pComment)
2272 {
2273 PSTR pszComment;
2274
2275 // Convert Unicode pComment to a ANSI string pszComment.
2276 cch = wcslen(ppi2w->pComment);
2277
2278 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2279 if (!pszComment)
2280 {
2281 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2282 ERR("HeapAlloc failed!\n");
2283 goto Cleanup;
2284 }
2285
2286 WideCharToMultiByte(CP_ACP, 0, ppi2w->pComment, -1, pszComment, cch + 1, NULL, NULL);
2287 StringCchCopyA(ppi2a->pComment, cch + 1, pszComment);
2288
2289 HeapFree(hProcessHeap, 0, pszComment);
2290 }
2291
2292 if (ppi2w->pLocation)
2293 {
2294 PSTR pszLocation;
2295
2296 // Convert Unicode pLocation to a ANSI string pszLocation.
2297 cch = wcslen(ppi2w->pLocation);
2298
2299 pszLocation = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2300 if (!pszLocation)
2301 {
2302 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2303 ERR("HeapAlloc failed!\n");
2304 goto Cleanup;
2305 }
2306
2307 WideCharToMultiByte(CP_ACP, 0, ppi2w->pLocation, -1, pszLocation, cch + 1, NULL, NULL);
2308 StringCchCopyA(ppi2a->pLocation, cch + 1, pszLocation);
2309
2310 HeapFree(hProcessHeap, 0, pszLocation);
2311 }
2312
2313 if (ppi2w->pSepFile)
2314 {
2315 PSTR pszSepFile;
2316
2317 // Convert Unicode pSepFile to a ANSI string pszSepFile.
2318 cch = wcslen(ppi2w->pSepFile);
2319
2320 pszSepFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2321 if (!pszSepFile)
2322 {
2323 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2324 ERR("HeapAlloc failed!\n");
2325 goto Cleanup;
2326 }
2327
2328 WideCharToMultiByte(CP_ACP, 0, ppi2w->pSepFile, -1, pszSepFile, cch + 1, NULL, NULL);
2329 StringCchCopyA(ppi2a->pSepFile, cch + 1, pszSepFile);
2330
2331 HeapFree(hProcessHeap, 0, pszSepFile);
2332 }
2333
2334 if (ppi2w->pPrintProcessor)
2335 {
2336 PSTR pszPrintProcessor;
2337
2338 // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor.
2339 cch = wcslen(ppi2w->pPrintProcessor);
2340
2341 pszPrintProcessor = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2342 if (!pszPrintProcessor)
2343 {
2344 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2345 ERR("HeapAlloc failed!\n");
2346 goto Cleanup;
2347 }
2348
2349 WideCharToMultiByte(CP_ACP, 0, ppi2w->pPrintProcessor, -1, pszPrintProcessor, cch + 1, NULL, NULL);
2350 StringCchCopyA(ppi2a->pPrintProcessor, cch + 1, pszPrintProcessor);
2351
2352 HeapFree(hProcessHeap, 0, pszPrintProcessor);
2353 }
2354
2355 if (ppi2w->pDatatype)
2356 {
2357 PSTR pszDatatype;
2358
2359 // Convert Unicode pDatatype to a ANSI string pszDatatype.
2360 cch = wcslen(ppi2w->pDatatype);
2361
2362 pszDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2363 if (!pszDatatype)
2364 {
2365 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2366 ERR("HeapAlloc failed!\n");
2367 goto Cleanup;
2368 }
2369
2370 WideCharToMultiByte(CP_ACP, 0, ppi2w->pDatatype, -1, pszDatatype, cch + 1, NULL, NULL);
2371 StringCchCopyA(ppi2a->pDatatype, cch + 1, pszDatatype);
2372
2373 HeapFree(hProcessHeap, 0, pszDatatype);
2374 }
2375
2376 if (ppi2w->pParameters)
2377 {
2378 PSTR pszParameters;
2379
2380 // Convert Unicode pParameters to a ANSI string pszParameters.
2381 cch = wcslen(ppi2w->pParameters);
2382
2383 pszParameters = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2384 if (!pszParameters)
2385 {
2386 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2387 ERR("HeapAlloc failed!\n");
2388 goto Cleanup;
2389 }
2390
2391 WideCharToMultiByte(CP_ACP, 0, ppi2w->pParameters, -1, pszParameters, cch + 1, NULL, NULL);
2392 StringCchCopyA(ppi2a->pParameters, cch + 1, pszParameters);
2393
2394 HeapFree(hProcessHeap, 0, pszParameters);
2395 }
2396 if ( ppi2w->pDevMode )
2397 {
2398 RosConvertUnicodeDevModeToAnsiDevmode( ppi2w->pDevMode, ppi2a->pDevMode );
2399 }
2400 break;
2401 }
2402
2403 case 4:
2404 {
2405 if (ppi4w->pPrinterName)
2406 {
2407 PSTR pszPrinterName;
2408
2409 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
2410 cch = wcslen(ppi4w->pPrinterName);
2411
2412 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2413 if (!pszPrinterName)
2414 {
2415 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2416 ERR("HeapAlloc failed!\n");
2417 goto Cleanup;
2418 }
2419
2420 WideCharToMultiByte(CP_ACP, 0, ppi4w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
2421 StringCchCopyA(ppi4a->pPrinterName, cch + 1, pszPrinterName);
2422
2423 HeapFree(hProcessHeap, 0, pszPrinterName);
2424 }
2425
2426 if (ppi4w->pServerName)
2427 {
2428 PSTR pszServerName;
2429
2430 // Convert Unicode pServerName to a ANSI string pszServerName.
2431 cch = wcslen(ppi4w->pServerName);
2432
2433 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2434 if (!pszServerName)
2435 {
2436 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2437 ERR("HeapAlloc failed!\n");
2438 goto Cleanup;
2439 }
2440
2441 WideCharToMultiByte(CP_ACP, 0, ppi4w->pServerName, -1, pszServerName, cch + 1, NULL, NULL);
2442 StringCchCopyA(ppi4a->pServerName, cch + 1, pszServerName);
2443
2444 HeapFree(hProcessHeap, 0, pszServerName);
2445 }
2446 break;
2447 }
2448
2449 case 5:
2450 {
2451 if (ppi5w->pPrinterName)
2452 {
2453 PSTR pszPrinterName;
2454
2455 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
2456 cch = wcslen(ppi5w->pPrinterName);
2457
2458 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2459 if (!pszPrinterName)
2460 {
2461 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2462 ERR("HeapAlloc failed!\n");
2463 goto Cleanup;
2464 }
2465
2466 WideCharToMultiByte(CP_ACP, 0, ppi5w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
2467 StringCchCopyA(ppi5a->pPrinterName, cch + 1, pszPrinterName);
2468
2469 HeapFree(hProcessHeap, 0, pszPrinterName);
2470 }
2471
2472 if (ppi5w->pPortName)
2473 {
2474 PSTR pszPortName;
2475
2476 // Convert Unicode pPortName to a ANSI string pszPortName.
2477 cch = wcslen(ppi5w->pPortName);
2478
2479 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2480 if (!pszPortName)
2481 {
2482 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2483 ERR("HeapAlloc failed!\n");
2484 goto Cleanup;
2485 }
2486
2487 WideCharToMultiByte(CP_ACP, 0, ppi5w->pPortName, -1, pszPortName, cch + 1, NULL, NULL);
2488 StringCchCopyA(ppi5a->pPortName, cch + 1, pszPortName);
2489
2490 HeapFree(hProcessHeap, 0, pszPortName);
2491 }
2492 break;
2493 }
2494
2495 case 7:
2496 {
2497 if (ppi7w->pszObjectGUID)
2498 {
2499 PSTR pszaObjectGUID;
2500
2501 // Convert Unicode pszObjectGUID to a ANSI string pszaObjectGUID.
2502 cch = wcslen(ppi7w->pszObjectGUID);
2503
2504 pszaObjectGUID = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2505 if (!pszaObjectGUID)
2506 {
2507 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2508 ERR("HeapAlloc failed!\n");
2509 goto Cleanup;
2510 }
2511
2512 WideCharToMultiByte(CP_ACP, 0, ppi7w->pszObjectGUID, -1, pszaObjectGUID, cch + 1, NULL, NULL);
2513 StringCchCopyA(ppi7a->pszObjectGUID, cch + 1, pszaObjectGUID);
2514
2515 HeapFree(hProcessHeap, 0, pszaObjectGUID);
2516 }
2517 }
2518 break;
2519 case 8:
2520 case 9:
2521 RosConvertUnicodeDevModeToAnsiDevmode(ppi9w->pDevMode, ppi9a->pDevMode);
2522 break;
2523 } // switch
2524
2525 dwErrorCode = ERROR_SUCCESS;
2526
2527 Cleanup:
2528 SetLastError(dwErrorCode);
2529 return (dwErrorCode == ERROR_SUCCESS);
2530 }
2531
2532 BOOL WINAPI
GetPrinterW(HANDLE hPrinter,DWORD Level,LPBYTE pPrinter,DWORD cbBuf,LPDWORD pcbNeeded)2533 GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
2534 {
2535 DWORD dwErrorCode;
2536 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
2537
2538 TRACE("GetPrinterW(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
2539
2540 // Sanity checks.
2541 if (!pHandle)
2542 {
2543 dwErrorCode = ERROR_INVALID_HANDLE;
2544 goto Cleanup;
2545 }
2546
2547 // Dismiss invalid levels already at this point.
2548 if (Level > 9)
2549 {
2550 dwErrorCode = ERROR_INVALID_LEVEL;
2551 goto Cleanup;
2552 }
2553
2554 if (cbBuf && pPrinter)
2555 ZeroMemory(pPrinter, cbBuf);
2556
2557 // Do the RPC call
2558 RpcTryExcept
2559 {
2560 dwErrorCode = _RpcGetPrinter(pHandle->hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
2561 }
2562 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2563 {
2564 dwErrorCode = RpcExceptionCode();
2565 ERR("_RpcGetPrinter failed with exception code %lu!\n", dwErrorCode);
2566 }
2567 RpcEndExcept;
2568
2569 if (dwErrorCode == ERROR_SUCCESS)
2570 {
2571 // Replace relative offset addresses in the output by absolute pointers.
2572 ASSERT(Level <= 9);
2573 MarshallUpStructure(cbBuf, pPrinter, pPrinterInfoMarshalling[Level]->pInfo, pPrinterInfoMarshalling[Level]->cbStructureSize, TRUE);
2574 }
2575
2576 Cleanup:
2577 SetLastError(dwErrorCode);
2578 return (dwErrorCode == ERROR_SUCCESS);
2579 }
2580
2581 BOOL WINAPI
OpenPrinterA(LPSTR pPrinterName,LPHANDLE phPrinter,LPPRINTER_DEFAULTSA pDefault)2582 OpenPrinterA(LPSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSA pDefault)
2583 {
2584 BOOL bReturnValue = FALSE;
2585 DWORD cch;
2586 PWSTR pwszPrinterName = NULL;
2587 PRINTER_DEFAULTSW wDefault = { 0 };
2588
2589 TRACE("OpenPrinterA(%s, %p, %p)\n", pPrinterName, phPrinter, pDefault);
2590
2591 if (pPrinterName)
2592 {
2593 // Convert pPrinterName to a Unicode string pwszPrinterName
2594 cch = strlen(pPrinterName);
2595
2596 pwszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
2597 if (!pwszPrinterName)
2598 {
2599 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2600 ERR("HeapAlloc failed!\n");
2601 goto Cleanup;
2602 }
2603
2604 MultiByteToWideChar(CP_ACP, 0, pPrinterName, -1, pwszPrinterName, cch + 1);
2605 }
2606
2607 if (pDefault)
2608 {
2609 wDefault.DesiredAccess = pDefault->DesiredAccess;
2610
2611 if (pDefault->pDatatype)
2612 {
2613 // Convert pDefault->pDatatype to a Unicode string wDefault.pDatatype
2614 cch = strlen(pDefault->pDatatype);
2615
2616 wDefault.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
2617 if (!wDefault.pDatatype)
2618 {
2619 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2620 ERR("HeapAlloc failed!\n");
2621 goto Cleanup;
2622 }
2623
2624 MultiByteToWideChar(CP_ACP, 0, pDefault->pDatatype, -1, wDefault.pDatatype, cch + 1);
2625 }
2626
2627 if (pDefault->pDevMode)
2628 wDefault.pDevMode = GdiConvertToDevmodeW(pDefault->pDevMode);
2629 }
2630
2631 bReturnValue = OpenPrinterW(pwszPrinterName, phPrinter, &wDefault);
2632
2633 if ( bReturnValue )
2634 {
2635 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)*phPrinter;
2636 pHandle->bAnsi = TRUE;
2637 }
2638
2639 Cleanup:
2640 if (wDefault.pDatatype)
2641 HeapFree(hProcessHeap, 0, wDefault.pDatatype);
2642
2643 if (wDefault.pDevMode)
2644 HeapFree(hProcessHeap, 0, wDefault.pDevMode);
2645
2646 if (pwszPrinterName)
2647 HeapFree(hProcessHeap, 0, pwszPrinterName);
2648
2649 return bReturnValue;
2650 }
2651
2652 BOOL WINAPI
OpenPrinterW(LPWSTR pPrinterName,LPHANDLE phPrinter,LPPRINTER_DEFAULTSW pDefault)2653 OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault)
2654 {
2655 DWORD dwErrorCode;
2656 HANDLE hPrinter;
2657 PSPOOLER_HANDLE pHandle;
2658 PWSTR pDatatype = NULL;
2659 WINSPOOL_DEVMODE_CONTAINER DevModeContainer = { 0 };
2660 ACCESS_MASK AccessRequired = 0;
2661
2662 TRACE("OpenPrinterW(%S, %p, %p)\n", pPrinterName, phPrinter, pDefault);
2663
2664 // Sanity check
2665 if (!phPrinter)
2666 {
2667 dwErrorCode = ERROR_INVALID_PARAMETER;
2668 goto Cleanup;
2669 }
2670
2671 // Prepare the additional parameters in the format required by _RpcOpenPrinter
2672 if (pDefault)
2673 {
2674 pDatatype = pDefault->pDatatype;
2675 DevModeContainer.cbBuf = sizeof(DEVMODEW);
2676 DevModeContainer.pDevMode = (BYTE*)pDefault->pDevMode;
2677 AccessRequired = pDefault->DesiredAccess;
2678 }
2679
2680 // Do the RPC call
2681 RpcTryExcept
2682 {
2683 dwErrorCode = _RpcOpenPrinter(pPrinterName, &hPrinter, pDatatype, &DevModeContainer, AccessRequired);
2684 }
2685 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2686 {
2687 dwErrorCode = RpcExceptionCode();
2688 ERR("_RpcOpenPrinter failed with exception code %lu!\n", dwErrorCode);
2689 }
2690 RpcEndExcept;
2691
2692 if (dwErrorCode == ERROR_SUCCESS)
2693 {
2694 // Create a new SPOOLER_HANDLE structure.
2695 pHandle = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(SPOOLER_HANDLE));
2696 if (!pHandle)
2697 {
2698 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2699 ERR("HeapAlloc failed!\n");
2700 goto Cleanup;
2701 }
2702
2703 pHandle->Sig = SPOOLER_HANDLE_SIG;
2704 pHandle->hPrinter = hPrinter;
2705 pHandle->hSPLFile = INVALID_HANDLE_VALUE;
2706 pHandle->hSpoolFileHandle = INVALID_HANDLE_VALUE;
2707
2708 // Return it as phPrinter.
2709 *phPrinter = (HANDLE)pHandle;
2710 }
2711
2712 Cleanup:
2713 SetLastError(dwErrorCode);
2714 return (dwErrorCode == ERROR_SUCCESS);
2715 }
2716
2717 //
2718 // Dead API.
2719 //
2720 DWORD WINAPI
PrinterMessageBoxA(HANDLE hPrinter,DWORD Error,HWND hWnd,LPSTR pText,LPSTR pCaption,DWORD dwType)2721 PrinterMessageBoxA(HANDLE hPrinter, DWORD Error, HWND hWnd, LPSTR pText, LPSTR pCaption, DWORD dwType)
2722 {
2723 return 50;
2724 }
2725
2726 DWORD WINAPI
PrinterMessageBoxW(HANDLE hPrinter,DWORD Error,HWND hWnd,LPWSTR pText,LPWSTR pCaption,DWORD dwType)2727 PrinterMessageBoxW(HANDLE hPrinter, DWORD Error, HWND hWnd, LPWSTR pText, LPWSTR pCaption, DWORD dwType)
2728 {
2729 return 50;
2730 }
2731
2732 BOOL WINAPI
QueryColorProfile(HANDLE hPrinter,PDEVMODEW pdevmode,ULONG ulQueryMode,VOID * pvProfileData,ULONG * pcbProfileData,FLONG * pflProfileData)2733 QueryColorProfile(
2734 HANDLE hPrinter,
2735 PDEVMODEW pdevmode,
2736 ULONG ulQueryMode,
2737 VOID *pvProfileData,
2738 ULONG *pcbProfileData,
2739 FLONG *pflProfileData )
2740 {
2741 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
2742 BOOL Ret = FALSE;
2743 HMODULE hLibrary;
2744
2745 FIXME("QueryColorProfile(%p, %p, %l, %p, %p, %p)\n", hPrinter, pdevmode, ulQueryMode, pvProfileData, pcbProfileData, pflProfileData);
2746
2747 if ( pHandle->bNoColorProfile )
2748 {
2749 Ret = (BOOL)SP_ERROR;
2750 }
2751 else
2752 {
2753
2754 if ( pdevmode )
2755 {
2756 if (!IsValidDevmodeNoSizeW( pdevmode ) )
2757 {
2758 ERR("QueryColorProfile : Devode Invalid\n");
2759 return FALSE;
2760 }
2761 }
2762
2763 hLibrary = LoadPrinterDriver( hPrinter );
2764
2765 if ( hLibrary )
2766 {
2767 fpQueryColorProfile = (PVOID)GetProcAddress( hLibrary, "DrvQueryColorProfile" );
2768
2769 if ( fpQueryColorProfile )
2770 {
2771 Ret = fpQueryColorProfile( hPrinter, pdevmode, ulQueryMode, pvProfileData, pcbProfileData, pflProfileData );
2772 }
2773 else
2774 {
2775 pHandle->bNoColorProfile = TRUE;
2776 Ret = (BOOL)SP_ERROR;
2777 }
2778
2779 FreeLibrary(hLibrary);
2780 }
2781 }
2782 return Ret;
2783 }
2784
2785 // Note from GDI32:printdrv.c
2786 //
2787 // QuerySpoolMode :
2788 // BOOL return TRUE if successful.
2789 // dlFont 0x0001 for Downloading fonts. 0x0002 unknown XPS_PASS?.
2790 // dwVersion is version of EMFSPOOL. Must be 0x00010000. See [MS-EMFSPOOL] page 18.
2791 //
2792
2793 #define QSM_DOWNLOADINGFONTS 0x0001
2794
2795 /*
2796 Note from MSDN : "V4 print drivers using RAW mode to send PCL/Postscript have 0 byte spool file"
2797
2798 Use XPS_PASS instead of RAW to pass information directly to the print filter pipeline in
2799 v4 and v3 XPSDrv drivers. Here's how to proceed with Windows 8:
2800
2801 Call GetPrinterDriver to retrieve the DRIVER_INFO_8 structure.
2802 Check DRIVER_INFO_8::dwPrinterDriverAttributes for the PRINTER_DRIVER_XPS flag.
2803 Choose your datatype based on the presence or absence of the flag:
2804 If the flag is set, use XPS_PASS.
2805 If the flag isn't set, use RAW.
2806 */
2807
2808 #define QSM_XPS_PASS 0x0002 // Guessing. PRINTER_DRIVER_XPS?
2809
2810 BOOL WINAPI
QuerySpoolMode(HANDLE hPrinter,PDWORD downloadFontsFlags,PDWORD dwVersion)2811 QuerySpoolMode( HANDLE hPrinter, PDWORD downloadFontsFlags, PDWORD dwVersion )
2812 {
2813 PRINTER_INFO_2W *pi2 = NULL;
2814 DWORD needed = 0;
2815 BOOL res;
2816
2817 FIXME("QuerySpoolMode(%p, %p, %p)\n", hPrinter, downloadFontsFlags, dwVersion);
2818
2819 res = GetPrinterW( hPrinter, 2, NULL, 0, &needed);
2820 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
2821 {
2822 pi2 = HeapAlloc(hProcessHeap, 0, needed);
2823 if (!pi2)
2824 {
2825 ERR("Failed to allocate PRINTER_INFO_2W of %u bytes\n", needed);
2826 return FALSE;
2827 }
2828 res = GetPrinterW(hPrinter, 2, (LPBYTE)pi2, needed, &needed);
2829 }
2830
2831 if ( res )
2832 {
2833 *dwVersion = 0x10000;
2834 *downloadFontsFlags = 0;
2835
2836 if ( pi2->pServerName )
2837 {
2838 *downloadFontsFlags |= QSM_DOWNLOADINGFONTS;
2839 }
2840 }
2841 //
2842 // Guessing,,,
2843 // To do : Add GetPrinterDriver for DRIVER_INFO_8, test PRINTER_DRIVER_XPS flag,
2844 // to set *downloadFontsFlags |= QSM_XPS_PASS;
2845 //
2846 // Vista+ looks for QSM_XPS_PASS to be set in GDI32.
2847 //
2848 HeapFree(hProcessHeap, 0, pi2);
2849 return res;
2850 }
2851
2852 //
2853 // This requires IC support.
2854 //
2855 DWORD WINAPI
QueryRemoteFonts(HANDLE hPrinter,PUNIVERSAL_FONT_ID pufi,ULONG NumberOfUFIs)2856 QueryRemoteFonts( HANDLE hPrinter, PUNIVERSAL_FONT_ID pufi, ULONG NumberOfUFIs )
2857 {
2858 HANDLE hIC;
2859 DWORD Result = -1, cOut, cIn = 0;
2860 PBYTE pOut;
2861
2862 FIXME("QueryRemoteFonts(%p, %p, %lu)\n", hPrinter, pufi, NumberOfUFIs);
2863
2864 hIC = CreatePrinterIC( hPrinter, NULL );
2865 if ( hIC )
2866 {
2867 cOut = (NumberOfUFIs * sizeof(UNIVERSAL_FONT_ID)) + sizeof(DWORD); // Include "DWORD" first part to return size.
2868
2869 pOut = HeapAlloc( hProcessHeap, 0, cOut );
2870 if ( pOut )
2871 {
2872 if ( PlayGdiScriptOnPrinterIC( hIC, (LPBYTE)&cIn, sizeof(DWORD), pOut, cOut, 0 ) )
2873 {
2874 cIn = *((PDWORD)pOut); // Fisrt part is the size of the UFID object.
2875
2876 Result = cIn; // Return the required size.
2877
2878 if( NumberOfUFIs < cIn )
2879 {
2880 cIn = NumberOfUFIs;
2881 }
2882 // Copy whole object back to GDI32, exclude first DWORD part.
2883 memcpy( pufi, pOut + sizeof(DWORD), cIn * sizeof(UNIVERSAL_FONT_ID) );
2884 }
2885 HeapFree( hProcessHeap, 0, pOut );
2886 }
2887 DeletePrinterIC( hIC );
2888 }
2889 return Result;
2890 }
2891
2892 BOOL WINAPI
ReadPrinter(HANDLE hPrinter,PVOID pBuf,DWORD cbBuf,PDWORD pNoBytesRead)2893 ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead)
2894 {
2895 DWORD dwErrorCode;
2896 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
2897
2898 TRACE("ReadPrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pNoBytesRead);
2899
2900 // Sanity checks.
2901 if (!pHandle)
2902 {
2903 dwErrorCode = ERROR_INVALID_HANDLE;
2904 goto Cleanup;
2905 }
2906
2907 // Do the RPC call
2908 RpcTryExcept
2909 {
2910 dwErrorCode = _RpcReadPrinter(pHandle->hPrinter, pBuf, cbBuf, pNoBytesRead);
2911 }
2912 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2913 {
2914 dwErrorCode = RpcExceptionCode();
2915 ERR("_RpcReadPrinter failed with exception code %lu!\n", dwErrorCode);
2916 }
2917 RpcEndExcept;
2918
2919 Cleanup:
2920 SetLastError(dwErrorCode);
2921 return (dwErrorCode == ERROR_SUCCESS);
2922 }
2923
2924 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter,PPRINTER_DEFAULTSA pDefault)2925 ResetPrinterA(HANDLE hPrinter, PPRINTER_DEFAULTSA pDefault)
2926 {
2927 BOOL ret;
2928 UNICODE_STRING pNameW;
2929 PDEVMODEW pdmw = NULL;
2930 PPRINTER_DEFAULTSW pdw = (PPRINTER_DEFAULTSW)pDefault;
2931
2932 TRACE("ResetPrinterA(%p, %p)\n", hPrinter, pDefault);
2933
2934 if ( pDefault->pDatatype == (LPSTR)-1 )
2935 {
2936 pdw->pDatatype = (LPWSTR)-1;
2937 }
2938 else
2939 {
2940 pdw->pDatatype = AsciiToUnicode( &pNameW, pDefault->pDatatype );
2941 }
2942 if ( pDefault->pDevMode == (LPDEVMODEA)-1)
2943 {
2944 pdw->pDevMode = (LPDEVMODEW)-1;
2945 }
2946 else
2947 {
2948 if ( pDefault->pDevMode )//&& IsValidDevmodeNoSizeW( pDefault->pDevMode ) )
2949 {
2950 RosConvertAnsiDevModeToUnicodeDevmode( pDefault->pDevMode, &pdmw );
2951 pdw->pDevMode = pdmw;
2952 }
2953 }
2954
2955 ret = ResetPrinterW( hPrinter, pdw );
2956
2957 if (pdmw) HeapFree(hProcessHeap, 0, pdmw);
2958
2959 RtlFreeUnicodeString( &pNameW );
2960
2961 return ret;
2962 }
2963
2964 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter,PPRINTER_DEFAULTSW pDefault)2965 ResetPrinterW(HANDLE hPrinter, PPRINTER_DEFAULTSW pDefault)
2966 {
2967 TRACE("ResetPrinterW(%p, %p)\n", hPrinter, pDefault);
2968 UNIMPLEMENTED;
2969 return FALSE;
2970 }
2971
2972 BOOL WINAPI
SeekPrinter(HANDLE hPrinter,LARGE_INTEGER liDistanceToMove,PLARGE_INTEGER pliNewPointer,DWORD dwMoveMethod,BOOL bWrite)2973 SeekPrinter( HANDLE hPrinter, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER pliNewPointer, DWORD dwMoveMethod, BOOL bWrite )
2974 {
2975 DWORD dwErrorCode;
2976 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
2977
2978 FIXME("SeekPrinter(%p, %I64u, %p, %lu, %d)\n", hPrinter, liDistanceToMove.QuadPart, pliNewPointer, dwMoveMethod, bWrite);
2979
2980 // Sanity checks.
2981 if (!pHandle)
2982 {
2983 dwErrorCode = ERROR_INVALID_HANDLE;
2984 goto Cleanup;
2985 }
2986
2987 // Do the RPC call
2988 RpcTryExcept
2989 {
2990 dwErrorCode = _RpcSeekPrinter(pHandle->hPrinter, liDistanceToMove, pliNewPointer, dwMoveMethod, bWrite);
2991 }
2992 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2993 {
2994 dwErrorCode = RpcExceptionCode();
2995 ERR("_RpcSeekPrinter failed with exception code %lu!\n", dwErrorCode);
2996 }
2997 RpcEndExcept;
2998
2999 Cleanup:
3000 SetLastError(dwErrorCode);
3001 return (dwErrorCode == ERROR_SUCCESS);
3002 }
3003
3004 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter)3005 SetDefaultPrinterA(LPCSTR pszPrinter)
3006 {
3007 BOOL bReturnValue = FALSE;
3008 DWORD cch;
3009 PWSTR pwszPrinter = NULL;
3010
3011 TRACE("SetDefaultPrinterA(%s)\n", pszPrinter);
3012
3013 if (pszPrinter)
3014 {
3015 // Convert pszPrinter to a Unicode string pwszPrinter
3016 cch = strlen(pszPrinter);
3017
3018 pwszPrinter = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
3019 if (!pwszPrinter)
3020 {
3021 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3022 ERR("HeapAlloc failed!\n");
3023 goto Cleanup;
3024 }
3025
3026 MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, pwszPrinter, cch + 1);
3027 }
3028
3029 bReturnValue = SetDefaultPrinterW(pwszPrinter);
3030
3031 Cleanup:
3032 if (pwszPrinter)
3033 HeapFree(hProcessHeap, 0, pwszPrinter);
3034
3035 return bReturnValue;
3036 }
3037
3038 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter)3039 SetDefaultPrinterW(LPCWSTR pszPrinter)
3040 {
3041 const WCHAR wszDevicesKey[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Devices";
3042
3043 DWORD cbDeviceValueData;
3044 DWORD cbPrinterValueData = 0;
3045 DWORD cchPrinter;
3046 DWORD dwErrorCode;
3047 HKEY hDevicesKey = NULL;
3048 HKEY hWindowsKey = NULL;
3049 PWSTR pwszDeviceValueData = NULL;
3050 WCHAR wszPrinter[MAX_PRINTER_NAME + 1];
3051
3052 TRACE("SetDefaultPrinterW(%S)\n", pszPrinter);
3053
3054 // Open the Devices registry key.
3055 dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszDevicesKey, 0, KEY_READ, &hDevicesKey);
3056 if (dwErrorCode != ERROR_SUCCESS)
3057 {
3058 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
3059 goto Cleanup;
3060 }
3061
3062 // Did the caller give us a printer to set as default?
3063 if (pszPrinter && *pszPrinter)
3064 {
3065 // Check if the given printer exists and query the value data size.
3066 dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, NULL, &cbPrinterValueData);
3067 if (dwErrorCode == ERROR_FILE_NOT_FOUND)
3068 {
3069 dwErrorCode = ERROR_INVALID_PRINTER_NAME;
3070 goto Cleanup;
3071 }
3072 else if (dwErrorCode != ERROR_SUCCESS)
3073 {
3074 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
3075 goto Cleanup;
3076 }
3077
3078 cchPrinter = wcslen(pszPrinter);
3079 }
3080 else
3081 {
3082 // If there is already a default printer, we're done!
3083 cchPrinter = _countof(wszPrinter);
3084 if (GetDefaultPrinterW(wszPrinter, &cchPrinter))
3085 {
3086 dwErrorCode = ERROR_SUCCESS;
3087 goto Cleanup;
3088 }
3089
3090 // Otherwise, get us the first printer from the "Devices" key to later set it as default and query the value data size.
3091 cchPrinter = _countof(wszPrinter);
3092 dwErrorCode = (DWORD)RegEnumValueW(hDevicesKey, 0, wszPrinter, &cchPrinter, NULL, NULL, NULL, &cbPrinterValueData);
3093 if (dwErrorCode != ERROR_MORE_DATA)
3094 goto Cleanup;
3095
3096 pszPrinter = wszPrinter;
3097 }
3098
3099 // We now need to query the value data, which has the format "winspool,<Port>:"
3100 // and make "<Printer Name>,winspool,<Port>:" out of it.
3101 // Allocate a buffer large enough for the final data.
3102 cbDeviceValueData = (cchPrinter + 1) * sizeof(WCHAR) + cbPrinterValueData;
3103 pwszDeviceValueData = HeapAlloc(hProcessHeap, 0, cbDeviceValueData);
3104 if (!pwszDeviceValueData)
3105 {
3106 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
3107 ERR("HeapAlloc failed!\n");
3108 goto Cleanup;
3109 }
3110
3111 // Copy the Printer Name and a comma into it.
3112 CopyMemory(pwszDeviceValueData, pszPrinter, cchPrinter * sizeof(WCHAR));
3113 pwszDeviceValueData[cchPrinter] = L',';
3114
3115 // Append the value data, which has the format "winspool,<Port>:"
3116 dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, (PBYTE)&pwszDeviceValueData[cchPrinter + 1], &cbPrinterValueData);
3117 if (dwErrorCode != ERROR_SUCCESS)
3118 goto Cleanup;
3119
3120 // Open the Windows registry key.
3121 dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_SET_VALUE, &hWindowsKey);
3122 if (dwErrorCode != ERROR_SUCCESS)
3123 {
3124 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
3125 goto Cleanup;
3126 }
3127
3128 // Store our new default printer.
3129 dwErrorCode = (DWORD)RegSetValueExW(hWindowsKey, wszDeviceValue, 0, REG_SZ, (PBYTE)pwszDeviceValueData, cbDeviceValueData);
3130 if (dwErrorCode != ERROR_SUCCESS)
3131 {
3132 ERR("RegSetValueExW failed with status %lu!\n", dwErrorCode);
3133 goto Cleanup;
3134 }
3135
3136 Cleanup:
3137 if (hDevicesKey)
3138 RegCloseKey(hDevicesKey);
3139
3140 if (hWindowsKey)
3141 RegCloseKey(hWindowsKey);
3142
3143 if (pwszDeviceValueData)
3144 HeapFree(hProcessHeap, 0, pwszDeviceValueData);
3145
3146 SetLastError(dwErrorCode);
3147 return (dwErrorCode == ERROR_SUCCESS);
3148 }
3149
3150 BOOL WINAPI
SetPrinterA(HANDLE hPrinter,DWORD Level,PBYTE pPrinter,DWORD Command)3151 SetPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command)
3152 {
3153 BOOL Ret = FALSE;
3154 UNICODE_STRING usBuffer;
3155 PPRINTER_INFO_STRESS ppisa = (PPRINTER_INFO_STRESS)pPrinter;
3156 PPRINTER_INFO_STRESS ppisw = (PPRINTER_INFO_STRESS)pPrinter;
3157 PPRINTER_INFO_2A ppi2a = (PPRINTER_INFO_2A)pPrinter;
3158 PPRINTER_INFO_2W ppi2w = (PPRINTER_INFO_2W)pPrinter;
3159 PPRINTER_INFO_7A ppi7a = (PPRINTER_INFO_7A)pPrinter;
3160 PPRINTER_INFO_7W ppi7w = (PPRINTER_INFO_7W)pPrinter;
3161 PPRINTER_INFO_9A ppi9a = (PPRINTER_INFO_9A)pPrinter;
3162 PPRINTER_INFO_9W ppi9w = (PPRINTER_INFO_9W)pPrinter;
3163 PWSTR pwszPrinterName = NULL;
3164 PWSTR pwszServerName = NULL;
3165 PWSTR pwszShareName = NULL;
3166 PWSTR pwszPortName = NULL;
3167 PWSTR pwszDriverName = NULL;
3168 PWSTR pwszComment = NULL;
3169 PWSTR pwszLocation = NULL;
3170 PWSTR pwszSepFile = NULL;
3171 PWSTR pwszPrintProcessor = NULL;
3172 PWSTR pwszDatatype = NULL;
3173 PWSTR pwszParameters = NULL;
3174 PDEVMODEW pdmw = NULL;
3175
3176 FIXME("SetPrinterA(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command);
3177
3178 switch ( Level )
3179 {
3180 case 0:
3181 if ( Command == 0 )
3182 {
3183 if (ppisa->pPrinterName)
3184 {
3185 pwszPrinterName = AsciiToUnicode(&usBuffer, (LPCSTR)ppisa->pPrinterName);
3186 if (!(ppisw->pPrinterName = pwszPrinterName)) goto Cleanup;
3187 }
3188 if (ppisa->pServerName)
3189 {
3190 pwszServerName = AsciiToUnicode(&usBuffer, (LPCSTR)ppisa->pServerName);
3191 if (!(ppisw->pPrinterName = pwszServerName)) goto Cleanup;
3192 }
3193 }
3194 if ( Command == PRINTER_CONTROL_SET_STATUS )
3195 {
3196 // Set the pPrinter parameter to a pointer to a DWORD value that specifies the new printer status.
3197 PRINTER_INFO_6 pi6;
3198 pi6.dwStatus = (DWORD_PTR)pPrinter;
3199 pPrinter = (LPBYTE)&pi6;
3200 Level = 6;
3201 Command = 0;
3202 }
3203 break;
3204 case 2:
3205 {
3206 if (ppi2a->pShareName)
3207 {
3208 pwszShareName = AsciiToUnicode(&usBuffer, ppi2a->pShareName);
3209 if (!(ppi2w->pShareName = pwszShareName)) goto Cleanup;
3210 }
3211 if (ppi2a->pPortName)
3212 {
3213 pwszPortName = AsciiToUnicode(&usBuffer, ppi2a->pPortName);
3214 if (!(ppi2w->pPortName = pwszPortName)) goto Cleanup;
3215 }
3216 if (ppi2a->pDriverName)
3217 {
3218 pwszDriverName = AsciiToUnicode(&usBuffer, ppi2a->pDriverName);
3219 if (!(ppi2w->pDriverName = pwszDriverName)) goto Cleanup;
3220 }
3221 if (ppi2a->pComment)
3222 {
3223 pwszComment = AsciiToUnicode(&usBuffer, ppi2a->pComment);
3224 if (!(ppi2w->pComment = pwszComment)) goto Cleanup;
3225 }
3226 if (ppi2a->pLocation)
3227 {
3228 pwszLocation = AsciiToUnicode(&usBuffer, ppi2a->pLocation);
3229 if (!(ppi2w->pLocation = pwszLocation)) goto Cleanup;
3230 }
3231 if (ppi2a->pSepFile)
3232 {
3233 pwszSepFile = AsciiToUnicode(&usBuffer, ppi2a->pSepFile);
3234 if (!(ppi2w->pSepFile = pwszSepFile)) goto Cleanup;
3235 }
3236 if (ppi2a->pServerName)
3237 {
3238 pwszPrintProcessor = AsciiToUnicode(&usBuffer, ppi2a->pPrintProcessor);
3239 if (!(ppi2w->pPrintProcessor = pwszPrintProcessor)) goto Cleanup;
3240 }
3241 if (ppi2a->pDatatype)
3242 {
3243 pwszDatatype = AsciiToUnicode(&usBuffer, ppi2a->pDatatype);
3244 if (!(ppi2w->pDatatype = pwszDatatype)) goto Cleanup;
3245 }
3246 if (ppi2a->pParameters)
3247 {
3248 pwszParameters = AsciiToUnicode(&usBuffer, ppi2a->pParameters);
3249 if (!(ppi2w->pParameters = pwszParameters)) goto Cleanup;
3250 }
3251
3252 if ( ppi2a->pDevMode )
3253 {
3254 RosConvertAnsiDevModeToUnicodeDevmode( ppi2a->pDevMode, &pdmw );
3255 ppi2w->pDevMode = pdmw;
3256 }
3257 }
3258 //
3259 // These two strings are relitive and common to these three Levels.
3260 // Fall through...
3261 //
3262 case 4:
3263 case 5:
3264 {
3265 if (ppi2a->pServerName) // 4 & 5 : pPrinterName.
3266 {
3267 pwszServerName = AsciiToUnicode(&usBuffer, ppi2a->pServerName);
3268 if (!(ppi2w->pPrinterName = pwszServerName)) goto Cleanup;
3269 }
3270 if (ppi2a->pPrinterName) // 4 : pServerName, 5 : pPortName.
3271 {
3272 pwszPrinterName = AsciiToUnicode(&usBuffer, ppi2a->pPrinterName);
3273 if (!(ppi2w->pPrinterName = pwszPrinterName)) goto Cleanup;
3274 }
3275 }
3276 break;
3277 case 3:
3278 case 6:
3279 break;
3280 case 7:
3281 {
3282 if (ppi7a->pszObjectGUID)
3283 {
3284 pwszPrinterName = AsciiToUnicode(&usBuffer, ppi7a->pszObjectGUID);
3285 if (!(ppi7w->pszObjectGUID = pwszPrinterName)) goto Cleanup;
3286 }
3287 }
3288 break;
3289
3290 case 8:
3291 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
3292 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3293 /* fall through */
3294 case 9:
3295 {
3296 RosConvertAnsiDevModeToUnicodeDevmode( ppi9a->pDevMode, &pdmw );
3297 ppi9w->pDevMode = pdmw;
3298 }
3299 break;
3300
3301 default:
3302 FIXME( "Unsupported level %d\n", Level);
3303 SetLastError( ERROR_INVALID_LEVEL );
3304 }
3305
3306 Ret = SetPrinterW( hPrinter, Level, pPrinter, Command );
3307
3308 Cleanup:
3309 if (pdmw) HeapFree(hProcessHeap, 0, pdmw);
3310 if (pwszPrinterName) HeapFree(hProcessHeap, 0, pwszPrinterName);
3311 if (pwszServerName) HeapFree(hProcessHeap, 0, pwszServerName);
3312 if (pwszShareName) HeapFree(hProcessHeap, 0, pwszShareName);
3313 if (pwszPortName) HeapFree(hProcessHeap, 0, pwszPortName);
3314 if (pwszDriverName) HeapFree(hProcessHeap, 0, pwszDriverName);
3315 if (pwszComment) HeapFree(hProcessHeap, 0, pwszComment);
3316 if (pwszLocation) HeapFree(hProcessHeap, 0, pwszLocation);
3317 if (pwszSepFile) HeapFree(hProcessHeap, 0, pwszSepFile);
3318 if (pwszPrintProcessor) HeapFree(hProcessHeap, 0, pwszPrintProcessor);
3319 if (pwszDatatype) HeapFree(hProcessHeap, 0, pwszDatatype);
3320 if (pwszParameters) HeapFree(hProcessHeap, 0, pwszParameters);
3321 return Ret;
3322 }
3323
3324 BOOL WINAPI
SetPrinterW(HANDLE hPrinter,DWORD Level,PBYTE pPrinter,DWORD Command)3325 SetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command)
3326 {
3327 DWORD dwErrorCode;
3328 WINSPOOL_PRINTER_CONTAINER PrinterContainer;
3329 WINSPOOL_DEVMODE_CONTAINER DevModeContainer;
3330 WINSPOOL_SECURITY_CONTAINER SecurityContainer;
3331 SECURITY_DESCRIPTOR *sd = NULL;
3332 DWORD size;
3333 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
3334
3335 FIXME("SetPrinterW(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command);
3336
3337 // Sanity checks
3338 if (!pHandle)
3339 return ERROR_INVALID_HANDLE;
3340
3341 DevModeContainer.cbBuf = 0;
3342 DevModeContainer.pDevMode = NULL;
3343
3344 SecurityContainer.cbBuf = 0;
3345 SecurityContainer.pSecurity = NULL;
3346
3347 switch ( Level )
3348 {
3349 case 0:
3350 if ( Command == PRINTER_CONTROL_SET_STATUS )
3351 {
3352 // Set the pPrinter parameter to a pointer to a DWORD value that specifies the new printer status.
3353 PRINTER_INFO_6 pi6;
3354 pi6.dwStatus = (DWORD_PTR)pPrinter;
3355 pPrinter = (LPBYTE)&pi6;
3356 Level = 6;
3357 Command = 0;
3358 }
3359 break;
3360 case 2:
3361 {
3362 PPRINTER_INFO_2W pi2w = (PPRINTER_INFO_2W)pPrinter;
3363 if ( pi2w )
3364 {
3365 if ( pi2w->pDevMode )
3366 {
3367 if ( IsValidDevmodeNoSizeW( pi2w->pDevMode ) )
3368 {
3369 DevModeContainer.cbBuf = pi2w->pDevMode->dmSize + pi2w->pDevMode->dmDriverExtra;
3370 DevModeContainer.pDevMode = (PBYTE)pi2w->pDevMode;
3371 }
3372 }
3373
3374 if ( pi2w->pSecurityDescriptor )
3375 {
3376 sd = get_sd( pi2w->pSecurityDescriptor, &size );
3377 if ( sd )
3378 {
3379 SecurityContainer.cbBuf = size;
3380 SecurityContainer.pSecurity = (PBYTE)sd;
3381 }
3382 }
3383 }
3384 else
3385 {
3386 SetLastError(ERROR_INVALID_PARAMETER);
3387 return FALSE;
3388 }
3389 }
3390 break;
3391 case 3:
3392 {
3393 PPRINTER_INFO_3 pi3 = (PPRINTER_INFO_3)pPrinter;
3394 if ( pi3 )
3395 {
3396 if ( pi3->pSecurityDescriptor )
3397 {
3398 sd = get_sd( pi3->pSecurityDescriptor, &size );
3399 if ( sd )
3400 {
3401 SecurityContainer.cbBuf = size;
3402 SecurityContainer.pSecurity = (PBYTE)sd;
3403 }
3404 }
3405 }
3406 else
3407 {
3408 SetLastError(ERROR_INVALID_PARAMETER);
3409 return FALSE;
3410 }
3411 }
3412 break;
3413
3414 case 4:
3415 case 5:
3416 case 6:
3417 case 7:
3418 if ( pPrinter == NULL )
3419 {
3420 SetLastError(ERROR_INVALID_PARAMETER);
3421 return FALSE;
3422 }
3423 break;
3424
3425 case 8:
3426 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
3427 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3428 /* fall through */
3429 case 9:
3430 {
3431 PPRINTER_INFO_9W pi9w = (PPRINTER_INFO_9W)pPrinter;
3432 if ( pi9w )
3433 {
3434 if ( pi9w->pDevMode )
3435 {
3436 if ( IsValidDevmodeNoSizeW( pi9w->pDevMode ) )
3437 {
3438 DevModeContainer.cbBuf = pi9w->pDevMode->dmSize + pi9w->pDevMode->dmDriverExtra;
3439 DevModeContainer.pDevMode = (LPBYTE)pi9w->pDevMode;
3440 }
3441 }
3442 }
3443 }
3444 break;
3445
3446 default:
3447 FIXME( "Unsupported level %d\n", Level );
3448 SetLastError( ERROR_INVALID_LEVEL );
3449 return FALSE;
3450 }
3451
3452 PrinterContainer.PrinterInfo.pPrinterInfo1 = (WINSPOOL_PRINTER_INFO_1*)pPrinter;
3453 PrinterContainer.Level = Level;
3454
3455 // Do the RPC call
3456 RpcTryExcept
3457 {
3458 dwErrorCode = _RpcSetPrinter(pHandle->hPrinter, &PrinterContainer, &DevModeContainer, &SecurityContainer, Command);
3459 }
3460 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
3461 {
3462 dwErrorCode = RpcExceptionCode();
3463 }
3464 RpcEndExcept;
3465
3466 if ( sd ) HeapFree( GetProcessHeap(), 0, sd );
3467
3468 SetLastError(dwErrorCode);
3469 return (dwErrorCode == ERROR_SUCCESS);
3470 }
3471
3472 BOOL WINAPI
SplDriverUnloadComplete(LPWSTR pDriverFile)3473 SplDriverUnloadComplete(LPWSTR pDriverFile)
3474 {
3475 TRACE("DriverUnloadComplete(%S)\n", pDriverFile);
3476 UNIMPLEMENTED;
3477 return TRUE; // return true for now.
3478 }
3479 BOOL WINAPI
3480
SpoolerPrinterEvent(LPWSTR pPrinterName,INT DriverEvent,DWORD Flags,LPARAM lParam)3481 SpoolerPrinterEvent( LPWSTR pPrinterName, INT DriverEvent, DWORD Flags, LPARAM lParam )
3482 {
3483 HMODULE hLibrary;
3484 HANDLE hPrinter;
3485 BOOL Ret = FALSE;
3486
3487 if ( OpenPrinterW( pPrinterName, &hPrinter, NULL ) )
3488 {
3489 hLibrary = LoadPrinterDriver( hPrinter );
3490
3491 if ( hLibrary )
3492 {
3493 fpPrinterEvent = (PVOID)GetProcAddress( hLibrary, "DrvPrinterEvent" );
3494
3495 if ( fpPrinterEvent )
3496 {
3497 Ret = fpPrinterEvent( pPrinterName, DriverEvent, Flags, lParam );
3498 }
3499
3500 FreeLibrary(hLibrary);
3501 }
3502
3503 ClosePrinter( hPrinter );
3504 }
3505
3506 return Ret;
3507 }
3508
file_dlg_proc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)3509 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
3510 {
3511 LPWSTR filename;
3512
3513 switch(msg)
3514 {
3515 case WM_INITDIALOG:
3516 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
3517 return TRUE;
3518
3519 case WM_COMMAND:
3520 if(HIWORD(wparam) == BN_CLICKED)
3521 {
3522 if(LOWORD(wparam) == IDOK)
3523 {
3524 HANDLE hf;
3525 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
3526 LPWSTR *output;
3527
3528 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
3529 if (!filename)
3530 {
3531 ERR("Failed to allocate filename of %u bytes\n", (len + 1) * sizeof(WCHAR));
3532 return FALSE;
3533 }
3534 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
3535
3536 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
3537 {
3538 WCHAR caption[200], message[200];
3539 int mb_ret;
3540
3541 LoadStringW(hinstWinSpool, IDS_CAPTION, caption, ARRAYSIZE(caption));
3542 LoadStringW(hinstWinSpool, IDS_FILE_EXISTS, message, ARRAYSIZE(message));
3543 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
3544 if(mb_ret == IDCANCEL)
3545 {
3546 HeapFree(GetProcessHeap(), 0, filename);
3547 return TRUE;
3548 }
3549 }
3550 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3551 if(hf == INVALID_HANDLE_VALUE)
3552 {
3553 WCHAR caption[200], message[200];
3554
3555 LoadStringW(hinstWinSpool, IDS_CAPTION, caption, ARRAYSIZE(caption));
3556 LoadStringW(hinstWinSpool, IDS_CANNOT_OPEN, message, ARRAYSIZE(message));
3557 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
3558 HeapFree(GetProcessHeap(), 0, filename);
3559 return TRUE;
3560 }
3561 CloseHandle(hf);
3562 DeleteFileW(filename);
3563 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
3564 *output = filename;
3565 EndDialog(hwnd, IDOK);
3566 return TRUE;
3567 }
3568 if(LOWORD(wparam) == IDCANCEL)
3569 {
3570 EndDialog(hwnd, IDCANCEL);
3571 return TRUE;
3572 }
3573 }
3574 return FALSE;
3575 }
3576 return FALSE;
3577 }
3578
3579 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
3580
3581 LPWSTR WINAPI
StartDocDlgW(HANDLE hPrinter,DOCINFOW * doc)3582 StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
3583 {
3584 LPWSTR ret = NULL;
3585 DWORD len, attr, retDlg;
3586
3587 FIXME("StartDocDlgW(%p, %p)\n", hPrinter, doc);
3588
3589 if (doc->lpszOutput == NULL) /* Check whether default port is FILE: */
3590 {
3591 PRINTER_INFO_5W *pi5;
3592 GetPrinterW(hPrinter, 5, NULL, 0, &len);
3593 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3594 return NULL;
3595 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
3596 if (!pi5)
3597 {
3598 ERR("Failed to allocate PRINTER_INFO_5W of %u bytes\n", len);
3599 return NULL;
3600 }
3601
3602 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
3603 if (!pi5->pPortName || _wcsicmp(pi5->pPortName, FILE_Port))
3604 {
3605 HeapFree(GetProcessHeap(), 0, pi5);
3606 return NULL;
3607 }
3608 HeapFree(GetProcessHeap(), 0, pi5);
3609 }
3610
3611 if (doc->lpszOutput == NULL || !_wcsicmp(doc->lpszOutput, FILE_Port))
3612 {
3613 LPWSTR name;
3614
3615 retDlg = DialogBoxParamW( hinstWinSpool,
3616 MAKEINTRESOURCEW(FILENAME_DIALOG),
3617 GetForegroundWindow(),
3618 file_dlg_proc,
3619 (LPARAM)&name );
3620
3621 if ( retDlg == IDOK )
3622 {
3623 if (!(len = GetFullPathNameW(name, 0, NULL, NULL)))
3624 {
3625 HeapFree(GetProcessHeap(), 0, name);
3626 return NULL;
3627 }
3628 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3629 if (!ret)
3630 {
3631 ERR("Failed to allocate path name buffer of %u bytes\n", len * sizeof(WCHAR));
3632 HeapFree(GetProcessHeap(), 0, name);
3633 return NULL;
3634 }
3635 GetFullPathNameW(name, len, ret, NULL);
3636 HeapFree(GetProcessHeap(), 0, name);
3637 }
3638 else if ( retDlg == 0 ) // FALSE, some type of error occurred.
3639 {
3640 ret = (LPWSTR)SP_ERROR;
3641 }
3642 else if ( retDlg == IDCANCEL )
3643 {
3644 SetLastError( ERROR_CANCELLED );
3645 ret = (LPWSTR)SP_APPABORT;
3646 }
3647 return ret;
3648 }
3649
3650 if (!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
3651 return NULL;
3652
3653 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3654 if (!ret)
3655 {
3656 ERR("Failed to allocate path name buffer of %u bytes\n", len * sizeof(WCHAR));
3657 return NULL;
3658 }
3659 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
3660
3661 attr = GetFileAttributesW(ret);
3662 if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
3663 {
3664 HeapFree(GetProcessHeap(), 0, ret);
3665 ret = NULL;
3666 }
3667 return ret;
3668 }
3669
3670 LPSTR WINAPI
StartDocDlgA(HANDLE hPrinter,DOCINFOA * doc)3671 StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
3672 {
3673 UNICODE_STRING usBuffer;
3674 DOCINFOW docW = { 0 };
3675 LPWSTR retW;
3676 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
3677 LPSTR ret = NULL;
3678
3679 docW.cbSize = sizeof(docW);
3680 if (doc->lpszDocName)
3681 {
3682 docnameW = AsciiToUnicode(&usBuffer, doc->lpszDocName);
3683 if (!(docW.lpszDocName = docnameW)) goto failed;
3684 }
3685 if (doc->lpszOutput)
3686 {
3687 outputW = AsciiToUnicode(&usBuffer, doc->lpszOutput);
3688 if (!(docW.lpszOutput = outputW)) goto failed;
3689 }
3690 if (doc->lpszDatatype)
3691 {
3692 datatypeW = AsciiToUnicode(&usBuffer, doc->lpszDatatype);
3693 if (!(docW.lpszDatatype = datatypeW)) goto failed;
3694 }
3695 docW.fwType = doc->fwType;
3696
3697 retW = StartDocDlgW(hPrinter, &docW);
3698
3699 if (retW)
3700 {
3701 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
3702 ret = HeapAlloc(GetProcessHeap(), 0, len);
3703 if (ret)
3704 {
3705 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
3706 }
3707 else
3708 {
3709 ERR("Failed to allocate path name buffer of %u bytes\n", len);
3710 }
3711 HeapFree(GetProcessHeap(), 0, retW);
3712 }
3713
3714 failed:
3715 if (datatypeW) HeapFree(GetProcessHeap(), 0, datatypeW);
3716 if (outputW) HeapFree(GetProcessHeap(), 0, outputW);
3717 if (docnameW) HeapFree(GetProcessHeap(), 0, docnameW);
3718
3719 return ret;
3720 }
3721
3722 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter,DWORD Level,PBYTE pDocInfo)3723 StartDocPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
3724 {
3725 DOC_INFO_1W wDocInfo1 = { 0 };
3726 DWORD cch;
3727 DWORD dwErrorCode;
3728 DWORD dwReturnValue = 0;
3729 PDOC_INFO_1A pDocInfo1 = (PDOC_INFO_1A)pDocInfo;
3730
3731 TRACE("StartDocPrinterA(%p, %lu, %p)\n", hPrinter, Level, pDocInfo);
3732
3733 // Only check the minimum required for accessing pDocInfo.
3734 // Additional sanity checks are done in StartDocPrinterW.
3735 if (!pDocInfo1)
3736 {
3737 dwErrorCode = ERROR_INVALID_PARAMETER;
3738 goto Cleanup;
3739 }
3740
3741 if (Level != 1)
3742 {
3743 ERR("Level = %d, unsupported!\n", Level);
3744 dwErrorCode = ERROR_INVALID_LEVEL;
3745 goto Cleanup;
3746 }
3747
3748 if (pDocInfo1->pDatatype)
3749 {
3750 // Convert pDocInfo1->pDatatype to a Unicode string wDocInfo1.pDatatype
3751 cch = strlen(pDocInfo1->pDatatype);
3752
3753 wDocInfo1.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
3754 if (!wDocInfo1.pDatatype)
3755 {
3756 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
3757 ERR("HeapAlloc failed!\n");
3758 goto Cleanup;
3759 }
3760
3761 MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDatatype, -1, wDocInfo1.pDatatype, cch + 1);
3762 }
3763
3764 if (pDocInfo1->pDocName)
3765 {
3766 // Convert pDocInfo1->pDocName to a Unicode string wDocInfo1.pDocName
3767 cch = strlen(pDocInfo1->pDocName);
3768
3769 wDocInfo1.pDocName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
3770 if (!wDocInfo1.pDocName)
3771 {
3772 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
3773 ERR("HeapAlloc failed!\n");
3774 goto Cleanup;
3775 }
3776
3777 MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDocName, -1, wDocInfo1.pDocName, cch + 1);
3778 }
3779
3780 if (pDocInfo1->pOutputFile)
3781 {
3782 // Convert pDocInfo1->pOutputFile to a Unicode string wDocInfo1.pOutputFile
3783 cch = strlen(pDocInfo1->pOutputFile);
3784
3785 wDocInfo1.pOutputFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
3786 if (!wDocInfo1.pOutputFile)
3787 {
3788 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
3789 ERR("HeapAlloc failed!\n");
3790 goto Cleanup;
3791 }
3792
3793 MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pOutputFile, -1, wDocInfo1.pOutputFile, cch + 1);
3794 }
3795
3796 dwReturnValue = StartDocPrinterW(hPrinter, Level, (PBYTE)&wDocInfo1);
3797 dwErrorCode = GetLastError();
3798
3799 Cleanup:
3800 if (wDocInfo1.pDatatype)
3801 HeapFree(hProcessHeap, 0, wDocInfo1.pDatatype);
3802
3803 if (wDocInfo1.pDocName)
3804 HeapFree(hProcessHeap, 0, wDocInfo1.pDocName);
3805
3806 if (wDocInfo1.pOutputFile)
3807 HeapFree(hProcessHeap, 0, wDocInfo1.pOutputFile);
3808
3809 SetLastError(dwErrorCode);
3810 return dwReturnValue;
3811 }
3812
3813 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter,DWORD Level,PBYTE pDocInfo)3814 StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
3815 {
3816 DWORD cbAddJobInfo1;
3817 DWORD cbNeeded;
3818 DWORD dwErrorCode;
3819 DWORD dwReturnValue = 0;
3820 PADDJOB_INFO_1W pAddJobInfo1 = NULL;
3821 PDOC_INFO_1W pDocInfo1 = (PDOC_INFO_1W)pDocInfo;
3822 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
3823
3824 TRACE("StartDocPrinterW(%p, %lu, %p)\n", hPrinter, Level, pDocInfo);
3825
3826 // Sanity checks.
3827 if (!pHandle)
3828 {
3829 dwErrorCode = ERROR_INVALID_HANDLE;
3830 goto Cleanup;
3831 }
3832
3833 if (!pDocInfo1)
3834 {
3835 dwErrorCode = ERROR_INVALID_PARAMETER;
3836 goto Cleanup;
3837 }
3838
3839 if (Level != 1)
3840 {
3841 ERR("Level = %d, unsupported!\n", Level);
3842 dwErrorCode = ERROR_INVALID_LEVEL;
3843 goto Cleanup;
3844 }
3845
3846 if (pHandle->bStartedDoc)
3847 {
3848 dwErrorCode = ERROR_INVALID_PRINTER_STATE;
3849 goto Cleanup;
3850 }
3851
3852 // Check if we want to redirect output into a file.
3853 if (pDocInfo1->pOutputFile)
3854 {
3855 // Do a StartDocPrinter RPC call in this case.
3856 dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
3857 }
3858 else
3859 {
3860 // Allocate memory for the ADDJOB_INFO_1W structure and a path.
3861 cbAddJobInfo1 = sizeof(ADDJOB_INFO_1W) + MAX_PATH * sizeof(WCHAR);
3862 pAddJobInfo1 = HeapAlloc(hProcessHeap, 0, cbAddJobInfo1);
3863 if (!pAddJobInfo1)
3864 {
3865 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
3866 ERR("HeapAlloc failed!\n");
3867 goto Cleanup;
3868 }
3869
3870 // Try to add a new job.
3871 // This only succeeds if the printer is set to do spooled printing.
3872 if (AddJobW((HANDLE)pHandle, 1, (PBYTE)pAddJobInfo1, cbAddJobInfo1, &cbNeeded))
3873 {
3874 // Do spooled printing.
3875 dwErrorCode = _StartDocPrinterSpooled(pHandle, pDocInfo1, pAddJobInfo1);
3876 }
3877 else if (GetLastError() == ERROR_INVALID_ACCESS)
3878 {
3879 // ERROR_INVALID_ACCESS is returned when the printer is set to do direct printing.
3880 // In this case, we do a StartDocPrinter RPC call.
3881 dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
3882 }
3883 else
3884 {
3885 dwErrorCode = GetLastError();
3886 ERR("AddJobW failed with error %lu!\n", dwErrorCode);
3887 goto Cleanup;
3888 }
3889 }
3890
3891 if (dwErrorCode == ERROR_SUCCESS)
3892 {
3893 pHandle->bStartedDoc = TRUE;
3894 dwReturnValue = pHandle->dwJobID;
3895 if ( !pHandle->bTrayIcon )
3896 {
3897 UpdateTrayIcon( hPrinter, pHandle->dwJobID );
3898 }
3899 }
3900
3901 Cleanup:
3902 if (pAddJobInfo1)
3903 HeapFree(hProcessHeap, 0, pAddJobInfo1);
3904
3905 SetLastError(dwErrorCode);
3906 return dwReturnValue;
3907 }
3908
3909 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter)3910 StartPagePrinter(HANDLE hPrinter)
3911 {
3912 DWORD dwErrorCode;
3913 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
3914
3915 TRACE("StartPagePrinter(%p)\n", hPrinter);
3916
3917 // Sanity checks.
3918 if (!pHandle)
3919 {
3920 dwErrorCode = ERROR_INVALID_HANDLE;
3921 goto Cleanup;
3922 }
3923
3924 // Do the RPC call
3925 RpcTryExcept
3926 {
3927 dwErrorCode = _RpcStartPagePrinter(pHandle->hPrinter);
3928 }
3929 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
3930 {
3931 dwErrorCode = RpcExceptionCode();
3932 ERR("_RpcStartPagePrinter failed with exception code %lu!\n", dwErrorCode);
3933 }
3934 RpcEndExcept;
3935
3936 Cleanup:
3937 SetLastError(dwErrorCode);
3938 return (dwErrorCode == ERROR_SUCCESS);
3939 }
3940
3941 BOOL WINAPI
WritePrinter(HANDLE hPrinter,PVOID pBuf,DWORD cbBuf,PDWORD pcWritten)3942 WritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten)
3943 {
3944 DWORD dwErrorCode;
3945 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
3946
3947 TRACE("WritePrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
3948
3949 // Sanity checks.
3950 if (!pHandle)
3951 {
3952 dwErrorCode = ERROR_INVALID_HANDLE;
3953 goto Cleanup;
3954 }
3955
3956 if (!pHandle->bStartedDoc)
3957 {
3958 dwErrorCode = ERROR_SPL_NO_STARTDOC;
3959 goto Cleanup;
3960 }
3961
3962 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
3963 {
3964 // Write to the spool file. This doesn't need an RPC request.
3965 if (!WriteFile(pHandle->hSPLFile, pBuf, cbBuf, pcWritten, NULL))
3966 {
3967 dwErrorCode = GetLastError();
3968 ERR("WriteFile failed with error %lu!\n", dwErrorCode);
3969 goto Cleanup;
3970 }
3971
3972 dwErrorCode = ERROR_SUCCESS;
3973 }
3974 else
3975 {
3976 // TODO: This case (for direct printing or remote printing) has bad performance if multiple small-sized WritePrinter calls are performed.
3977 // We may increase performance by writing into a buffer and only doing a single RPC call when the buffer is full.
3978
3979 // Do the RPC call
3980 RpcTryExcept
3981 {
3982 dwErrorCode = _RpcWritePrinter(pHandle->hPrinter, pBuf, cbBuf, pcWritten);
3983 }
3984 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
3985 {
3986 dwErrorCode = RpcExceptionCode();
3987 ERR("_RpcWritePrinter failed with exception code %lu!\n", dwErrorCode);
3988 }
3989 RpcEndExcept;
3990 }
3991
3992 Cleanup:
3993 SetLastError(dwErrorCode);
3994 return (dwErrorCode == ERROR_SUCCESS);
3995 }
3996
3997 BOOL WINAPI
XcvDataW(HANDLE hXcv,PCWSTR pszDataName,PBYTE pInputData,DWORD cbInputData,PBYTE pOutputData,DWORD cbOutputData,PDWORD pcbOutputNeeded,PDWORD pdwStatus)3998 XcvDataW(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded, PDWORD pdwStatus)
3999 {
4000 DWORD dwErrorCode, Bogus = 0;
4001 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hXcv;
4002
4003 TRACE("XcvDataW(%p, %S, %p, %lu, %p, %lu, %p, %p)\n", hXcv, pszDataName, pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
4004
4005 if ( pcbOutputNeeded == NULL )
4006 {
4007 dwErrorCode = ERROR_INVALID_PARAMETER;
4008 goto Cleanup;
4009 }
4010
4011 // Sanity checks.
4012 if (!pHandle) // ( IntProtectHandle( hXcv, FALSE ) )
4013 {
4014 dwErrorCode = ERROR_INVALID_HANDLE;
4015 goto Cleanup;
4016 }
4017
4018 //
4019 // Do fixups.
4020 //
4021 if ( pInputData == NULL )
4022 {
4023 if ( !cbInputData )
4024 {
4025 pInputData = (PBYTE)&Bogus;
4026 }
4027 }
4028
4029 if ( pOutputData == NULL )
4030 {
4031 if ( !cbOutputData )
4032 {
4033 pOutputData = (PBYTE)&Bogus;
4034 }
4035 }
4036
4037 // Do the RPC call
4038 RpcTryExcept
4039 {
4040 dwErrorCode = _RpcXcvData( pHandle->hPrinter,
4041 pszDataName,
4042 pInputData,
4043 cbInputData,
4044 pOutputData,
4045 cbOutputData,
4046 pcbOutputNeeded,
4047 pdwStatus );
4048 }
4049 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
4050 {
4051 dwErrorCode = RpcExceptionCode();
4052 ERR("_RpcXcvData failed with exception code %lu!\n", dwErrorCode);
4053 }
4054 RpcEndExcept;
4055
4056 //IntUnprotectHandle( hXcv );
4057
4058 Cleanup:
4059 SetLastError(dwErrorCode);
4060 return (dwErrorCode == ERROR_SUCCESS);
4061 }
4062
4063 HANDLE
4064 WINAPI
CreatePrinterIC(_In_ HANDLE hPrinter,_In_opt_ LPDEVMODEW pDevMode)4065 CreatePrinterIC(
4066 _In_ HANDLE hPrinter,
4067 _In_opt_ LPDEVMODEW pDevMode)
4068 {
4069 UNIMPLEMENTED;
4070 return NULL;
4071 }
4072
4073 BOOL
4074 WINAPI
DeletePrinterIC(_In_ HANDLE hPrinterIC)4075 DeletePrinterIC(
4076 _In_ HANDLE hPrinterIC)
4077 {
4078 UNIMPLEMENTED;
4079 return FALSE;
4080 }
4081
4082 BOOL
4083 WINAPI
PlayGdiScriptOnPrinterIC(_In_ HANDLE hPrinterIC,_In_reads_bytes_ (cIn)LPBYTE pIn,_In_ DWORD cIn,_Out_writes_bytes_ (cOut)LPBYTE pOut,_In_ DWORD cOut,_In_ DWORD ul)4084 PlayGdiScriptOnPrinterIC(
4085 _In_ HANDLE hPrinterIC,
4086 _In_reads_bytes_(cIn) LPBYTE pIn,
4087 _In_ DWORD cIn,
4088 _Out_writes_bytes_(cOut) LPBYTE pOut,
4089 _In_ DWORD cOut,
4090 _In_ DWORD ul)
4091 {
4092 UNIMPLEMENTED;
4093 return FALSE;
4094 }
4095