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