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