1 /*
2  * PROJECT:     ReactOS Spooler API
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Functions related to Printer Drivers
5  * COPYRIGHT:   Copyright 2015-2017 Colin Finck (colin@reactos.org)
6  */
7 
8 #include "precomp.h"
9 #include <marshalling/printerdrivers.h>
10 
11 extern const WCHAR wszCurrentEnvironment[];
12 
13 static int multi_sz_lenA(const char *str)
14 {
15     const char *ptr = str;
16     if(!str) return 0;
17     do
18     {
19         ptr += lstrlenA(ptr) + 1;
20     } while(*ptr);
21 
22     return ptr - str + 1;
23 }
24 
25 static int multi_sz_lenW(const WCHAR *str)
26 {
27     const WCHAR *ptr = str;
28     if (!str) return 0;
29     do
30     {
31         ptr += lstrlenW(ptr) + 1;
32     } while (*ptr);
33 
34     return (ptr - str + 1);
35 }
36 
37 BOOL WINAPI
38 AddPrinterDriverA(PSTR pName, DWORD Level, PBYTE pDriverInfo)
39 {
40     TRACE("AddPrinterDriverA(%s, %lu, %p)\n", pName, Level, pDriverInfo);
41     return AddPrinterDriverExA(pName, Level, pDriverInfo, APD_COPY_NEW_FILES);
42 }
43 
44 BOOL WINAPI
45 AddPrinterDriverExA(PSTR pName, DWORD Level, PBYTE pDriverInfo, DWORD dwFileCopyFlags)
46 {
47     PDRIVER_INFO_8A  pdiA;
48     DRIVER_INFO_8W   diW;
49     LPWSTR  nameW = NULL;
50     DWORD   lenA;
51     DWORD   len;
52     BOOL    res = FALSE;
53 
54     TRACE("AddPrinterDriverExA(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
55 
56     pdiA = (DRIVER_INFO_8A *) pDriverInfo;
57     ZeroMemory(&diW, sizeof(diW));
58 
59     if (Level < 2 || Level == 5 || Level == 7 || Level > 8)
60     {
61         SetLastError(ERROR_INVALID_LEVEL);
62         return FALSE;
63     }
64 
65     if (pdiA == NULL)
66     {
67         SetLastError(ERROR_INVALID_PARAMETER);
68         return FALSE;
69     }
70 
71     /* convert servername to unicode */
72     if (pName)
73     {
74         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
75         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
76         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
77     }
78 
79     /* common fields */
80     diW.cVersion = pdiA->cVersion;
81 
82     if (pdiA->pName)
83     {
84         len = MultiByteToWideChar(CP_ACP, 0, pdiA->pName, -1, NULL, 0);
85         diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
86         MultiByteToWideChar(CP_ACP, 0, pdiA->pName, -1, diW.pName, len);
87     }
88 
89     if (pdiA->pEnvironment)
90     {
91         len = MultiByteToWideChar(CP_ACP, 0, pdiA->pEnvironment, -1, NULL, 0);
92         diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
93         MultiByteToWideChar(CP_ACP, 0, pdiA->pEnvironment, -1, diW.pEnvironment, len);
94     }
95 
96     if (pdiA->pDriverPath)
97     {
98         len = MultiByteToWideChar(CP_ACP, 0, pdiA->pDriverPath, -1, NULL, 0);
99         diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
100         MultiByteToWideChar(CP_ACP, 0, pdiA->pDriverPath, -1, diW.pDriverPath, len);
101     }
102 
103     if (pdiA->pDataFile)
104     {
105         len = MultiByteToWideChar(CP_ACP, 0, pdiA->pDataFile, -1, NULL, 0);
106         diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
107         MultiByteToWideChar(CP_ACP, 0, pdiA->pDataFile, -1, diW.pDataFile, len);
108     }
109 
110     if (pdiA->pConfigFile)
111     {
112         len = MultiByteToWideChar(CP_ACP, 0, pdiA->pConfigFile, -1, NULL, 0);
113         diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
114         MultiByteToWideChar(CP_ACP, 0, pdiA->pConfigFile, -1, diW.pConfigFile, len);
115     }
116 
117     if ((Level > 2) && pdiA->pHelpFile)
118     {
119         len = MultiByteToWideChar(CP_ACP, 0, pdiA->pHelpFile, -1, NULL, 0);
120         diW.pHelpFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
121         MultiByteToWideChar(CP_ACP, 0, pdiA->pHelpFile, -1, diW.pHelpFile, len);
122     }
123 
124     if ((Level > 2) && pdiA->pDependentFiles)
125     {
126         lenA = multi_sz_lenA(pdiA->pDependentFiles);
127         len = MultiByteToWideChar(CP_ACP, 0, pdiA->pDependentFiles, lenA, NULL, 0);
128         diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
129         MultiByteToWideChar(CP_ACP, 0, pdiA->pDependentFiles, lenA, diW.pDependentFiles, len);
130     }
131 
132     if ((Level > 2) && pdiA->pMonitorName)
133     {
134         len = MultiByteToWideChar(CP_ACP, 0, pdiA->pMonitorName, -1, NULL, 0);
135         diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
136         MultiByteToWideChar(CP_ACP, 0, pdiA->pMonitorName, -1, diW.pMonitorName, len);
137     }
138 
139     if ((Level > 2) && pdiA->pDefaultDataType)
140     {
141         len = MultiByteToWideChar(CP_ACP, 0, pdiA->pDefaultDataType, -1, NULL, 0);
142         diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
143         MultiByteToWideChar(CP_ACP, 0, pdiA->pDefaultDataType, -1, diW.pDefaultDataType, len);
144     }
145 
146     if ((Level > 3) && pdiA->pszzPreviousNames)
147     {
148         lenA = multi_sz_lenA(pdiA->pszzPreviousNames);
149         len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszzPreviousNames, lenA, NULL, 0);
150         diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
151         MultiByteToWideChar(CP_ACP, 0, pdiA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
152     }
153 
154     if (Level > 5)
155     {
156         diW.ftDriverDate = pdiA->ftDriverDate;
157         diW.dwlDriverVersion = pdiA->dwlDriverVersion;
158     }
159 
160     if ((Level > 5) && pdiA->pszMfgName)
161     {
162         len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszMfgName, -1, NULL, 0);
163         diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
164         MultiByteToWideChar(CP_ACP, 0, pdiA->pszMfgName, -1, diW.pszMfgName, len);
165     }
166 
167     if ((Level > 5) && pdiA->pszOEMUrl)
168     {
169         len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszOEMUrl, -1, NULL, 0);
170         diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
171         MultiByteToWideChar(CP_ACP, 0, pdiA->pszOEMUrl, -1, diW.pszOEMUrl, len);
172     }
173 
174     if ((Level > 5) && pdiA->pszHardwareID)
175     {
176         len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszHardwareID, -1, NULL, 0);
177         diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
178         MultiByteToWideChar(CP_ACP, 0, pdiA->pszHardwareID, -1, diW.pszHardwareID, len);
179     }
180 
181     if ((Level > 5) && pdiA->pszProvider)
182     {
183         len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszProvider, -1, NULL, 0);
184         diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
185         MultiByteToWideChar(CP_ACP, 0, pdiA->pszProvider, -1, diW.pszProvider, len);
186     }
187 
188     if ((Level > 7) && pdiA->pszPrintProcessor)
189     {
190         len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszPrintProcessor, -1, NULL, 0);
191         diW.pszPrintProcessor = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
192         MultiByteToWideChar(CP_ACP, 0, pdiA->pszPrintProcessor, -1, diW.pszPrintProcessor, len);
193     }
194 
195     if ((Level > 7) && pdiA->pszVendorSetup)
196     {
197         len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszVendorSetup, -1, NULL, 0);
198         diW.pszVendorSetup = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
199         MultiByteToWideChar(CP_ACP, 0, pdiA->pszVendorSetup, -1, diW.pszVendorSetup, len);
200     }
201 
202     if ((Level > 7) && pdiA->pszzColorProfiles)
203     {
204         lenA = multi_sz_lenA(pdiA->pszzColorProfiles);
205         len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszzColorProfiles, lenA, NULL, 0);
206         diW.pszzColorProfiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
207         MultiByteToWideChar(CP_ACP, 0, pdiA->pszzColorProfiles, lenA, diW.pszzColorProfiles, len);
208     }
209 
210     if ((Level > 7) && pdiA->pszInfPath)
211     {
212         len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszInfPath, -1, NULL, 0);
213         diW.pszInfPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
214         MultiByteToWideChar(CP_ACP, 0, pdiA->pszInfPath, -1, diW.pszInfPath, len);
215     }
216 
217     if ((Level > 7) && pdiA->pszzCoreDriverDependencies)
218     {
219         lenA = multi_sz_lenA(pdiA->pszzCoreDriverDependencies);
220         len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszzCoreDriverDependencies, lenA, NULL, 0);
221         diW.pszzCoreDriverDependencies = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
222         MultiByteToWideChar(CP_ACP, 0, pdiA->pszzCoreDriverDependencies, lenA, diW.pszzCoreDriverDependencies, len);
223     }
224 
225     if (Level > 7)
226     {
227         diW.dwPrinterDriverAttributes = pdiA->dwPrinterDriverAttributes;
228         diW.ftMinInboxDriverVerDate = pdiA->ftMinInboxDriverVerDate;
229         diW.dwlMinInboxDriverVerVersion = pdiA->dwlMinInboxDriverVerVersion;
230     }
231 
232     res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
233 
234     TRACE("got %u with %u\n", res, GetLastError());
235     if (nameW) HeapFree(GetProcessHeap(), 0, nameW);
236     if (diW.pName) HeapFree(GetProcessHeap(), 0, diW.pName);
237     if (diW.pEnvironment) HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
238     if (diW.pDriverPath) HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
239     if (diW.pDataFile) HeapFree(GetProcessHeap(), 0, diW.pDataFile);
240     if (diW.pConfigFile) HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
241     if (diW.pHelpFile) HeapFree(GetProcessHeap(), 0, diW.pHelpFile);
242     if (diW.pDependentFiles) HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
243     if (diW.pMonitorName) HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
244     if (diW.pDefaultDataType) HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
245     if (diW.pszzPreviousNames) HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
246     if (diW.pszMfgName) HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
247     if (diW.pszOEMUrl) HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
248     if (diW.pszHardwareID) HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
249     if (diW.pszProvider) HeapFree(GetProcessHeap(), 0, diW.pszProvider);
250     if (diW.pszPrintProcessor) HeapFree(GetProcessHeap(), 0, diW.pszPrintProcessor);
251     if (diW.pszVendorSetup) HeapFree(GetProcessHeap(), 0, diW.pszVendorSetup);
252     if (diW.pszzColorProfiles) HeapFree(GetProcessHeap(), 0, diW.pszzColorProfiles);
253     if (diW.pszInfPath) HeapFree(GetProcessHeap(), 0, diW.pszInfPath);
254     if (diW.pszzCoreDriverDependencies) HeapFree(GetProcessHeap(), 0, diW.pszzCoreDriverDependencies);
255 
256     TRACE("=> %u with %u\n", res, GetLastError());
257     return res;
258 }
259 
260 BOOL WINAPI
261 AddPrinterDriverExW(PWSTR pName, DWORD Level, PBYTE pDriverInfo, DWORD dwFileCopyFlags)
262 {
263     DWORD dwErrorCode = ERROR_SUCCESS;
264     WINSPOOL_DRIVER_INFO_8 * pdi = NULL;
265     WINSPOOL_DRIVER_CONTAINER pDriverContainer;
266 
267     TRACE("AddPrinterDriverExW(%S, %lu, %p, %lu)\n", pName, Level, pDriverInfo, dwFileCopyFlags);
268 
269     pDriverContainer.Level = Level;
270 
271     switch (Level)
272     {
273         case 8:
274         {
275             PDRIVER_INFO_8W pdi8w = (PDRIVER_INFO_8W)pDriverInfo;
276             pdi = HeapAlloc(hProcessHeap, 0, sizeof(WINSPOOL_DRIVER_INFO_8));
277 
278             pdi->pPrintProcessor   = pdi8w->pszPrintProcessor;
279             pdi->pVendorSetup      = pdi8w->pszVendorSetup;
280 
281             pdi->pszzColorProfiles = pdi8w->pszzColorProfiles;
282             pdi->cchColorProfiles = 0;
283             if ( pdi8w->pszzColorProfiles && *pdi8w->pszzColorProfiles )
284             {
285                 pdi->cchColorProfiles = multi_sz_lenW( pdi8w->pszzColorProfiles );
286             }
287 
288             pdi->pInfPath = pdi8w->pszInfPath;
289 
290             pdi->pszzCoreDriverDependencies = pdi8w->pszzCoreDriverDependencies;
291             pdi->cchCoreDependencies = 0;
292             if ( pdi8w->pszzCoreDriverDependencies && *pdi8w->pszzCoreDriverDependencies )
293             {
294                 pdi->cchCoreDependencies = multi_sz_lenW( pdi8w->pszzCoreDriverDependencies );
295             }
296 
297             pdi->ftMinInboxDriverVerDate     = pdi8w->ftMinInboxDriverVerDate;
298             pdi->dwlMinInboxDriverVerVersion = pdi8w->dwlMinInboxDriverVerVersion;
299         }
300         case 6:
301         {
302             PDRIVER_INFO_6W pdi6w = (PDRIVER_INFO_6W)pDriverInfo;
303             if ( pdi == NULL ) pdi = HeapAlloc(hProcessHeap, 0, sizeof(WINSPOOL_DRIVER_INFO_6));
304 
305             pdi->pMfgName         = pdi6w->pszMfgName;
306             pdi->pOEMUrl          = pdi6w->pszOEMUrl;
307             pdi->pHardwareID      = pdi6w->pszHardwareID;
308             pdi->pProvider        = pdi6w->pszProvider;
309             pdi->ftDriverDate     = pdi6w->ftDriverDate;
310             pdi->dwlDriverVersion = pdi6w->dwlDriverVersion;
311         }
312         case 4:
313         {
314             PDRIVER_INFO_4W pdi4w = (PDRIVER_INFO_4W)pDriverInfo;
315             if ( pdi == NULL )  pdi = HeapAlloc(hProcessHeap, 0, sizeof(WINSPOOL_DRIVER_INFO_4));
316 
317             pdi->pszzPreviousNames = pdi4w->pszzPreviousNames;
318             pdi->cchPreviousNames  = 0;
319             if ( pdi4w->pDependentFiles && *pdi4w->pDependentFiles )
320             {
321                pdi->cchPreviousNames = multi_sz_lenW( pdi4w->pDependentFiles );
322             }
323         }
324         case 3:
325         {
326             PDRIVER_INFO_3W pdi3w = (PDRIVER_INFO_3W)pDriverInfo;
327             if ( pdi == NULL ) pdi = HeapAlloc(hProcessHeap, 0, sizeof(WINSPOOL_DRIVER_INFO_3));
328 
329             pdi->pHelpFile        = pdi3w->pHelpFile;
330             pdi->pDependentFiles  = pdi3w->pDependentFiles;
331             pdi->pMonitorName     = pdi3w->pMonitorName;
332             pdi->pDefaultDataType = pdi3w->pDefaultDataType;
333 
334             pdi->pDependentFiles = pdi3w->pDependentFiles;
335             pdi->cchDependentFiles = 0;
336             if ( pdi3w->pDependentFiles && *pdi3w->pDependentFiles )
337             {
338                 pdi->cchDependentFiles = multi_sz_lenW( pdi3w->pDependentFiles );
339             }
340         }
341         case 2:
342         {
343             PDRIVER_INFO_2W pdi2w = (PDRIVER_INFO_2W)pDriverInfo;
344             if ( pdi == NULL ) pdi = HeapAlloc(hProcessHeap, 0, sizeof(WINSPOOL_DRIVER_INFO_2));
345 
346             pdi->pName = pdi2w->pName;
347 
348             pdi->pEnvironment = pdi2w->pEnvironment;
349             if ( !pdi2w->pEnvironment || !*pdi2w->pEnvironment )
350             {
351                 pdi2w->pEnvironment = (PWSTR)wszCurrentEnvironment;
352             }
353 
354             pdi->pDriverPath = pdi2w->pDriverPath;
355             pdi->pDataFile   = pdi2w->pDataFile;
356             pdi->pConfigFile = pdi2w->pConfigFile;
357         }
358             break;
359 
360         default:
361             SetLastError(ERROR_INVALID_LEVEL);
362             return FALSE;
363     }
364 
365     pDriverContainer.DriverInfo.Level8 = pdi;
366 
367     RpcTryExcept
368     {
369         dwErrorCode = _RpcAddPrinterDriverEx( pName, &pDriverContainer, dwFileCopyFlags );
370     }
371     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
372     {
373         dwErrorCode = RpcExceptionCode();
374         ERR("_RpcAddPrinterDriverEx failed with exception code %lu!\n", dwErrorCode);
375     }
376     RpcEndExcept;
377 
378     if ( pdi ) HeapFree( GetProcessHeap(), 0, pdi );
379 
380     SetLastError(dwErrorCode);
381     return (dwErrorCode == ERROR_SUCCESS);
382 }
383 
384 BOOL WINAPI
385 AddPrinterDriverW(PWSTR pName, DWORD Level, PBYTE pDriverInfo)
386 {
387     TRACE("AddPrinterDriverW(%S, %lu, %p)\n", pName, Level, pDriverInfo);
388     return AddPrinterDriverExW(pName, Level, pDriverInfo, APD_COPY_NEW_FILES);
389 }
390 
391 BOOL WINAPI
392 DeletePrinterDriverA(PSTR pName, PSTR pEnvironment, PSTR pDriverName)
393 {
394     TRACE("DeletePrinterDriverA(%s, %s, %s)\n", pName, pEnvironment, pDriverName);
395     return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
396 }
397 
398 BOOL WINAPI
399 DeletePrinterDriverExA(PSTR pName, PSTR pEnvironment, PSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
400 {
401     DWORD dwErrorCode;
402     UNICODE_STRING NameW, EnvW, DriverW;
403     BOOL ret;
404 
405     TRACE("DeletePrinterDriverExA(%s, %s, %s, %lu, %lu)\n", pName, pEnvironment, pDriverName, dwDeleteFlag, dwVersionFlag);
406 
407     AsciiToUnicode(&NameW, pName);
408     AsciiToUnicode(&EnvW, pEnvironment);
409     AsciiToUnicode(&DriverW, pDriverName);
410 
411     ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
412 
413     dwErrorCode = GetLastError();
414 
415     RtlFreeUnicodeString(&DriverW);
416     RtlFreeUnicodeString(&EnvW);
417     RtlFreeUnicodeString(&NameW);
418 
419     SetLastError(dwErrorCode);
420     return ret;
421 }
422 
423 BOOL WINAPI
424 DeletePrinterDriverExW(PWSTR pName, PWSTR pEnvironment, PWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
425 {
426     DWORD dwErrorCode;
427 
428     TRACE("DeletePrinterDriverExW(%S, %S, %S, %lu, %lu)\n", pName, pEnvironment, pDriverName, dwDeleteFlag, dwVersionFlag);
429 
430     if ( !pDriverName || !*pDriverName )
431     {
432         SetLastError(ERROR_INVALID_PARAMETER);
433         return FALSE;
434     }
435 
436     if ( !pEnvironment || !*pEnvironment )
437     {
438         pEnvironment = (PWSTR)wszCurrentEnvironment;
439     }
440 
441     // Do the RPC call.
442     RpcTryExcept
443     {
444         dwErrorCode = _RpcDeletePrinterDriverEx(pName, pEnvironment, pDriverName, dwDeleteFlag, dwVersionFlag);
445     }
446     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
447     {
448         dwErrorCode = RpcExceptionCode();
449         ERR("_RpcDeletePrinterDriverEx failed with exception code %lu!\n", dwErrorCode);
450     }
451     RpcEndExcept;
452 
453     SetLastError(dwErrorCode);
454     return (dwErrorCode == ERROR_SUCCESS);
455 
456 }
457 
458 BOOL WINAPI
459 DeletePrinterDriverW(PWSTR pName, PWSTR pEnvironment, PWSTR pDriverName)
460 {
461     TRACE("DeletePrinterDriverW(%S, %S, %S)\n", pName, pEnvironment, pDriverName);
462     return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
463 }
464 
465 BOOL WINAPI
466 EnumPrinterDriversA(PSTR pName, PSTR pEnvironment, DWORD Level, PBYTE pDriverInfo, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
467 {
468     BOOL ret = FALSE;
469     DWORD dwErrorCode, i;
470     UNICODE_STRING pNameW, pEnvironmentW;
471     PWSTR pwstrNameW, pwstrEnvironmentW;
472     PDRIVER_INFO_1W pdi1w = (PDRIVER_INFO_1W)pDriverInfo;
473     PDRIVER_INFO_8W pdi8w = (PDRIVER_INFO_8W)pDriverInfo;
474 
475     FIXME("EnumPrinterDriversA(%s, %s, %lu, %p, %lu, %p, %p)\n", pName, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded, pcReturned);
476 
477     pwstrNameW = AsciiToUnicode(&pNameW, pName);
478     pwstrEnvironmentW = AsciiToUnicode(&pEnvironmentW, pEnvironment);
479 
480     ret = EnumPrinterDriversW( pwstrNameW, pwstrEnvironmentW, Level, pDriverInfo, cbBuf, pcbNeeded, pcReturned );
481 
482     dwErrorCode = GetLastError();
483 
484     if (ret)
485     {
486         for ( i = 0; i < *pcReturned; i++ )
487         {
488             switch (Level)
489             {
490                 case 1:
491                 {
492                     dwErrorCode = UnicodeToAnsiInPlace(pdi1w[i].pName);
493                     if (dwErrorCode != ERROR_SUCCESS)
494                     {
495                         goto Cleanup;
496                     }
497                     break;
498                 }
499                 case 8:
500                 {
501                     dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pszPrintProcessor);
502                     if (dwErrorCode != ERROR_SUCCESS)
503                     {
504                         goto Cleanup;
505                     }
506                     dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pszVendorSetup);
507                     if (dwErrorCode != ERROR_SUCCESS)
508                     {
509                         goto Cleanup;
510                     }
511                     dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w[i].pszzColorProfiles);
512                     if (dwErrorCode != ERROR_SUCCESS)
513                     {
514                         goto Cleanup;
515                     }
516                     dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pszInfPath);
517                     if (dwErrorCode != ERROR_SUCCESS)
518                     {
519                         goto Cleanup;
520                     }
521                     dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w[i].pszzCoreDriverDependencies);
522                     if (dwErrorCode != ERROR_SUCCESS)
523                     {
524                         goto Cleanup;
525                     }
526                 }
527                 case 6:
528                 {
529                     dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pszMfgName);
530                     if (dwErrorCode != ERROR_SUCCESS)
531                     {
532                         goto Cleanup;
533                     }
534 
535                     dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pszOEMUrl);
536                     if (dwErrorCode != ERROR_SUCCESS)
537                     {
538                         goto Cleanup;
539                     }
540 
541                     dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pszHardwareID);
542                     if (dwErrorCode != ERROR_SUCCESS)
543                     {
544                         goto Cleanup;
545                     }
546 
547                     dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pszProvider);
548                     if (dwErrorCode != ERROR_SUCCESS)
549                     {
550                         goto Cleanup;
551                     }
552                 }
553                 case 4:
554                 {
555                     dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w[i].pszzPreviousNames);
556                     if (dwErrorCode != ERROR_SUCCESS)
557                     {
558                         goto Cleanup;
559                     }
560                 }
561                 case 3:
562                 {
563                     dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pHelpFile);
564                     if (dwErrorCode != ERROR_SUCCESS)
565                     {
566                         goto Cleanup;
567                     }
568 
569                     dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w[i].pDependentFiles);
570                     if (dwErrorCode != ERROR_SUCCESS)
571                     {
572                         goto Cleanup;
573                     }
574 
575                     dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pMonitorName);
576                     if (dwErrorCode != ERROR_SUCCESS)
577                     {
578                         goto Cleanup;
579                     }
580 
581                     dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pDefaultDataType);
582                     if (dwErrorCode != ERROR_SUCCESS)
583                     {
584                         goto Cleanup;
585                     }
586                 }
587                 case 2:
588                 case 5:
589                 {
590                     dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pName);
591                     if (dwErrorCode != ERROR_SUCCESS)
592                     {
593                         goto Cleanup;
594                     }
595 
596                     dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pEnvironment);
597                     if (dwErrorCode != ERROR_SUCCESS)
598                     {
599                         goto Cleanup;
600                     }
601 
602                     dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pDriverPath);
603                     if (dwErrorCode != ERROR_SUCCESS)
604                     {
605                         goto Cleanup;
606                     }
607 
608                     dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pDataFile);
609                     if (dwErrorCode != ERROR_SUCCESS)
610                     {
611                         goto Cleanup;
612                     }
613 
614                     dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pConfigFile);
615                     if (dwErrorCode != ERROR_SUCCESS)
616                     {
617                         goto Cleanup;
618                     }
619                 }
620             }
621         }
622         dwErrorCode = ERROR_SUCCESS;
623     }
624 Cleanup:
625     RtlFreeUnicodeString(&pNameW);
626     RtlFreeUnicodeString(&pEnvironmentW);
627     SetLastError(dwErrorCode);
628     FIXME("EnumPrinterDriversA Exit %d Err %d\n",ret,GetLastError());
629     return ret;
630 }
631 
632 BOOL WINAPI
633 EnumPrinterDriversW(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pDriverInfo, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
634 {
635     DWORD dwErrorCode;
636 
637     FIXME("EnumPrinterDriversW(%S, %S, %lu, %p, %lu, %p, %p)\n", pName, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded, pcReturned);
638 
639     // Dismiss invalid levels already at this point.
640     if (Level < 1 || Level == 7 || Level > 8)
641     {
642         dwErrorCode = ERROR_INVALID_LEVEL;
643         goto Cleanup;
644     }
645 
646     if ( !pEnvironment || !*pEnvironment )
647     {
648         pEnvironment = (PWSTR)wszCurrentEnvironment;
649     }
650 
651     if (cbBuf && pDriverInfo)
652         ZeroMemory(pDriverInfo, cbBuf);
653 
654     // Do the RPC call
655     RpcTryExcept
656     {
657         dwErrorCode = _RpcEnumPrinterDrivers( pName, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded, pcReturned );
658     }
659     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
660     {
661         dwErrorCode = RpcExceptionCode();
662         ERR("_RpcEnumPrinterDrivers failed with exception code %lu!\n", dwErrorCode);
663     }
664     RpcEndExcept;
665 
666     if (dwErrorCode == ERROR_SUCCESS)
667     {
668         // Replace relative offset addresses in the output by absolute pointers.
669         ASSERT(Level <= 6 || Level == 8);
670         MarshallUpStructuresArray(cbBuf, pDriverInfo, *pcReturned, pPrinterDriverMarshalling[Level]->pInfo, pPrinterDriverMarshalling[Level]->cbStructureSize, TRUE);
671     }
672 
673 Cleanup:
674     SetLastError(dwErrorCode); FIXME("EnumPrinterDriversW Exit Err %d\n",dwErrorCode);
675     return (dwErrorCode == ERROR_SUCCESS);
676 
677 }
678 
679 BOOL WINAPI
680 GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
681 {
682     DWORD dwErrorCode;
683     /*
684      * We are mapping multiple different pointers to the same pDriverInfo pointer here so that
685      * we can use the same incoming pointer for different Levels
686      */
687     PDRIVER_INFO_1W pdi1w = (PDRIVER_INFO_1W)pDriverInfo;
688     PDRIVER_INFO_8W pdi8w = (PDRIVER_INFO_8W)pDriverInfo;
689 
690     DWORD cch;
691     PWSTR pwszEnvironment = NULL;
692 
693     TRACE("GetPrinterDriverA(%p, %s, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
694 
695     // Check for invalid levels here for early error return. Should be 1-6 & 8.
696     if (Level <  1 || Level == 7 || Level > 8)
697     {
698         dwErrorCode = ERROR_INVALID_LEVEL;
699         ERR("Invalid Level! %d\n",Level);
700         goto Cleanup;
701     }
702 
703     if (pEnvironment)
704     {
705         // Convert pEnvironment to a Unicode string pwszEnvironment.
706         cch = strlen(pEnvironment);
707 
708         pwszEnvironment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
709         if (!pwszEnvironment)
710         {
711             dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
712             ERR("HeapAlloc failed!\n");
713             goto Cleanup;
714         }
715 
716         MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, pwszEnvironment, cch + 1);
717     }
718 
719     if (!GetPrinterDriverW(hPrinter, pwszEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded))
720     {
721         dwErrorCode = GetLastError();
722         goto Cleanup;
723     }
724 
725     // Do Unicode to ANSI conversions for strings based on Level
726     switch (Level)
727     {
728         case 1:
729         {
730             dwErrorCode = UnicodeToAnsiInPlace(pdi1w->pName);
731             if (dwErrorCode != ERROR_SUCCESS)
732             {
733                 goto Cleanup;
734             }
735             break;
736         }
737         case 8:
738         {
739             dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pszPrintProcessor);
740             if (dwErrorCode != ERROR_SUCCESS)
741             {
742                 goto Cleanup;
743             }
744             dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pszVendorSetup);
745             if (dwErrorCode != ERROR_SUCCESS)
746             {
747                 goto Cleanup;
748             }
749             dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w->pszzColorProfiles);
750             if (dwErrorCode != ERROR_SUCCESS)
751             {
752                 goto Cleanup;
753             }
754             dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pszInfPath);
755             if (dwErrorCode != ERROR_SUCCESS)
756             {
757                 goto Cleanup;
758             }
759             dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w->pszzCoreDriverDependencies);
760             if (dwErrorCode != ERROR_SUCCESS)
761             {
762                 goto Cleanup;
763             }
764         }
765         case 6:
766         {
767             dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pszMfgName);
768             if (dwErrorCode != ERROR_SUCCESS)
769             {
770                 goto Cleanup;
771             }
772 
773             dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pszOEMUrl);
774             if (dwErrorCode != ERROR_SUCCESS)
775             {
776                 goto Cleanup;
777             }
778 
779             dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pszHardwareID);
780             if (dwErrorCode != ERROR_SUCCESS)
781             {
782                 goto Cleanup;
783             }
784 
785             dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pszProvider);
786             if (dwErrorCode != ERROR_SUCCESS)
787             {
788                 goto Cleanup;
789             }
790         }
791         case 4:
792         {
793             dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w->pszzPreviousNames);
794             if (dwErrorCode != ERROR_SUCCESS)
795             {
796                 goto Cleanup;
797             }
798         }
799         case 3:
800         {
801             dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pHelpFile);
802             if (dwErrorCode != ERROR_SUCCESS)
803             {
804                 goto Cleanup;
805             }
806 
807             dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w->pDependentFiles);
808             if (dwErrorCode != ERROR_SUCCESS)
809             {
810                 goto Cleanup;
811             }
812 
813             dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pMonitorName);
814             if (dwErrorCode != ERROR_SUCCESS)
815             {
816                 goto Cleanup;
817             }
818 
819             dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pDefaultDataType);
820             if (dwErrorCode != ERROR_SUCCESS)
821             {
822                 goto Cleanup;
823             }
824         }
825         case 2:
826         case 5:
827         {
828             dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pConfigFile);
829             if (dwErrorCode != ERROR_SUCCESS)
830             {
831                 goto Cleanup;
832             }
833             dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pDataFile);
834 
835             if (dwErrorCode != ERROR_SUCCESS)
836             {
837                 goto Cleanup;
838             }
839 
840             dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pDriverPath);
841             if (dwErrorCode != ERROR_SUCCESS)
842             {
843                 goto Cleanup;
844             }
845 
846             dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pEnvironment);
847             if (dwErrorCode != ERROR_SUCCESS)
848             {
849                 goto Cleanup;
850             }
851 
852             dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pName);
853             if (dwErrorCode != ERROR_SUCCESS)
854             {
855                 goto Cleanup;
856             }
857         }
858     }
859 
860     dwErrorCode = ERROR_SUCCESS;
861 
862 Cleanup:
863     if (pwszEnvironment)
864     {
865         HeapFree(hProcessHeap, 0, pwszEnvironment);
866     }
867 
868     SetLastError(dwErrorCode);
869     return (dwErrorCode == ERROR_SUCCESS);
870 }
871 
872 BOOL WINAPI
873 GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
874 {
875     DWORD dwErrorCode;
876     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
877 
878     TRACE("GetPrinterDriverW(%p, %S, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
879 
880     // Sanity checks.
881     if (!pHandle)
882     {
883         dwErrorCode = ERROR_INVALID_HANDLE;
884         goto Cleanup;
885     }
886 
887     // Dismiss invalid levels already at this point.
888     if (Level > 8 || Level == 7 || Level < 1)
889     {
890         dwErrorCode = ERROR_INVALID_LEVEL;
891         goto Cleanup;
892     }
893 
894     if ( !pEnvironment || !*pEnvironment )
895     {
896         pEnvironment = (PWSTR)wszCurrentEnvironment;
897     }
898 
899     if (cbBuf && pDriverInfo)
900         ZeroMemory(pDriverInfo, cbBuf);
901 
902     // Do the RPC call
903     RpcTryExcept
904     {
905         dwErrorCode = _RpcGetPrinterDriver(pHandle->hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
906     }
907     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
908     {
909         dwErrorCode = RpcExceptionCode();
910         ERR("_RpcGetPrinterDriver failed with exception code %lu!\n", dwErrorCode);
911     }
912     RpcEndExcept;
913 
914     if (dwErrorCode == ERROR_SUCCESS)
915     {
916         // Replace relative offset addresses in the output by absolute pointers.
917         ASSERT(Level <= 6 || Level == 8);
918         MarshallUpStructure(cbBuf, pDriverInfo, pPrinterDriverMarshalling[Level]->pInfo, pPrinterDriverMarshalling[Level]->cbStructureSize, TRUE);
919     }
920 
921 Cleanup:
922     SetLastError(dwErrorCode);
923     return (dwErrorCode == ERROR_SUCCESS);
924 }
925 
926 BOOL WINAPI
927 GetPrinterDriverDirectoryA(PSTR pName, PSTR pEnvironment, DWORD Level, PBYTE pDriverDirectory, DWORD cbBuf, PDWORD pcbNeeded)
928 {
929     UNICODE_STRING nameW, environmentW;
930     BOOL ret;
931     DWORD pcbNeededW;
932     INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
933     WCHAR *driverDirectoryW = NULL;
934 
935     TRACE("GetPrinterDriverDirectoryA(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
936 
937     if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
938 
939     if (pName)
940     {
941         RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
942     }
943     else
944     {
945         nameW.Buffer = NULL;
946     }
947     if (pEnvironment)
948     {
949         RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
950     }
951     else
952     {
953         environmentW.Buffer = NULL;
954     }
955 
956     ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level, (LPBYTE)driverDirectoryW, len, &pcbNeededW );
957 
958     if (ret)
959     {
960         DWORD needed =  WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1, (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
961 
962         if ( pcbNeeded )
963             *pcbNeeded = needed;
964 
965         ret = needed <= cbBuf;
966     }
967     else
968     {
969         if (pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
970     }
971 
972     TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
973 
974     HeapFree( GetProcessHeap(), 0, driverDirectoryW );
975     RtlFreeUnicodeString(&environmentW);
976     RtlFreeUnicodeString(&nameW);
977 
978     return ret;
979 }
980 
981 BOOL WINAPI
982 GetPrinterDriverDirectoryW(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pDriverDirectory, DWORD cbBuf, PDWORD pcbNeeded)
983 {
984     DWORD dwErrorCode;
985 
986     TRACE("GetPrinterDriverDirectoryW(%S, %S, %lu, %p, %lu, %p)\n", pName, pEnvironment, Level, pDriverDirectory, cbBuf, pcbNeeded);
987 
988     if (Level != 1)
989     {
990         dwErrorCode = ERROR_INVALID_LEVEL;
991         goto Cleanup;
992     }
993 
994     if ( !pEnvironment || !*pEnvironment )
995     {
996         pEnvironment = (PWSTR)wszCurrentEnvironment;
997     }
998 
999     // Do the RPC call.
1000     RpcTryExcept
1001     {
1002         dwErrorCode = _RpcGetPrinterDriverDirectory(pName, pEnvironment, Level, pDriverDirectory, cbBuf, pcbNeeded);
1003     }
1004     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1005     {
1006         dwErrorCode = RpcExceptionCode();
1007         ERR("_RpcGetPrinterDriverDirectory failed with exception code %lu!\n", dwErrorCode);
1008     }
1009     RpcEndExcept;
1010 
1011 Cleanup:
1012     SetLastError(dwErrorCode);
1013     return (dwErrorCode == ERROR_SUCCESS);
1014 }
1015