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 // Local Constants
14 
15 /** And the award for the most confusingly named setting goes to "Device", for storing the default printer of the current user.
16     Ok, I admit that this has historical reasons. It's still not straightforward in any way though! */
17 static const WCHAR wszWindowsKey[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows";
18 static const WCHAR wszDeviceValue[] = L"Device";
19 
20 static DWORD
21 _StartDocPrinterSpooled(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1, PADDJOB_INFO_1W pAddJobInfo1)
22 {
23     DWORD cbNeeded;
24     DWORD dwErrorCode;
25     PJOB_INFO_1W pJobInfo1 = NULL;
26 
27     // Create the spool file.
28     pHandle->hSPLFile = CreateFileW(pAddJobInfo1->Path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
29     if (pHandle->hSPLFile == INVALID_HANDLE_VALUE)
30     {
31         dwErrorCode = GetLastError();
32         ERR("CreateFileW failed for \"%S\" with error %lu!\n", pAddJobInfo1->Path, dwErrorCode);
33         goto Cleanup;
34     }
35 
36     // Get the size of the job information.
37     GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, NULL, 0, &cbNeeded);
38     if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
39     {
40         dwErrorCode = GetLastError();
41         ERR("GetJobW failed with error %lu!\n", dwErrorCode);
42         goto Cleanup;
43     }
44 
45     // Allocate enough memory for the returned job information.
46     pJobInfo1 = HeapAlloc(hProcessHeap, 0, cbNeeded);
47     if (!pJobInfo1)
48     {
49         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
50         ERR("HeapAlloc failed!\n");
51         goto Cleanup;
52     }
53 
54     // Get the job information.
55     if (!GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, cbNeeded, &cbNeeded))
56     {
57         dwErrorCode = GetLastError();
58         ERR("GetJobW failed with error %lu!\n", dwErrorCode);
59         goto Cleanup;
60     }
61 
62     // Add our document information.
63     if (pDocInfo1->pDatatype)
64         pJobInfo1->pDatatype = pDocInfo1->pDatatype;
65 
66     pJobInfo1->pDocument = pDocInfo1->pDocName;
67 
68     // Set the new job information.
69     if (!SetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, 0))
70     {
71         dwErrorCode = GetLastError();
72         ERR("SetJobW failed with error %lu!\n", dwErrorCode);
73         goto Cleanup;
74     }
75 
76     // We were successful!
77     pHandle->dwJobID = pAddJobInfo1->JobId;
78     dwErrorCode = ERROR_SUCCESS;
79 
80 Cleanup:
81     if (pJobInfo1)
82         HeapFree(hProcessHeap, 0, pJobInfo1);
83 
84     return dwErrorCode;
85 }
86 
87 static DWORD
88 _StartDocPrinterWithRPC(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1)
89 {
90     DWORD dwErrorCode;
91     WINSPOOL_DOC_INFO_CONTAINER DocInfoContainer;
92 
93     DocInfoContainer.Level = 1;
94     DocInfoContainer.DocInfo.pDocInfo1 = (WINSPOOL_DOC_INFO_1*)pDocInfo1;
95 
96     RpcTryExcept
97     {
98         dwErrorCode = _RpcStartDocPrinter(pHandle->hPrinter, &DocInfoContainer, &pHandle->dwJobID);
99     }
100     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
101     {
102         dwErrorCode = RpcExceptionCode();
103         ERR("_RpcStartDocPrinter failed with exception code %lu!\n", dwErrorCode);
104     }
105     RpcEndExcept;
106 
107     return dwErrorCode;
108 }
109 
110 BOOL WINAPI
111 AbortPrinter(HANDLE hPrinter)
112 {
113     TRACE("AbortPrinter(%p)\n", hPrinter);
114     UNIMPLEMENTED;
115     return FALSE;
116 }
117 
118 HANDLE WINAPI
119 AddPrinterA(PSTR pName, DWORD Level, PBYTE pPrinter)
120 {
121     TRACE("AddPrinterA(%s, %lu, %p)\n", pName, Level, pPrinter);
122     UNIMPLEMENTED;
123     return NULL;
124 }
125 
126 HANDLE WINAPI
127 AddPrinterW(PWSTR pName, DWORD Level, PBYTE pPrinter)
128 {
129     TRACE("AddPrinterW(%S, %lu, %p)\n", pName, Level, pPrinter);
130     UNIMPLEMENTED;
131     return NULL;
132 }
133 
134 BOOL WINAPI
135 ClosePrinter(HANDLE hPrinter)
136 {
137     DWORD dwErrorCode;
138     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
139 
140     TRACE("ClosePrinter(%p)\n", hPrinter);
141 
142     // Sanity checks.
143     if (!pHandle)
144     {
145         dwErrorCode = ERROR_INVALID_HANDLE;
146         goto Cleanup;
147     }
148 
149     // Do the RPC call.
150     RpcTryExcept
151     {
152         dwErrorCode = _RpcClosePrinter(&pHandle->hPrinter);
153     }
154     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
155     {
156         dwErrorCode = RpcExceptionCode();
157         ERR("_RpcClosePrinter failed with exception code %lu!\n", dwErrorCode);
158     }
159     RpcEndExcept;
160 
161     // Close any open file handle.
162     if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
163         CloseHandle(pHandle->hSPLFile);
164 
165     // Free the memory for the handle.
166     HeapFree(hProcessHeap, 0, pHandle);
167 
168 Cleanup:
169     SetLastError(dwErrorCode);
170     return (dwErrorCode == ERROR_SUCCESS);
171 }
172 
173 BOOL WINAPI
174 DeletePrinter(HANDLE hPrinter)
175 {
176     TRACE("DeletePrinter(%p)\n", hPrinter);
177     UNIMPLEMENTED;
178     return FALSE;
179 }
180 
181 DWORD WINAPI
182 DeviceCapabilitiesA(LPCSTR pDevice, LPCSTR pPort, WORD fwCapability, LPSTR pOutput, const DEVMODEA* pDevMode)
183 {
184     TRACE("DeviceCapabilitiesA(%s, %s, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode);
185     UNIMPLEMENTED;
186     return 0;
187 }
188 
189 DWORD WINAPI
190 DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort, WORD fwCapability, LPWSTR pOutput, const DEVMODEW* pDevMode)
191 {
192     TRACE("DeviceCapabilitiesW(%S, %S, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode);
193     UNIMPLEMENTED;
194     return 0;
195 }
196 
197 INT WINAPI
198 DocumentEvent( HANDLE hPrinter, HDC hdc, int iEsc, ULONG cbIn, PVOID pvIn, ULONG cbOut, PVOID pvOut)
199 {
200     TRACE("DocumentEvent(%p, %p, %lu, %lu, %p, %lu, %p)\n", hPrinter, hdc, iEsc, cbIn, pvIn, cbOut, pvOut);
201     UNIMPLEMENTED;
202     return DOCUMENTEVENT_UNSUPPORTED;
203 }
204 
205 LONG WINAPI
206 DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput, DWORD fMode)
207 {
208     TRACE("DocumentPropertiesA(%p, %p, %s, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode);
209     UNIMPLEMENTED;
210     return -1;
211 }
212 
213 static PRINTER_INFO_9W * get_devmodeW(HANDLE hprn)
214 {
215     PRINTER_INFO_9W *pi9 = NULL;
216     DWORD needed = 0;
217     BOOL res;
218 
219     res = GetPrinterW(hprn, 9, NULL, 0, &needed);
220     if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
221     {
222         pi9 = HeapAlloc(hProcessHeap, 0, needed);
223         res = GetPrinterW(hprn, 9, (LPBYTE)pi9, needed, &needed);
224     }
225 
226     if (res)
227         return pi9;
228 
229     ERR("GetPrinterW failed with %u\n", GetLastError());
230     HeapFree(hProcessHeap, 0, pi9);
231     return NULL;
232 }
233 
234 LONG WINAPI
235 DocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput, DWORD fMode)
236 {
237     HANDLE hUseHandle = NULL;
238     PRINTER_INFO_9W *pi9 = NULL;
239     LONG Result = -1, Length;
240 
241     TRACE("DocumentPropertiesW(%p, %p, %S, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode);
242     if (hPrinter)
243     {
244         hUseHandle = hPrinter;
245     }
246     else if (!OpenPrinterW(pDeviceName, &hUseHandle, NULL))
247     {
248         ERR("No handle, and no usable printer name passed in\n");
249         return -1;
250     }
251 
252     pi9 = get_devmodeW(hUseHandle);
253 
254     if (pi9)
255     {
256         Length = pi9->pDevMode->dmSize + pi9->pDevMode->dmDriverExtra;
257         // See wineps.drv PSDRV_ExtDeviceMode
258         if (fMode)
259         {
260             Result = 1; /* IDOK */
261 
262             if (fMode & DM_IN_BUFFER)
263             {
264                 FIXME("Merge pDevModeInput with pi9, write back to driver!\n");
265                 // See wineps.drv PSDRV_MergeDevmodes
266             }
267 
268             if (fMode & DM_IN_PROMPT)
269             {
270                 FIXME("Show property sheet!\n");
271                 Result = 2; /* IDCANCEL */
272             }
273 
274             if (fMode & (DM_OUT_BUFFER | DM_OUT_DEFAULT))
275             {
276                 if (pDevModeOutput)
277                 {
278                     memcpy(pDevModeOutput, pi9->pDevMode, pi9->pDevMode->dmSize + pi9->pDevMode->dmDriverExtra);
279                 }
280                 else
281                 {
282                     ERR("No pDevModeOutput\n");
283                     Result = -1;
284                 }
285             }
286         }
287         else
288         {
289             Result = Length;
290         }
291 
292         HeapFree(hProcessHeap, 0, pi9);
293     }
294 
295     if (hUseHandle && !hPrinter)
296         ClosePrinter(hUseHandle);
297     return Result;
298 }
299 
300 BOOL WINAPI
301 EndDocPrinter(HANDLE hPrinter)
302 {
303     DWORD dwErrorCode;
304     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
305 
306     TRACE("EndDocPrinter(%p)\n", hPrinter);
307 
308     // Sanity checks.
309     if (!pHandle)
310     {
311         dwErrorCode = ERROR_INVALID_HANDLE;
312         goto Cleanup;
313     }
314 
315     if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
316     {
317         // For spooled jobs, the document is finished by calling _RpcScheduleJob.
318         RpcTryExcept
319         {
320             dwErrorCode = _RpcScheduleJob(pHandle->hPrinter, pHandle->dwJobID);
321         }
322         RpcExcept(EXCEPTION_EXECUTE_HANDLER)
323         {
324             dwErrorCode = RpcExceptionCode();
325             ERR("_RpcScheduleJob failed with exception code %lu!\n", dwErrorCode);
326         }
327         RpcEndExcept;
328 
329         // Close the spool file handle.
330         CloseHandle(pHandle->hSPLFile);
331     }
332     else
333     {
334         // In all other cases, just call _RpcEndDocPrinter.
335         RpcTryExcept
336         {
337             dwErrorCode = _RpcEndDocPrinter(pHandle->hPrinter);
338         }
339         RpcExcept(EXCEPTION_EXECUTE_HANDLER)
340         {
341             dwErrorCode = RpcExceptionCode();
342             ERR("_RpcEndDocPrinter failed with exception code %lu!\n", dwErrorCode);
343         }
344         RpcEndExcept;
345     }
346 
347     // A new document can now be started again.
348     pHandle->bStartedDoc = FALSE;
349 
350 Cleanup:
351     SetLastError(dwErrorCode);
352     return (dwErrorCode == ERROR_SUCCESS);
353 }
354 
355 BOOL WINAPI
356 EndPagePrinter(HANDLE hPrinter)
357 {
358     DWORD dwErrorCode;
359     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
360 
361     TRACE("EndPagePrinter(%p)\n", hPrinter);
362 
363     // Sanity checks.
364     if (!pHandle)
365     {
366         dwErrorCode = ERROR_INVALID_HANDLE;
367         goto Cleanup;
368     }
369 
370     if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
371     {
372         // For spooled jobs, we don't need to do anything.
373         dwErrorCode = ERROR_SUCCESS;
374     }
375     else
376     {
377         // In all other cases, just call _RpcEndPagePrinter.
378         RpcTryExcept
379         {
380             dwErrorCode = _RpcEndPagePrinter(pHandle->hPrinter);
381         }
382         RpcExcept(EXCEPTION_EXECUTE_HANDLER)
383         {
384             dwErrorCode = RpcExceptionCode();
385             ERR("_RpcEndPagePrinter failed with exception code %lu!\n", dwErrorCode);
386         }
387         RpcEndExcept;
388     }
389 
390 Cleanup:
391     SetLastError(dwErrorCode);
392     return (dwErrorCode == ERROR_SUCCESS);
393 }
394 
395 BOOL WINAPI
396 EnumPrintersA(DWORD Flags, PSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
397 {
398     BOOL bReturnValue = FALSE;
399     DWORD cch;
400     PWSTR pwszName = NULL;
401     PSTR pszPrinterName = NULL;
402     PSTR pszServerName = NULL;
403     PSTR pszDescription = NULL;
404     PSTR pszName = NULL;
405     PSTR pszComment = NULL;
406     PSTR pszShareName = NULL;
407     PSTR pszPortName = NULL;
408     PSTR pszDriverName = NULL;
409     PSTR pszLocation = NULL;
410     PSTR pszSepFile = NULL;
411     PSTR pszPrintProcessor = NULL;
412     PSTR pszDatatype = NULL;
413     PSTR pszParameters = NULL;
414     DWORD i;
415     PPRINTER_INFO_1W ppi1w = NULL;
416     PPRINTER_INFO_1A ppi1a = NULL;
417     PPRINTER_INFO_2W ppi2w = NULL;
418     PPRINTER_INFO_2A ppi2a = NULL;
419     PPRINTER_INFO_4W ppi4w = NULL;
420     PPRINTER_INFO_4A ppi4a = NULL;
421     PPRINTER_INFO_5W ppi5w = NULL;
422     PPRINTER_INFO_5A ppi5a = NULL;
423 
424     TRACE("EnumPrintersA(%lu, %s, %lu, %p, %lu, %p, %p)\n", Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
425 
426     // Check for invalid levels here for early error return. MSDN says that only 1, 2, 4, and 5 are allowable.
427     if (Level !=  1 && Level != 2 && Level != 4 && Level != 5)
428     {
429         SetLastError(ERROR_INVALID_LEVEL);
430         ERR("Invalid Level!\n");
431         goto Cleanup;
432     }
433 
434     if (Name)
435     {
436         // Convert pName to a Unicode string pwszName.
437         cch = strlen(Name);
438 
439         pwszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
440         if (!pwszName)
441         {
442             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
443             ERR("HeapAlloc failed!\n");
444             goto Cleanup;
445         }
446 
447         MultiByteToWideChar(CP_ACP, 0, Name, -1, pwszName, cch + 1);
448     }
449 
450     /* Ref: https://stackoverflow.com/questions/41147180/why-enumprintersa-and-enumprintersw-request-the-same-amount-of-memory */
451     bReturnValue = EnumPrintersW(Flags, pwszName, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
452     HeapFree(hProcessHeap, 0, pwszName);
453 
454     TRACE("*pcReturned is '%d' and bReturnValue is '%d' and GetLastError is '%ld'.\n", *pcReturned, bReturnValue, GetLastError());
455 
456     /* We are mapping multiple different pointers to the same pPrinterEnum pointer here so that */
457     /* we can do in-place conversion. We read the Unicode response from the EnumPrintersW and */
458     /* then we write back the ANSI conversion into the same buffer for our EnumPrintersA output */
459 
460     /* mapping to pPrinterEnum for Unicode (w) characters for Levels 1, 2, 4, and 5 */
461     ppi1w = (PPRINTER_INFO_1W)pPrinterEnum;
462     ppi2w = (PPRINTER_INFO_2W)pPrinterEnum;
463     ppi4w = (PPRINTER_INFO_4W)pPrinterEnum;
464     ppi5w = (PPRINTER_INFO_5W)pPrinterEnum;
465     /* mapping to pPrinterEnum for ANSI (a) characters for Levels 1, 2, 4, and 5 */
466     ppi1a = (PPRINTER_INFO_1A)pPrinterEnum;
467     ppi2a = (PPRINTER_INFO_2A)pPrinterEnum;
468     ppi4a = (PPRINTER_INFO_4A)pPrinterEnum;
469     ppi5a = (PPRINTER_INFO_5A)pPrinterEnum;
470 
471     for (i = 0; i < *pcReturned; i++)
472     {
473         switch (Level)
474         {
475             case 1:
476             {
477                 if (ppi1w[i].pDescription)
478                 {
479                     // Convert Unicode pDescription to a ANSI string pszDescription.
480                     cch = wcslen(ppi1w[i].pDescription);
481 
482                     pszDescription = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
483                     if (!pszDescription)
484                     {
485                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
486                         ERR("HeapAlloc failed!\n");
487                         goto Cleanup;
488                     }
489 
490                     WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pDescription, -1, pszDescription, cch + 1, NULL, NULL);
491                     StringCchCopyA(ppi1a[i].pDescription, cch + 1, pszDescription);
492 
493                     HeapFree(hProcessHeap, 0, pszDescription);
494                 }
495 
496                 if (ppi1w[i].pName)
497                 {
498                     // Convert Unicode pName to a ANSI string pszName.
499                     cch = wcslen(ppi1w[i].pName);
500 
501                     pszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
502                     if (!pszName)
503                     {
504                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
505                         ERR("HeapAlloc failed!\n");
506                         goto Cleanup;
507                     }
508 
509                     WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pName, -1, pszName, cch + 1, NULL, NULL);
510                     StringCchCopyA(ppi1a[i].pName, cch + 1, pszName);
511 
512                     HeapFree(hProcessHeap, 0, pszName);
513                 }
514 
515                 if (ppi1w[i].pComment)
516                 {
517                     // Convert Unicode pComment to a ANSI string pszComment.
518                     cch = wcslen(ppi1w[i].pComment);
519 
520                     pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
521                     if (!pszComment)
522                     {
523                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
524                         ERR("HeapAlloc failed!\n");
525                         goto Cleanup;
526                     }
527 
528                     WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pComment, -1, pszComment, cch + 1, NULL, NULL);
529                     StringCchCopyA(ppi1a[i].pComment, cch + 1, pszComment);
530 
531                     HeapFree(hProcessHeap, 0, pszComment);
532                 }
533                 break;
534             }
535 
536 
537             case 2:
538             {
539                 if (ppi2w[i].pServerName)
540                 {
541                     // Convert Unicode pServerName to a ANSI string pszServerName.
542                     cch = wcslen(ppi2w[i].pServerName);
543 
544                     pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
545                     if (!pszServerName)
546                     {
547                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
548                         ERR("HeapAlloc failed!\n");
549                         goto Cleanup;
550                     }
551 
552                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pServerName, -1, pszServerName, cch + 1, NULL, NULL);
553                     StringCchCopyA(ppi2a[i].pServerName, cch + 1, pszServerName);
554 
555                     HeapFree(hProcessHeap, 0, pszServerName);
556                 }
557 
558                 if (ppi2w[i].pPrinterName)
559                 {
560                     // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
561                     cch = wcslen(ppi2w[i].pPrinterName);
562 
563                     pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
564                     if (!pszPrinterName)
565                     {
566                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
567                         ERR("HeapAlloc failed!\n");
568                         goto Cleanup;
569                     }
570 
571                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
572                     StringCchCopyA(ppi2a[i].pPrinterName, cch + 1, pszPrinterName);
573 
574                     HeapFree(hProcessHeap, 0, pszPrinterName);
575                 }
576 
577                 if (ppi2w[i].pShareName)
578                 {
579                     // Convert Unicode pShareName to a ANSI string pszShareName.
580                     cch = wcslen(ppi2w[i].pShareName);
581 
582                     pszShareName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
583                     if (!pszShareName)
584                     {
585                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
586                         ERR("HeapAlloc failed!\n");
587                         goto Cleanup;
588                     }
589 
590                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pShareName, -1, pszShareName, cch + 1, NULL, NULL);
591                     StringCchCopyA(ppi2a[i].pShareName, cch + 1, pszShareName);
592 
593                     HeapFree(hProcessHeap, 0, pszShareName);
594                 }
595 
596                 if (ppi2w[i].pPortName)
597                 {
598                     // Convert Unicode pPortName to a ANSI string pszPortName.
599                     cch = wcslen(ppi2w[i].pPortName);
600 
601                     pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
602                     if (!pszPortName)
603                     {
604                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
605                         ERR("HeapAlloc failed!\n");
606                         goto Cleanup;
607                     }
608 
609                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPortName, -1, pszPortName, cch + 1, NULL, NULL);
610                     StringCchCopyA(ppi2a[i].pPortName, cch + 1, pszPortName);
611 
612                     HeapFree(hProcessHeap, 0, pszPortName);
613                 }
614 
615                 if (ppi2w[i].pDriverName)
616                 {
617                     // Convert Unicode pDriverName to a ANSI string pszDriverName.
618                     cch = wcslen(ppi2w[i].pDriverName);
619 
620                     pszDriverName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
621                     if (!pszDriverName)
622                     {
623                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
624                         ERR("HeapAlloc failed!\n");
625                         goto Cleanup;
626                     }
627 
628                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pDriverName, -1, pszDriverName, cch + 1, NULL, NULL);
629                     StringCchCopyA(ppi2a[i].pDriverName, cch + 1, pszDriverName);
630 
631                     HeapFree(hProcessHeap, 0, pszDriverName);
632                 }
633 
634                 if (ppi2w[i].pComment)
635                 {
636                     // Convert Unicode pComment to a ANSI string pszComment.
637                     cch = wcslen(ppi2w[i].pComment);
638 
639                     pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
640                     if (!pszComment)
641                     {
642                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
643                         ERR("HeapAlloc failed!\n");
644                         goto Cleanup;
645                     }
646 
647                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pComment, -1, pszComment, cch + 1, NULL, NULL);
648                     StringCchCopyA(ppi2a[i].pComment, cch + 1, pszComment);
649 
650                     HeapFree(hProcessHeap, 0, pszComment);
651                 }
652 
653                 if (ppi2w[i].pLocation)
654                 {
655                     // Convert Unicode pLocation to a ANSI string pszLocation.
656                     cch = wcslen(ppi2w[i].pLocation);
657 
658                     pszLocation = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
659                     if (!pszLocation)
660                     {
661                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
662                         ERR("HeapAlloc failed!\n");
663                         goto Cleanup;
664                     }
665 
666                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pLocation, -1, pszLocation, cch + 1, NULL, NULL);
667                     StringCchCopyA(ppi2a[i].pLocation, cch + 1, pszLocation);
668 
669                     HeapFree(hProcessHeap, 0, pszLocation);
670                 }
671 
672 
673                 if (ppi2w[i].pSepFile)
674                 {
675                     // Convert Unicode pSepFile to a ANSI string pszSepFile.
676                     cch = wcslen(ppi2w[i].pSepFile);
677 
678                     pszSepFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
679                     if (!pszSepFile)
680                     {
681                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
682                         ERR("HeapAlloc failed!\n");
683                         goto Cleanup;
684                     }
685 
686                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pSepFile, -1, pszSepFile, cch + 1, NULL, NULL);
687                     StringCchCopyA(ppi2a[i].pSepFile, cch + 1, pszSepFile);
688 
689                     HeapFree(hProcessHeap, 0, pszSepFile);
690                 }
691 
692                 if (ppi2w[i].pPrintProcessor)
693                 {
694                     // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor.
695                     cch = wcslen(ppi2w[i].pPrintProcessor);
696 
697                     pszPrintProcessor = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
698                     if (!pszPrintProcessor)
699                     {
700                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
701                         ERR("HeapAlloc failed!\n");
702                         goto Cleanup;
703                     }
704 
705                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPrintProcessor, -1, pszPrintProcessor, cch + 1, NULL, NULL);
706                     StringCchCopyA(ppi2a[i].pPrintProcessor, cch + 1, pszPrintProcessor);
707 
708                     HeapFree(hProcessHeap, 0, pszPrintProcessor);
709                 }
710 
711 
712                 if (ppi2w[i].pDatatype)
713                 {
714                     // Convert Unicode pDatatype to a ANSI string pszDatatype.
715                     cch = wcslen(ppi2w[i].pDatatype);
716 
717                     pszDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
718                     if (!pszDatatype)
719                     {
720                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
721                         ERR("HeapAlloc failed!\n");
722                         goto Cleanup;
723                     }
724 
725                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pDatatype, -1, pszDatatype, cch + 1, NULL, NULL);
726                     StringCchCopyA(ppi2a[i].pDatatype, cch + 1, pszDatatype);
727 
728                     HeapFree(hProcessHeap, 0, pszDatatype);
729                 }
730 
731                 if (ppi2w[i].pParameters)
732                 {
733                     // Convert Unicode pParameters to a ANSI string pszParameters.
734                     cch = wcslen(ppi2w[i].pParameters);
735 
736                     pszParameters = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
737                     if (!pszParameters)
738                     {
739                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
740                         ERR("HeapAlloc failed!\n");
741                         goto Cleanup;
742                     }
743 
744                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pParameters, -1, pszParameters, cch + 1, NULL, NULL);
745                     StringCchCopyA(ppi2a[i].pParameters, cch + 1, pszParameters);
746 
747                     HeapFree(hProcessHeap, 0, pszParameters);
748                 }
749                 break;
750 
751             }
752 
753             case 4:
754             {
755                 if (ppi4w[i].pPrinterName)
756                 {
757                     // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
758                     cch = wcslen(ppi4w[i].pPrinterName);
759 
760                     pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
761                     if (!pszPrinterName)
762                     {
763                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
764                         ERR("HeapAlloc failed!\n");
765                         goto Cleanup;
766                     }
767 
768                     WideCharToMultiByte(CP_ACP, 0, ppi4w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
769                     StringCchCopyA(ppi4a[i].pPrinterName, cch + 1, pszPrinterName);
770 
771                     HeapFree(hProcessHeap, 0, pszPrinterName);
772                 }
773 
774                 if (ppi4w[i].pServerName)
775                 {
776                     // Convert Unicode pServerName to a ANSI string pszServerName.
777                     cch = wcslen(ppi4w[i].pServerName);
778 
779                     pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
780                     if (!pszServerName)
781                     {
782                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
783                         ERR("HeapAlloc failed!\n");
784                         goto Cleanup;
785                     }
786 
787                     WideCharToMultiByte(CP_ACP, 0, ppi4w[i].pServerName, -1, pszServerName, cch + 1, NULL, NULL);
788                     StringCchCopyA(ppi4a[i].pServerName, cch + 1, pszServerName);
789 
790                     HeapFree(hProcessHeap, 0, pszServerName);
791                 }
792                 break;
793             }
794 
795             case 5:
796             {
797                 if (ppi5w[i].pPrinterName)
798                 {
799                     // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
800                     cch = wcslen(ppi5w[i].pPrinterName);
801 
802                     pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
803                     if (!pszPrinterName)
804                     {
805                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
806                         ERR("HeapAlloc failed!\n");
807                         goto Cleanup;
808                     }
809 
810                     WideCharToMultiByte(CP_ACP, 0, ppi5w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
811                     StringCchCopyA(ppi5a[i].pPrinterName, cch + 1, pszPrinterName);
812 
813                     HeapFree(hProcessHeap, 0, pszPrinterName);
814                 }
815 
816                 if (ppi5w[i].pPortName)
817                 {
818                     // Convert Unicode pPortName to a ANSI string pszPortName.
819                     cch = wcslen(ppi5w[i].pPortName);
820 
821                     pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
822                     if (!pszPortName)
823                     {
824                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
825                         ERR("HeapAlloc failed!\n");
826                         goto Cleanup;
827                     }
828 
829                     WideCharToMultiByte(CP_ACP, 0, ppi5w[i].pPortName, -1, pszPortName, cch + 1, NULL, NULL);
830                     StringCchCopyA(ppi5a[i].pPortName, cch + 1, pszPortName);
831 
832                     HeapFree(hProcessHeap, 0, pszPortName);
833                 }
834                 break;
835             }
836 
837         }   // switch
838     }       // for
839 
840 Cleanup:
841 
842     return bReturnValue;
843 }
844 
845 BOOL WINAPI
846 EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
847 {
848     DWORD dwErrorCode;
849 
850     TRACE("EnumPrintersW(%lu, %S, %lu, %p, %lu, %p, %p)\n", Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
851 
852     // Dismiss invalid levels already at this point.
853     if (Level == 3 || Level > 5)
854     {
855         dwErrorCode = ERROR_INVALID_LEVEL;
856         goto Cleanup;
857     }
858 
859     if (cbBuf && pPrinterEnum)
860         ZeroMemory(pPrinterEnum, cbBuf);
861 
862     // Do the RPC call
863     RpcTryExcept
864     {
865         dwErrorCode = _RpcEnumPrinters(Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
866     }
867     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
868     {
869         dwErrorCode = RpcExceptionCode();
870         ERR("_RpcEnumPrinters failed with exception code %lu!\n", dwErrorCode);
871     }
872     RpcEndExcept;
873 
874     if (dwErrorCode == ERROR_SUCCESS)
875     {
876         // Replace relative offset addresses in the output by absolute pointers.
877         ASSERT(Level <= 9);
878         MarshallUpStructuresArray(cbBuf, pPrinterEnum, *pcReturned, pPrinterInfoMarshalling[Level]->pInfo, pPrinterInfoMarshalling[Level]->cbStructureSize, TRUE);
879     }
880 
881 Cleanup:
882     SetLastError(dwErrorCode);
883     return (dwErrorCode == ERROR_SUCCESS);
884 }
885 
886 BOOL WINAPI
887 FlushPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten, DWORD cSleep)
888 {
889     TRACE("FlushPrinter(%p, %p, %lu, %p, %lu)\n", hPrinter, pBuf, cbBuf, pcWritten, cSleep);
890     UNIMPLEMENTED;
891     return FALSE;
892 }
893 
894 BOOL WINAPI
895 GetDefaultPrinterA(LPSTR pszBuffer, LPDWORD pcchBuffer)
896 {
897     DWORD dwErrorCode;
898     PWSTR pwszBuffer = NULL;
899 
900     TRACE("GetDefaultPrinterA(%p, %p)\n", pszBuffer, pcchBuffer);
901 
902     // Sanity check.
903     if (!pcchBuffer)
904     {
905         dwErrorCode = ERROR_INVALID_PARAMETER;
906         goto Cleanup;
907     }
908 
909     // Check if an ANSI buffer was given and if so, allocate a Unicode buffer of the same size.
910     if (pszBuffer && *pcchBuffer)
911     {
912         pwszBuffer = HeapAlloc(hProcessHeap, 0, *pcchBuffer * sizeof(WCHAR));
913         if (!pwszBuffer)
914         {
915             dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
916             ERR("HeapAlloc failed!\n");
917             goto Cleanup;
918         }
919     }
920 
921     if (!GetDefaultPrinterW(pwszBuffer, pcchBuffer))
922     {
923         dwErrorCode = GetLastError();
924         goto Cleanup;
925     }
926 
927     // We successfully got a string in pwszBuffer, so convert the Unicode string to ANSI.
928     WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, *pcchBuffer, NULL, NULL);
929 
930     dwErrorCode = ERROR_SUCCESS;
931 
932 Cleanup:
933     if (pwszBuffer)
934         HeapFree(hProcessHeap, 0, pwszBuffer);
935 
936     SetLastError(dwErrorCode);
937     return (dwErrorCode == ERROR_SUCCESS);
938 }
939 
940 BOOL WINAPI
941 GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer)
942 {
943     DWORD cbNeeded;
944     DWORD cchInputBuffer;
945     DWORD dwErrorCode;
946     HKEY hWindowsKey = NULL;
947     PWSTR pwszDevice = NULL;
948     PWSTR pwszComma;
949 
950     TRACE("GetDefaultPrinterW(%p, %p)\n", pszBuffer, pcchBuffer);
951 
952     // Sanity check.
953     if (!pcchBuffer)
954     {
955         dwErrorCode = ERROR_INVALID_PARAMETER;
956         goto Cleanup;
957     }
958 
959     cchInputBuffer = *pcchBuffer;
960 
961     // Open the registry key where the default printer for the current user is stored.
962     dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_READ, &hWindowsKey);
963     if (dwErrorCode != ERROR_SUCCESS)
964     {
965         ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
966         goto Cleanup;
967     }
968 
969     // Determine the size of the required buffer.
970     dwErrorCode = (DWORD)RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, NULL, &cbNeeded);
971     if (dwErrorCode != ERROR_SUCCESS)
972     {
973         ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
974         goto Cleanup;
975     }
976 
977     // Allocate it.
978     pwszDevice = HeapAlloc(hProcessHeap, 0, cbNeeded);
979     if (!pwszDevice)
980     {
981         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
982         ERR("HeapAlloc failed!\n");
983         goto Cleanup;
984     }
985 
986     // Now get the actual value.
987     dwErrorCode = RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, (PBYTE)pwszDevice, &cbNeeded);
988     if (dwErrorCode != ERROR_SUCCESS)
989     {
990         ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
991         goto Cleanup;
992     }
993 
994     // We get a string "<Printer Name>,winspool,<Port>:".
995     // Extract the printer name from it.
996     pwszComma = wcschr(pwszDevice, L',');
997     if (!pwszComma)
998     {
999         ERR("Found no or invalid default printer: %S!\n", pwszDevice);
1000         dwErrorCode = ERROR_INVALID_NAME;
1001         goto Cleanup;
1002     }
1003 
1004     // Store the length of the Printer Name (including the terminating NUL character!) in *pcchBuffer.
1005     *pcchBuffer = pwszComma - pwszDevice + 1;
1006 
1007     // Check if the supplied buffer is large enough.
1008     if (cchInputBuffer < *pcchBuffer)
1009     {
1010         dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
1011         goto Cleanup;
1012     }
1013 
1014     // Copy the default printer.
1015     *pwszComma = 0;
1016     CopyMemory(pszBuffer, pwszDevice, *pcchBuffer * sizeof(WCHAR));
1017 
1018     dwErrorCode = ERROR_SUCCESS;
1019 
1020 Cleanup:
1021     if (hWindowsKey)
1022         RegCloseKey(hWindowsKey);
1023 
1024     if (pwszDevice)
1025         HeapFree(hProcessHeap, 0, pwszDevice);
1026 
1027     SetLastError(dwErrorCode);
1028     return (dwErrorCode == ERROR_SUCCESS);
1029 }
1030 
1031 BOOL WINAPI
1032 GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
1033 {
1034     PPRINTER_INFO_1A ppi1a = (PPRINTER_INFO_1A)pPrinter;
1035     PPRINTER_INFO_1W ppi1w = (PPRINTER_INFO_1W)pPrinter;
1036     PPRINTER_INFO_2A ppi2a = (PPRINTER_INFO_2A)pPrinter;
1037     PPRINTER_INFO_2W ppi2w = (PPRINTER_INFO_2W)pPrinter;
1038     PPRINTER_INFO_4A ppi4a = (PPRINTER_INFO_4A)pPrinter;
1039     PPRINTER_INFO_4W ppi4w = (PPRINTER_INFO_4W)pPrinter;
1040     PPRINTER_INFO_5A ppi5a = (PPRINTER_INFO_5A)pPrinter;
1041     PPRINTER_INFO_5W ppi5w = (PPRINTER_INFO_5W)pPrinter;
1042     PPRINTER_INFO_7A ppi7a = (PPRINTER_INFO_7A)pPrinter;
1043     PPRINTER_INFO_7W ppi7w = (PPRINTER_INFO_7W)pPrinter;
1044     DWORD cch;
1045     BOOL bReturnValue = FALSE;
1046 
1047     TRACE("GetPrinterA(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
1048 
1049     // Check for invalid levels here for early error return. Should be 1-9.
1050     if (Level <  1 || Level > 9)
1051     {
1052         SetLastError(ERROR_INVALID_LEVEL);
1053         ERR("Invalid Level!\n");
1054         goto Cleanup;
1055     }
1056 
1057     bReturnValue = GetPrinterW(hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
1058 
1059     if (!bReturnValue)
1060     {
1061         TRACE("GetPrinterW failed!\n");
1062         goto Cleanup;
1063     }
1064 
1065     switch (Level)
1066     {
1067         case 1:
1068         {
1069             if (ppi1w->pDescription)
1070             {
1071                 PSTR pszDescription;
1072 
1073                 // Convert Unicode pDescription to a ANSI string pszDescription.
1074                 cch = wcslen(ppi1w->pDescription);
1075 
1076                 pszDescription = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1077                 if (!pszDescription)
1078                 {
1079                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1080                     ERR("HeapAlloc failed!\n");
1081                     goto Cleanup;
1082                 }
1083 
1084                 WideCharToMultiByte(CP_ACP, 0, ppi1w->pDescription, -1, pszDescription, cch + 1, NULL, NULL);
1085                 StringCchCopyA(ppi1a->pDescription, cch + 1, pszDescription);
1086 
1087                 HeapFree(hProcessHeap, 0, pszDescription);
1088             }
1089 
1090             if (ppi1w->pName)
1091             {
1092                 PSTR pszName;
1093 
1094                 // Convert Unicode pName to a ANSI string pszName.
1095                 cch = wcslen(ppi1w->pName);
1096 
1097                 pszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1098                 if (!pszName)
1099                 {
1100                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1101                     ERR("HeapAlloc failed!\n");
1102                     goto Cleanup;
1103                 }
1104 
1105                 WideCharToMultiByte(CP_ACP, 0, ppi1w->pName, -1, pszName, cch + 1, NULL, NULL);
1106                 StringCchCopyA(ppi1a->pName, cch + 1, pszName);
1107 
1108                 HeapFree(hProcessHeap, 0, pszName);
1109             }
1110 
1111             if (ppi1w->pComment)
1112             {
1113                 PSTR pszComment;
1114 
1115                 // Convert Unicode pComment to a ANSI string pszComment.
1116                 cch = wcslen(ppi1w->pComment);
1117 
1118                 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1119                 if (!pszComment)
1120                 {
1121                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1122                     ERR("HeapAlloc failed!\n");
1123                     goto Cleanup;
1124                 }
1125 
1126                 WideCharToMultiByte(CP_ACP, 0, ppi1w->pComment, -1, pszComment, cch + 1, NULL, NULL);
1127                 StringCchCopyA(ppi1a->pComment, cch + 1, pszComment);
1128 
1129                 HeapFree(hProcessHeap, 0, pszComment);
1130             }
1131             break;
1132         }
1133 
1134         case 2:
1135         {
1136             if (ppi2w->pServerName)
1137             {
1138                 PSTR pszServerName;
1139 
1140                 // Convert Unicode pServerName to a ANSI string pszServerName.
1141                 cch = wcslen(ppi2w->pServerName);
1142 
1143                 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1144                 if (!pszServerName)
1145                 {
1146                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1147                     ERR("HeapAlloc failed!\n");
1148                     goto Cleanup;
1149                 }
1150 
1151                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pServerName, -1, pszServerName, cch + 1, NULL, NULL);
1152                 StringCchCopyA(ppi2a->pServerName, cch + 1, pszServerName);
1153 
1154                 HeapFree(hProcessHeap, 0, pszServerName);
1155             }
1156 
1157             if (ppi2w->pPrinterName)
1158             {
1159                 PSTR pszPrinterName;
1160 
1161                 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
1162                 cch = wcslen(ppi2w->pPrinterName);
1163 
1164                 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1165                 if (!pszPrinterName)
1166                 {
1167                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1168                     ERR("HeapAlloc failed!\n");
1169                     goto Cleanup;
1170                 }
1171 
1172                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
1173                 StringCchCopyA(ppi2a->pPrinterName, cch + 1, pszPrinterName);
1174 
1175                 HeapFree(hProcessHeap, 0, pszPrinterName);
1176             }
1177 
1178             if (ppi2w->pShareName)
1179             {
1180                 PSTR pszShareName;
1181 
1182                 // Convert Unicode pShareName to a ANSI string pszShareName.
1183                 cch = wcslen(ppi2w->pShareName);
1184 
1185                 pszShareName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1186                 if (!pszShareName)
1187                 {
1188                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1189                     ERR("HeapAlloc failed!\n");
1190                     goto Cleanup;
1191                 }
1192 
1193                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pShareName, -1, pszShareName, cch + 1, NULL, NULL);
1194                 StringCchCopyA(ppi2a->pShareName, cch + 1, pszShareName);
1195 
1196                 HeapFree(hProcessHeap, 0, pszShareName);
1197             }
1198 
1199             if (ppi2w->pPortName)
1200             {
1201                 PSTR pszPortName;
1202 
1203                 // Convert Unicode pPortName to a ANSI string pszPortName.
1204                 cch = wcslen(ppi2w->pPortName);
1205 
1206                 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1207                 if (!pszPortName)
1208                 {
1209                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1210                     ERR("HeapAlloc failed!\n");
1211                     goto Cleanup;
1212                 }
1213 
1214                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pPortName, -1, pszPortName, cch + 1, NULL, NULL);
1215                 StringCchCopyA(ppi2a->pPortName, cch + 1, pszPortName);
1216 
1217                 HeapFree(hProcessHeap, 0, pszPortName);
1218             }
1219 
1220             if (ppi2w->pDriverName)
1221             {
1222                 PSTR pszDriverName;
1223 
1224                 // Convert Unicode pDriverName to a ANSI string pszDriverName.
1225                 cch = wcslen(ppi2w->pDriverName);
1226 
1227                 pszDriverName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1228                 if (!pszDriverName)
1229                 {
1230                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1231                     ERR("HeapAlloc failed!\n");
1232                     goto Cleanup;
1233                 }
1234 
1235                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pDriverName, -1, pszDriverName, cch + 1, NULL, NULL);
1236                 StringCchCopyA(ppi2a->pDriverName, cch + 1, pszDriverName);
1237 
1238                 HeapFree(hProcessHeap, 0, pszDriverName);
1239             }
1240 
1241             if (ppi2w->pComment)
1242             {
1243                 PSTR pszComment;
1244 
1245                 // Convert Unicode pComment to a ANSI string pszComment.
1246                 cch = wcslen(ppi2w->pComment);
1247 
1248                 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1249                 if (!pszComment)
1250                 {
1251                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1252                     ERR("HeapAlloc failed!\n");
1253                     goto Cleanup;
1254                 }
1255 
1256                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pComment, -1, pszComment, cch + 1, NULL, NULL);
1257                 StringCchCopyA(ppi2a->pComment, cch + 1, pszComment);
1258 
1259                 HeapFree(hProcessHeap, 0, pszComment);
1260             }
1261 
1262             if (ppi2w->pLocation)
1263             {
1264                 PSTR pszLocation;
1265 
1266                 // Convert Unicode pLocation to a ANSI string pszLocation.
1267                 cch = wcslen(ppi2w->pLocation);
1268 
1269                 pszLocation = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1270                 if (!pszLocation)
1271                 {
1272                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1273                     ERR("HeapAlloc failed!\n");
1274                     goto Cleanup;
1275                 }
1276 
1277                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pLocation, -1, pszLocation, cch + 1, NULL, NULL);
1278                 StringCchCopyA(ppi2a->pLocation, cch + 1, pszLocation);
1279 
1280                 HeapFree(hProcessHeap, 0, pszLocation);
1281             }
1282 
1283             if (ppi2w->pSepFile)
1284             {
1285                 PSTR pszSepFile;
1286 
1287                 // Convert Unicode pSepFile to a ANSI string pszSepFile.
1288                 cch = wcslen(ppi2w->pSepFile);
1289 
1290                 pszSepFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1291                 if (!pszSepFile)
1292                 {
1293                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1294                     ERR("HeapAlloc failed!\n");
1295                     goto Cleanup;
1296                 }
1297 
1298                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pSepFile, -1, pszSepFile, cch + 1, NULL, NULL);
1299                 StringCchCopyA(ppi2a->pSepFile, cch + 1, pszSepFile);
1300 
1301                 HeapFree(hProcessHeap, 0, pszSepFile);
1302             }
1303 
1304             if (ppi2w->pPrintProcessor)
1305             {
1306                 PSTR pszPrintProcessor;
1307 
1308                 // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor.
1309                 cch = wcslen(ppi2w->pPrintProcessor);
1310 
1311                 pszPrintProcessor = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1312                 if (!pszPrintProcessor)
1313                 {
1314                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1315                     ERR("HeapAlloc failed!\n");
1316                     goto Cleanup;
1317                 }
1318 
1319                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pPrintProcessor, -1, pszPrintProcessor, cch + 1, NULL, NULL);
1320                 StringCchCopyA(ppi2a->pPrintProcessor, cch + 1, pszPrintProcessor);
1321 
1322                 HeapFree(hProcessHeap, 0, pszPrintProcessor);
1323             }
1324 
1325             if (ppi2w->pDatatype)
1326             {
1327                 PSTR pszDatatype;
1328 
1329                 // Convert Unicode pDatatype to a ANSI string pszDatatype.
1330                 cch = wcslen(ppi2w->pDatatype);
1331 
1332                 pszDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1333                 if (!pszDatatype)
1334                 {
1335                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1336                     ERR("HeapAlloc failed!\n");
1337                     goto Cleanup;
1338                 }
1339 
1340                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pDatatype, -1, pszDatatype, cch + 1, NULL, NULL);
1341                 StringCchCopyA(ppi2a->pDatatype, cch + 1, pszDatatype);
1342 
1343                 HeapFree(hProcessHeap, 0, pszDatatype);
1344             }
1345 
1346             if (ppi2w->pParameters)
1347             {
1348                 PSTR pszParameters;
1349 
1350                 // Convert Unicode pParameters to a ANSI string pszParameters.
1351                 cch = wcslen(ppi2w->pParameters);
1352 
1353                 pszParameters = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1354                 if (!pszParameters)
1355                 {
1356                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1357                     ERR("HeapAlloc failed!\n");
1358                     goto Cleanup;
1359                 }
1360 
1361                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pParameters, -1, pszParameters, cch + 1, NULL, NULL);
1362                 StringCchCopyA(ppi2a->pParameters, cch + 1, pszParameters);
1363 
1364                 HeapFree(hProcessHeap, 0, pszParameters);
1365             }
1366             break;
1367         }
1368 
1369         case 4:
1370         {
1371             if (ppi4w->pPrinterName)
1372             {
1373                 PSTR pszPrinterName;
1374 
1375                 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
1376                 cch = wcslen(ppi4w->pPrinterName);
1377 
1378                 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1379                 if (!pszPrinterName)
1380                 {
1381                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1382                     ERR("HeapAlloc failed!\n");
1383                     goto Cleanup;
1384                 }
1385 
1386                 WideCharToMultiByte(CP_ACP, 0, ppi4w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
1387                 StringCchCopyA(ppi4a->pPrinterName, cch + 1, pszPrinterName);
1388 
1389                 HeapFree(hProcessHeap, 0, pszPrinterName);
1390             }
1391 
1392             if (ppi4w->pServerName)
1393             {
1394                 PSTR pszServerName;
1395 
1396                 // Convert Unicode pServerName to a ANSI string pszServerName.
1397                 cch = wcslen(ppi4w->pServerName);
1398 
1399                 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1400                 if (!pszServerName)
1401                 {
1402                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1403                     ERR("HeapAlloc failed!\n");
1404                     goto Cleanup;
1405                 }
1406 
1407                 WideCharToMultiByte(CP_ACP, 0, ppi4w->pServerName, -1, pszServerName, cch + 1, NULL, NULL);
1408                 StringCchCopyA(ppi4a->pServerName, cch + 1, pszServerName);
1409 
1410                 HeapFree(hProcessHeap, 0, pszServerName);
1411             }
1412             break;
1413         }
1414 
1415         case 5:
1416         {
1417             if (ppi5w->pPrinterName)
1418             {
1419                 PSTR pszPrinterName;
1420 
1421                 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
1422                 cch = wcslen(ppi5w->pPrinterName);
1423 
1424                 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1425                 if (!pszPrinterName)
1426                 {
1427                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1428                     ERR("HeapAlloc failed!\n");
1429                     goto Cleanup;
1430                 }
1431 
1432                 WideCharToMultiByte(CP_ACP, 0, ppi5w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
1433                 StringCchCopyA(ppi5a->pPrinterName, cch + 1, pszPrinterName);
1434 
1435                 HeapFree(hProcessHeap, 0, pszPrinterName);
1436             }
1437 
1438             if (ppi5w->pPortName)
1439             {
1440                 PSTR pszPortName;
1441 
1442                 // Convert Unicode pPortName to a ANSI string pszPortName.
1443                 cch = wcslen(ppi5w->pPortName);
1444 
1445                 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1446                 if (!pszPortName)
1447                 {
1448                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1449                     ERR("HeapAlloc failed!\n");
1450                     goto Cleanup;
1451                 }
1452 
1453                 WideCharToMultiByte(CP_ACP, 0, ppi5w->pPortName, -1, pszPortName, cch + 1, NULL, NULL);
1454                 StringCchCopyA(ppi5a->pPortName, cch + 1, pszPortName);
1455 
1456                 HeapFree(hProcessHeap, 0, pszPortName);
1457             }
1458             break;
1459         }
1460 
1461         case 7:
1462         {
1463             if (ppi7w->pszObjectGUID)
1464             {
1465                 PSTR pszaObjectGUID;
1466 
1467                 // Convert Unicode pszObjectGUID to a ANSI string pszaObjectGUID.
1468                 cch = wcslen(ppi7w->pszObjectGUID);
1469 
1470                 pszaObjectGUID = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1471                 if (!pszaObjectGUID)
1472                 {
1473                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1474                     ERR("HeapAlloc failed!\n");
1475                     goto Cleanup;
1476                 }
1477 
1478                 WideCharToMultiByte(CP_ACP, 0, ppi7w->pszObjectGUID, -1, pszaObjectGUID, cch + 1, NULL, NULL);
1479                 StringCchCopyA(ppi7a->pszObjectGUID, cch + 1, pszaObjectGUID);
1480 
1481                 HeapFree(hProcessHeap, 0, pszaObjectGUID);
1482             }
1483             break;
1484         }
1485     }       // switch
1486 
1487 Cleanup:
1488     return bReturnValue;
1489 }
1490 
1491 BOOL WINAPI
1492 GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
1493 {
1494     /*
1495      * We are mapping multiple different pointers to the same pDriverInfo pointer here so that
1496      * we can use the same incoming pointer for different Levels
1497      */
1498     PDRIVER_INFO_1W pdi1w = (PDRIVER_INFO_1W)pDriverInfo;
1499     PDRIVER_INFO_2W pdi2w = (PDRIVER_INFO_2W)pDriverInfo;
1500     PDRIVER_INFO_3W pdi3w = (PDRIVER_INFO_3W)pDriverInfo;
1501     PDRIVER_INFO_4W pdi4w = (PDRIVER_INFO_4W)pDriverInfo;
1502     PDRIVER_INFO_5W pdi5w = (PDRIVER_INFO_5W)pDriverInfo;
1503     PDRIVER_INFO_6W pdi6w = (PDRIVER_INFO_6W)pDriverInfo;
1504 
1505     BOOL bReturnValue = FALSE;
1506     DWORD cch;
1507     PWSTR pwszEnvironment = NULL;
1508 
1509     TRACE("GetPrinterDriverA(%p, %s, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
1510 
1511     // Check for invalid levels here for early error return. Should be 1-6.
1512     if (Level <  1 || Level > 6)
1513     {
1514         SetLastError(ERROR_INVALID_LEVEL);
1515         ERR("Invalid Level!\n");
1516         goto Exit;
1517     }
1518 
1519     if (pEnvironment)
1520     {
1521         // Convert pEnvironment to a Unicode string pwszEnvironment.
1522         cch = strlen(pEnvironment);
1523 
1524         pwszEnvironment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
1525         if (!pwszEnvironment)
1526         {
1527             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1528             ERR("HeapAlloc failed!\n");
1529             goto Exit;
1530         }
1531 
1532         MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, pwszEnvironment, cch + 1);
1533     }
1534 
1535     bReturnValue = GetPrinterDriverW(hPrinter, pwszEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
1536     TRACE("*pcbNeeded is '%d' and bReturnValue is '%d' and GetLastError is '%ld'.\n", *pcbNeeded, bReturnValue, GetLastError());
1537 
1538     if (pwszEnvironment)
1539     {
1540         HeapFree(hProcessHeap, 0, pwszEnvironment);
1541     }
1542 
1543     if (!bReturnValue)
1544     {
1545         TRACE("GetPrinterDriverW failed!\n");
1546         goto Exit;
1547     }
1548 
1549     // Do Unicode to ANSI conversions for strings based on Level
1550     switch (Level)
1551     {
1552         case 1:
1553         {
1554             if (!UnicodeToAnsiInPlace(pdi1w->pName))
1555                 goto Exit;
1556 
1557             break;
1558         }
1559 
1560         case 2:
1561         {
1562             if (!UnicodeToAnsiInPlace(pdi2w->pName))
1563                 goto Exit;
1564 
1565             if (!UnicodeToAnsiInPlace(pdi2w->pEnvironment))
1566                 goto Exit;
1567 
1568             if (!UnicodeToAnsiInPlace(pdi2w->pDriverPath))
1569                 goto Exit;
1570 
1571             if (!UnicodeToAnsiInPlace(pdi2w->pDataFile))
1572                 goto Exit;
1573 
1574             if (!UnicodeToAnsiInPlace(pdi2w->pConfigFile))
1575                 goto Exit;
1576 
1577             break;
1578         }
1579 
1580         case 3:
1581         {
1582             if (!UnicodeToAnsiInPlace(pdi3w->pName))
1583                 goto Exit;
1584 
1585             if (!UnicodeToAnsiInPlace(pdi3w->pEnvironment))
1586                 goto Exit;
1587 
1588             if (!UnicodeToAnsiInPlace(pdi3w->pDriverPath))
1589                 goto Exit;
1590 
1591             if (!UnicodeToAnsiInPlace(pdi3w->pDataFile))
1592                 goto Exit;
1593 
1594             if (!UnicodeToAnsiInPlace(pdi3w->pConfigFile))
1595                 goto Exit;
1596 
1597             if (!UnicodeToAnsiInPlace(pdi3w->pHelpFile))
1598                 goto Exit;
1599 
1600             if (!UnicodeToAnsiInPlace(pdi3w->pDependentFiles))
1601                 goto Exit;
1602 
1603             if (!UnicodeToAnsiInPlace(pdi3w->pMonitorName))
1604                 goto Exit;
1605 
1606             if (!UnicodeToAnsiInPlace(pdi3w->pDefaultDataType))
1607                 goto Exit;
1608 
1609             break;
1610         }
1611 
1612         case 4:
1613         {
1614             if (!UnicodeToAnsiInPlace(pdi4w->pName))
1615                 goto Exit;
1616 
1617             if (!UnicodeToAnsiInPlace(pdi4w->pEnvironment))
1618                 goto Exit;
1619 
1620             if (!UnicodeToAnsiInPlace(pdi4w->pDriverPath))
1621                 goto Exit;
1622 
1623             if (!UnicodeToAnsiInPlace(pdi4w->pDataFile))
1624                 goto Exit;
1625 
1626             if (!UnicodeToAnsiInPlace(pdi4w->pConfigFile))
1627                 goto Exit;
1628 
1629             if (!UnicodeToAnsiInPlace(pdi4w->pHelpFile))
1630                 goto Exit;
1631 
1632             if (!UnicodeToAnsiInPlace(pdi4w->pDependentFiles))
1633                 goto Exit;
1634 
1635             if (!UnicodeToAnsiInPlace(pdi4w->pMonitorName))
1636                 goto Exit;
1637 
1638             if (!UnicodeToAnsiInPlace(pdi4w->pDefaultDataType))
1639                 goto Exit;
1640 
1641             if (!UnicodeToAnsiInPlace(pdi4w->pszzPreviousNames))
1642                 goto Exit;
1643 
1644             break;
1645         }
1646 
1647         case 5:
1648         {
1649             if (!UnicodeToAnsiInPlace(pdi5w->pName))
1650                 goto Exit;
1651 
1652             if (!UnicodeToAnsiInPlace(pdi5w->pEnvironment))
1653                 goto Exit;
1654 
1655             if (!UnicodeToAnsiInPlace(pdi5w->pDriverPath))
1656                 goto Exit;
1657 
1658             if (!UnicodeToAnsiInPlace(pdi5w->pDataFile))
1659                 goto Exit;
1660 
1661             if (!UnicodeToAnsiInPlace(pdi5w->pConfigFile))
1662                 goto Exit;
1663 
1664             break;
1665         }
1666 
1667         case 6:
1668         {
1669             if (!UnicodeToAnsiInPlace(pdi6w->pName))
1670                 goto Exit;
1671 
1672             if (!UnicodeToAnsiInPlace(pdi6w->pEnvironment))
1673                 goto Exit;
1674 
1675             if (!UnicodeToAnsiInPlace(pdi6w->pDriverPath))
1676                 goto Exit;
1677 
1678             if (!UnicodeToAnsiInPlace(pdi6w->pDataFile))
1679                 goto Exit;
1680 
1681             if (!UnicodeToAnsiInPlace(pdi6w->pConfigFile))
1682                 goto Exit;
1683 
1684             if (!UnicodeToAnsiInPlace(pdi6w->pHelpFile))
1685                 goto Exit;
1686 
1687             if (!UnicodeToAnsiInPlace(pdi6w->pDependentFiles))
1688                 goto Exit;
1689 
1690             if (!UnicodeToAnsiInPlace(pdi6w->pMonitorName))
1691                 goto Exit;
1692 
1693             if (!UnicodeToAnsiInPlace(pdi6w->pDefaultDataType))
1694                 goto Exit;
1695 
1696             if (!UnicodeToAnsiInPlace(pdi6w->pszzPreviousNames))
1697                 goto Exit;
1698 
1699             if (!UnicodeToAnsiInPlace(pdi6w->pszMfgName))
1700                 goto Exit;
1701 
1702             if (!UnicodeToAnsiInPlace(pdi6w->pszOEMUrl))
1703                 goto Exit;
1704 
1705             if (!UnicodeToAnsiInPlace(pdi6w->pszHardwareID))
1706                 goto Exit;
1707 
1708             if (!UnicodeToAnsiInPlace(pdi6w->pszProvider))
1709                 goto Exit;
1710         }
1711     }
1712 
1713     bReturnValue = TRUE;
1714 
1715 Exit:
1716 
1717     return bReturnValue;
1718 }
1719 
1720 BOOL WINAPI
1721 GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
1722 {
1723     DWORD dwErrorCode;
1724     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
1725 
1726     TRACE("GetPrinterDriverW(%p, %S, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
1727 
1728     // Sanity checks.
1729     if (!pHandle)
1730     {
1731         dwErrorCode = ERROR_INVALID_HANDLE;
1732         goto Cleanup;
1733     }
1734 
1735     // Dismiss invalid levels already at this point.
1736     if (Level > 8 || Level < 1)
1737     {
1738         dwErrorCode = ERROR_INVALID_LEVEL;
1739         goto Cleanup;
1740     }
1741 
1742     if (cbBuf && pDriverInfo)
1743         ZeroMemory(pDriverInfo, cbBuf);
1744 
1745     // Do the RPC call
1746     RpcTryExcept
1747     {
1748         dwErrorCode = _RpcGetPrinterDriver(pHandle->hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
1749     }
1750     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1751     {
1752         dwErrorCode = RpcExceptionCode();
1753         ERR("_RpcGetPrinterDriver failed with exception code %lu!\n", dwErrorCode);
1754     }
1755     RpcEndExcept;
1756 
1757     if (dwErrorCode == ERROR_SUCCESS)
1758     {
1759         // Replace relative offset addresses in the output by absolute pointers.
1760         ASSERT(Level <= 5);
1761         MarshallUpStructure(cbBuf, pDriverInfo, pPrinterDriverMarshalling[Level]->pInfo, pPrinterDriverMarshalling[Level]->cbStructureSize, TRUE);
1762     }
1763 
1764 Cleanup:
1765     SetLastError(dwErrorCode);
1766     return (dwErrorCode == ERROR_SUCCESS);
1767 }
1768 
1769 BOOL WINAPI
1770 GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
1771 {
1772     DWORD dwErrorCode;
1773     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
1774 
1775     TRACE("GetPrinterW(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
1776 
1777     // Sanity checks.
1778     if (!pHandle)
1779     {
1780         dwErrorCode = ERROR_INVALID_HANDLE;
1781         goto Cleanup;
1782     }
1783 
1784     // Dismiss invalid levels already at this point.
1785     if (Level > 9)
1786     {
1787         dwErrorCode = ERROR_INVALID_LEVEL;
1788         goto Cleanup;
1789     }
1790 
1791     if (cbBuf && pPrinter)
1792         ZeroMemory(pPrinter, cbBuf);
1793 
1794     // Do the RPC call
1795     RpcTryExcept
1796     {
1797         dwErrorCode = _RpcGetPrinter(pHandle->hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
1798     }
1799     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1800     {
1801         dwErrorCode = RpcExceptionCode();
1802         ERR("_RpcGetPrinter failed with exception code %lu!\n", dwErrorCode);
1803     }
1804     RpcEndExcept;
1805 
1806     if (dwErrorCode == ERROR_SUCCESS)
1807     {
1808         // Replace relative offset addresses in the output by absolute pointers.
1809         ASSERT(Level <= 9);
1810         MarshallUpStructure(cbBuf, pPrinter, pPrinterInfoMarshalling[Level]->pInfo, pPrinterInfoMarshalling[Level]->cbStructureSize, TRUE);
1811     }
1812 
1813 Cleanup:
1814     SetLastError(dwErrorCode);
1815     return (dwErrorCode == ERROR_SUCCESS);
1816 }
1817 
1818 BOOL WINAPI
1819 OpenPrinterA(LPSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSA pDefault)
1820 {
1821     BOOL bReturnValue = FALSE;
1822     DWORD cch;
1823     PWSTR pwszPrinterName = NULL;
1824     PRINTER_DEFAULTSW wDefault = { 0 };
1825 
1826     TRACE("OpenPrinterA(%s, %p, %p)\n", pPrinterName, phPrinter, pDefault);
1827 
1828     if (pPrinterName)
1829     {
1830         // Convert pPrinterName to a Unicode string pwszPrinterName
1831         cch = strlen(pPrinterName);
1832 
1833         pwszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
1834         if (!pwszPrinterName)
1835         {
1836             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1837             ERR("HeapAlloc failed!\n");
1838             goto Cleanup;
1839         }
1840 
1841         MultiByteToWideChar(CP_ACP, 0, pPrinterName, -1, pwszPrinterName, cch + 1);
1842     }
1843 
1844     if (pDefault)
1845     {
1846         wDefault.DesiredAccess = pDefault->DesiredAccess;
1847 
1848         if (pDefault->pDatatype)
1849         {
1850             // Convert pDefault->pDatatype to a Unicode string wDefault.pDatatype
1851             cch = strlen(pDefault->pDatatype);
1852 
1853             wDefault.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
1854             if (!wDefault.pDatatype)
1855             {
1856                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1857                 ERR("HeapAlloc failed!\n");
1858                 goto Cleanup;
1859             }
1860 
1861             MultiByteToWideChar(CP_ACP, 0, pDefault->pDatatype, -1, wDefault.pDatatype, cch + 1);
1862         }
1863 
1864         if (pDefault->pDevMode)
1865             wDefault.pDevMode = GdiConvertToDevmodeW(pDefault->pDevMode);
1866     }
1867 
1868     bReturnValue = OpenPrinterW(pwszPrinterName, phPrinter, &wDefault);
1869 
1870 Cleanup:
1871     if (wDefault.pDatatype)
1872         HeapFree(hProcessHeap, 0, wDefault.pDatatype);
1873 
1874     if (wDefault.pDevMode)
1875         HeapFree(hProcessHeap, 0, wDefault.pDevMode);
1876 
1877     if (pwszPrinterName)
1878         HeapFree(hProcessHeap, 0, pwszPrinterName);
1879 
1880     return bReturnValue;
1881 }
1882 
1883 BOOL WINAPI
1884 OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault)
1885 {
1886     DWORD dwErrorCode;
1887     HANDLE hPrinter;
1888     PSPOOLER_HANDLE pHandle;
1889     PWSTR pDatatype = NULL;
1890     WINSPOOL_DEVMODE_CONTAINER DevModeContainer = { 0 };
1891     ACCESS_MASK AccessRequired = 0;
1892 
1893     TRACE("OpenPrinterW(%S, %p, %p)\n", pPrinterName, phPrinter, pDefault);
1894 
1895     // Sanity check
1896     if (!phPrinter)
1897     {
1898         dwErrorCode = ERROR_INVALID_PARAMETER;
1899         goto Cleanup;
1900     }
1901 
1902     // Prepare the additional parameters in the format required by _RpcOpenPrinter
1903     if (pDefault)
1904     {
1905         pDatatype = pDefault->pDatatype;
1906         DevModeContainer.cbBuf = sizeof(DEVMODEW);
1907         DevModeContainer.pDevMode = (BYTE*)pDefault->pDevMode;
1908         AccessRequired = pDefault->DesiredAccess;
1909     }
1910 
1911     // Do the RPC call
1912     RpcTryExcept
1913     {
1914         dwErrorCode = _RpcOpenPrinter(pPrinterName, &hPrinter, pDatatype, &DevModeContainer, AccessRequired);
1915     }
1916     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1917     {
1918         dwErrorCode = RpcExceptionCode();
1919         ERR("_RpcOpenPrinter failed with exception code %lu!\n", dwErrorCode);
1920     }
1921     RpcEndExcept;
1922 
1923     if (dwErrorCode == ERROR_SUCCESS)
1924     {
1925         // Create a new SPOOLER_HANDLE structure.
1926         pHandle = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(SPOOLER_HANDLE));
1927         if (!pHandle)
1928         {
1929             dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1930             ERR("HeapAlloc failed!\n");
1931             goto Cleanup;
1932         }
1933 
1934         pHandle->hPrinter = hPrinter;
1935         pHandle->hSPLFile = INVALID_HANDLE_VALUE;
1936 
1937         // Return it as phPrinter.
1938         *phPrinter = (HANDLE)pHandle;
1939     }
1940 
1941 Cleanup:
1942     SetLastError(dwErrorCode);
1943     return (dwErrorCode == ERROR_SUCCESS);
1944 }
1945 
1946 BOOL WINAPI
1947 ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead)
1948 {
1949     DWORD dwErrorCode;
1950     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
1951 
1952     TRACE("ReadPrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pNoBytesRead);
1953 
1954     // Sanity checks.
1955     if (!pHandle)
1956     {
1957         dwErrorCode = ERROR_INVALID_HANDLE;
1958         goto Cleanup;
1959     }
1960 
1961     // Do the RPC call
1962     RpcTryExcept
1963     {
1964         dwErrorCode = _RpcReadPrinter(pHandle->hPrinter, pBuf, cbBuf, pNoBytesRead);
1965     }
1966     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1967     {
1968         dwErrorCode = RpcExceptionCode();
1969         ERR("_RpcReadPrinter failed with exception code %lu!\n", dwErrorCode);
1970     }
1971     RpcEndExcept;
1972 
1973 Cleanup:
1974     SetLastError(dwErrorCode);
1975     return (dwErrorCode == ERROR_SUCCESS);
1976 }
1977 
1978 BOOL WINAPI
1979 ResetPrinterA(HANDLE hPrinter, PPRINTER_DEFAULTSA pDefault)
1980 {
1981     TRACE("ResetPrinterA(%p, %p)\n", hPrinter, pDefault);
1982     UNIMPLEMENTED;
1983     return FALSE;
1984 }
1985 
1986 BOOL WINAPI
1987 ResetPrinterW(HANDLE hPrinter, PPRINTER_DEFAULTSW pDefault)
1988 {
1989     TRACE("ResetPrinterW(%p, %p)\n", hPrinter, pDefault);
1990     UNIMPLEMENTED;
1991     return FALSE;
1992 }
1993 
1994 BOOL WINAPI
1995 SetDefaultPrinterA(LPCSTR pszPrinter)
1996 {
1997     BOOL bReturnValue = FALSE;
1998     DWORD cch;
1999     PWSTR pwszPrinter = NULL;
2000 
2001     TRACE("SetDefaultPrinterA(%s)\n", pszPrinter);
2002 
2003     if (pszPrinter)
2004     {
2005         // Convert pszPrinter to a Unicode string pwszPrinter
2006         cch = strlen(pszPrinter);
2007 
2008         pwszPrinter = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
2009         if (!pwszPrinter)
2010         {
2011             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2012             ERR("HeapAlloc failed!\n");
2013             goto Cleanup;
2014         }
2015 
2016         MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, pwszPrinter, cch + 1);
2017     }
2018 
2019     bReturnValue = SetDefaultPrinterW(pwszPrinter);
2020 
2021 Cleanup:
2022     if (pwszPrinter)
2023         HeapFree(hProcessHeap, 0, pwszPrinter);
2024 
2025     return bReturnValue;
2026 }
2027 
2028 BOOL WINAPI
2029 SetDefaultPrinterW(LPCWSTR pszPrinter)
2030 {
2031     const WCHAR wszDevicesKey[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Devices";
2032 
2033     DWORD cbDeviceValueData;
2034     DWORD cbPrinterValueData = 0;
2035     DWORD cchPrinter;
2036     DWORD dwErrorCode;
2037     HKEY hDevicesKey = NULL;
2038     HKEY hWindowsKey = NULL;
2039     PWSTR pwszDeviceValueData = NULL;
2040     WCHAR wszPrinter[MAX_PRINTER_NAME + 1];
2041 
2042     TRACE("SetDefaultPrinterW(%S)\n", pszPrinter);
2043 
2044     // Open the Devices registry key.
2045     dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszDevicesKey, 0, KEY_READ, &hDevicesKey);
2046     if (dwErrorCode != ERROR_SUCCESS)
2047     {
2048         ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
2049         goto Cleanup;
2050     }
2051 
2052     // Did the caller give us a printer to set as default?
2053     if (pszPrinter && *pszPrinter)
2054     {
2055         // Check if the given printer exists and query the value data size.
2056         dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, NULL, &cbPrinterValueData);
2057         if (dwErrorCode == ERROR_FILE_NOT_FOUND)
2058         {
2059             dwErrorCode = ERROR_INVALID_PRINTER_NAME;
2060             goto Cleanup;
2061         }
2062         else if (dwErrorCode != ERROR_SUCCESS)
2063         {
2064             ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
2065             goto Cleanup;
2066         }
2067 
2068         cchPrinter = wcslen(pszPrinter);
2069     }
2070     else
2071     {
2072         // If there is already a default printer, we're done!
2073         cchPrinter = _countof(wszPrinter);
2074         if (GetDefaultPrinterW(wszPrinter, &cchPrinter))
2075         {
2076             dwErrorCode = ERROR_SUCCESS;
2077             goto Cleanup;
2078         }
2079 
2080         // Otherwise, get us the first printer from the "Devices" key to later set it as default and query the value data size.
2081         cchPrinter = _countof(wszPrinter);
2082         dwErrorCode = (DWORD)RegEnumValueW(hDevicesKey, 0, wszPrinter, &cchPrinter, NULL, NULL, NULL, &cbPrinterValueData);
2083         if (dwErrorCode != ERROR_MORE_DATA)
2084             goto Cleanup;
2085 
2086         pszPrinter = wszPrinter;
2087     }
2088 
2089     // We now need to query the value data, which has the format "winspool,<Port>:"
2090     // and make "<Printer Name>,winspool,<Port>:" out of it.
2091     // Allocate a buffer large enough for the final data.
2092     cbDeviceValueData = (cchPrinter + 1) * sizeof(WCHAR) + cbPrinterValueData;
2093     pwszDeviceValueData = HeapAlloc(hProcessHeap, 0, cbDeviceValueData);
2094     if (!pwszDeviceValueData)
2095     {
2096         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2097         ERR("HeapAlloc failed!\n");
2098         goto Cleanup;
2099     }
2100 
2101     // Copy the Printer Name and a comma into it.
2102     CopyMemory(pwszDeviceValueData, pszPrinter, cchPrinter * sizeof(WCHAR));
2103     pwszDeviceValueData[cchPrinter] = L',';
2104 
2105     // Append the value data, which has the format "winspool,<Port>:"
2106     dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, (PBYTE)&pwszDeviceValueData[cchPrinter + 1], &cbPrinterValueData);
2107     if (dwErrorCode != ERROR_SUCCESS)
2108         goto Cleanup;
2109 
2110     // Open the Windows registry key.
2111     dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_SET_VALUE, &hWindowsKey);
2112     if (dwErrorCode != ERROR_SUCCESS)
2113     {
2114         ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
2115         goto Cleanup;
2116     }
2117 
2118     // Store our new default printer.
2119     dwErrorCode = (DWORD)RegSetValueExW(hWindowsKey, wszDeviceValue, 0, REG_SZ, (PBYTE)pwszDeviceValueData, cbDeviceValueData);
2120     if (dwErrorCode != ERROR_SUCCESS)
2121     {
2122         ERR("RegSetValueExW failed with status %lu!\n", dwErrorCode);
2123         goto Cleanup;
2124     }
2125 
2126 Cleanup:
2127     if (hDevicesKey)
2128         RegCloseKey(hDevicesKey);
2129 
2130     if (hWindowsKey)
2131         RegCloseKey(hWindowsKey);
2132 
2133     if (pwszDeviceValueData)
2134         HeapFree(hProcessHeap, 0, pwszDeviceValueData);
2135 
2136     SetLastError(dwErrorCode);
2137     return (dwErrorCode == ERROR_SUCCESS);
2138 }
2139 
2140 BOOL WINAPI
2141 SetPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command)
2142 {
2143     TRACE("SetPrinterA(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command);
2144     UNIMPLEMENTED;
2145     return FALSE;
2146 }
2147 
2148 BOOL WINAPI
2149 SetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command)
2150 {
2151     TRACE("SetPrinterW(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command);
2152     UNIMPLEMENTED;
2153     return FALSE;
2154 }
2155 
2156 BOOL WINAPI
2157 SplDriverUnloadComplete(LPWSTR pDriverFile)
2158 {
2159     TRACE("DriverUnloadComplete(%S)\n", pDriverFile);
2160     UNIMPLEMENTED;
2161     return TRUE; // return true for now.
2162 }
2163 
2164 DWORD WINAPI
2165 StartDocPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
2166 {
2167     DOC_INFO_1W wDocInfo1 = { 0 };
2168     DWORD cch;
2169     DWORD dwErrorCode;
2170     DWORD dwReturnValue = 0;
2171     PDOC_INFO_1A pDocInfo1 = (PDOC_INFO_1A)pDocInfo;
2172 
2173     TRACE("StartDocPrinterA(%p, %lu, %p)\n", hPrinter, Level, pDocInfo);
2174 
2175     // Only check the minimum required for accessing pDocInfo.
2176     // Additional sanity checks are done in StartDocPrinterW.
2177     if (!pDocInfo1)
2178     {
2179         dwErrorCode = ERROR_INVALID_PARAMETER;
2180         goto Cleanup;
2181     }
2182 
2183     if (Level != 1)
2184     {
2185         dwErrorCode = ERROR_INVALID_LEVEL;
2186         goto Cleanup;
2187     }
2188 
2189     if (pDocInfo1->pDatatype)
2190     {
2191         // Convert pDocInfo1->pDatatype to a Unicode string wDocInfo1.pDatatype
2192         cch = strlen(pDocInfo1->pDatatype);
2193 
2194         wDocInfo1.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
2195         if (!wDocInfo1.pDatatype)
2196         {
2197             dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2198             ERR("HeapAlloc failed!\n");
2199             goto Cleanup;
2200         }
2201 
2202         MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDatatype, -1, wDocInfo1.pDatatype, cch + 1);
2203     }
2204 
2205     if (pDocInfo1->pDocName)
2206     {
2207         // Convert pDocInfo1->pDocName to a Unicode string wDocInfo1.pDocName
2208         cch = strlen(pDocInfo1->pDocName);
2209 
2210         wDocInfo1.pDocName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
2211         if (!wDocInfo1.pDocName)
2212         {
2213             dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2214             ERR("HeapAlloc failed!\n");
2215             goto Cleanup;
2216         }
2217 
2218         MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDocName, -1, wDocInfo1.pDocName, cch + 1);
2219     }
2220 
2221     if (pDocInfo1->pOutputFile)
2222     {
2223         // Convert pDocInfo1->pOutputFile to a Unicode string wDocInfo1.pOutputFile
2224         cch = strlen(pDocInfo1->pOutputFile);
2225 
2226         wDocInfo1.pOutputFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
2227         if (!wDocInfo1.pOutputFile)
2228         {
2229             dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2230             ERR("HeapAlloc failed!\n");
2231             goto Cleanup;
2232         }
2233 
2234         MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pOutputFile, -1, wDocInfo1.pOutputFile, cch + 1);
2235     }
2236 
2237     dwReturnValue = StartDocPrinterW(hPrinter, Level, (PBYTE)&wDocInfo1);
2238     dwErrorCode = GetLastError();
2239 
2240 Cleanup:
2241     if (wDocInfo1.pDatatype)
2242         HeapFree(hProcessHeap, 0, wDocInfo1.pDatatype);
2243 
2244     if (wDocInfo1.pDocName)
2245         HeapFree(hProcessHeap, 0, wDocInfo1.pDocName);
2246 
2247     if (wDocInfo1.pOutputFile)
2248         HeapFree(hProcessHeap, 0, wDocInfo1.pOutputFile);
2249 
2250     SetLastError(dwErrorCode);
2251     return dwReturnValue;
2252 }
2253 
2254 DWORD WINAPI
2255 StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
2256 {
2257     DWORD cbAddJobInfo1;
2258     DWORD cbNeeded;
2259     DWORD dwErrorCode;
2260     DWORD dwReturnValue = 0;
2261     PADDJOB_INFO_1W pAddJobInfo1 = NULL;
2262     PDOC_INFO_1W pDocInfo1 = (PDOC_INFO_1W)pDocInfo;
2263     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
2264 
2265     TRACE("StartDocPrinterW(%p, %lu, %p)\n", hPrinter, Level, pDocInfo);
2266 
2267     // Sanity checks.
2268     if (!pHandle)
2269     {
2270         dwErrorCode = ERROR_INVALID_HANDLE;
2271         goto Cleanup;
2272     }
2273 
2274     if (!pDocInfo1)
2275     {
2276         dwErrorCode = ERROR_INVALID_PARAMETER;
2277         goto Cleanup;
2278     }
2279 
2280     if (Level != 1)
2281     {
2282         dwErrorCode = ERROR_INVALID_LEVEL;
2283         goto Cleanup;
2284     }
2285 
2286     if (pHandle->bStartedDoc)
2287     {
2288         dwErrorCode = ERROR_INVALID_PRINTER_STATE;
2289         goto Cleanup;
2290     }
2291 
2292     // Check if we want to redirect output into a file.
2293     if (pDocInfo1->pOutputFile)
2294     {
2295         // Do a StartDocPrinter RPC call in this case.
2296         dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
2297     }
2298     else
2299     {
2300         // Allocate memory for the ADDJOB_INFO_1W structure and a path.
2301         cbAddJobInfo1 = sizeof(ADDJOB_INFO_1W) + MAX_PATH * sizeof(WCHAR);
2302         pAddJobInfo1 = HeapAlloc(hProcessHeap, 0, cbAddJobInfo1);
2303         if (!pAddJobInfo1)
2304         {
2305             dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2306             ERR("HeapAlloc failed!\n");
2307             goto Cleanup;
2308         }
2309 
2310         // Try to add a new job.
2311         // This only succeeds if the printer is set to do spooled printing.
2312         if (AddJobW((HANDLE)pHandle, 1, (PBYTE)pAddJobInfo1, cbAddJobInfo1, &cbNeeded))
2313         {
2314             // Do spooled printing.
2315             dwErrorCode = _StartDocPrinterSpooled(pHandle, pDocInfo1, pAddJobInfo1);
2316         }
2317         else if (GetLastError() == ERROR_INVALID_ACCESS)
2318         {
2319             // ERROR_INVALID_ACCESS is returned when the printer is set to do direct printing.
2320             // In this case, we do a StartDocPrinter RPC call.
2321             dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
2322         }
2323         else
2324         {
2325             dwErrorCode = GetLastError();
2326             ERR("AddJobW failed with error %lu!\n", dwErrorCode);
2327             goto Cleanup;
2328         }
2329     }
2330 
2331     if (dwErrorCode == ERROR_SUCCESS)
2332     {
2333         pHandle->bStartedDoc = TRUE;
2334         dwReturnValue = pHandle->dwJobID;
2335     }
2336 
2337 Cleanup:
2338     if (pAddJobInfo1)
2339         HeapFree(hProcessHeap, 0, pAddJobInfo1);
2340 
2341     SetLastError(dwErrorCode);
2342     return dwReturnValue;
2343 }
2344 
2345 BOOL WINAPI
2346 StartPagePrinter(HANDLE hPrinter)
2347 {
2348     DWORD dwErrorCode;
2349     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
2350 
2351     TRACE("StartPagePrinter(%p)\n", hPrinter);
2352 
2353     // Sanity checks.
2354     if (!pHandle)
2355     {
2356         dwErrorCode = ERROR_INVALID_HANDLE;
2357         goto Cleanup;
2358     }
2359 
2360     // Do the RPC call
2361     RpcTryExcept
2362     {
2363         dwErrorCode = _RpcStartPagePrinter(pHandle->hPrinter);
2364     }
2365     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2366     {
2367         dwErrorCode = RpcExceptionCode();
2368         ERR("_RpcStartPagePrinter failed with exception code %lu!\n", dwErrorCode);
2369     }
2370     RpcEndExcept;
2371 
2372 Cleanup:
2373     SetLastError(dwErrorCode);
2374     return (dwErrorCode == ERROR_SUCCESS);
2375 }
2376 
2377 BOOL WINAPI
2378 WritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten)
2379 {
2380     DWORD dwErrorCode;
2381     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
2382 
2383     TRACE("WritePrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2384 
2385     // Sanity checks.
2386     if (!pHandle)
2387     {
2388         dwErrorCode = ERROR_INVALID_HANDLE;
2389         goto Cleanup;
2390     }
2391 
2392     if (!pHandle->bStartedDoc)
2393     {
2394         dwErrorCode = ERROR_SPL_NO_STARTDOC;
2395         goto Cleanup;
2396     }
2397 
2398     if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
2399     {
2400         // Write to the spool file. This doesn't need an RPC request.
2401         if (!WriteFile(pHandle->hSPLFile, pBuf, cbBuf, pcWritten, NULL))
2402         {
2403             dwErrorCode = GetLastError();
2404             ERR("WriteFile failed with error %lu!\n", dwErrorCode);
2405             goto Cleanup;
2406         }
2407 
2408         dwErrorCode = ERROR_SUCCESS;
2409     }
2410     else
2411     {
2412         // TODO: This case (for direct printing or remote printing) has bad performance if multiple small-sized WritePrinter calls are performed.
2413         // We may increase performance by writing into a buffer and only doing a single RPC call when the buffer is full.
2414 
2415         // Do the RPC call
2416         RpcTryExcept
2417         {
2418             dwErrorCode = _RpcWritePrinter(pHandle->hPrinter, pBuf, cbBuf, pcWritten);
2419         }
2420         RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2421         {
2422             dwErrorCode = RpcExceptionCode();
2423             ERR("_RpcWritePrinter failed with exception code %lu!\n", dwErrorCode);
2424         }
2425         RpcEndExcept;
2426     }
2427 
2428 Cleanup:
2429     SetLastError(dwErrorCode);
2430     return (dwErrorCode == ERROR_SUCCESS);
2431 }
2432 
2433 BOOL WINAPI
2434 XcvDataW(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded, PDWORD pdwStatus)
2435 {
2436     TRACE("XcvDataW(%p, %S, %p, %lu, %p, %lu, %p, %p)\n", hXcv, pszDataName, pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
2437     return FALSE;
2438 }
2439