1 /*
2  * PROJECT:     ReactOS Spooler API
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Functions related to Printer Configuration Data
5  * COPYRIGHT:   Copyright 2015-2017 Colin Finck (colin@reactos.org)
6  */
7 
8 #include "precomp.h"
9 
10 LONG WINAPI
11 AdvancedSetupDialog(HWND hWnd, INT Unknown, PDEVMODEA pDevModeInput, PDEVMODEA pDevModeOutput)
12 {
13    HANDLE hPrinter;
14    LONG Ret = -1;
15 
16     TRACE("AdvancedSetupDialog(%p, %d, %p, %p)\n", hWnd, Unknown, pDevModeOutput, pDevModeInput);
17 
18     if ( OpenPrinterA( (LPSTR)pDevModeInput->dmDeviceName, &hPrinter, NULL ) )
19     {
20         Ret = AdvancedDocumentPropertiesA( hWnd, hPrinter, (PSTR)pDevModeInput->dmDeviceName, pDevModeOutput, pDevModeInput );
21         ClosePrinter(hPrinter);
22     }
23     return Ret;
24 }
25 
26 LONG WINAPI
27 AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, PSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
28 {
29     TRACE("AdvancedDocumentPropertiesA(%p, %p, %s, %p, %p)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput);
30     UNIMPLEMENTED;
31     return 0;
32 }
33 
34 LONG WINAPI
35 AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, PWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
36 {
37     TRACE("AdvancedDocumentPropertiesW(%p, %p, %S, %p, %p)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput);
38     UNIMPLEMENTED;
39     return 0;
40 }
41 
42 DWORD WINAPI
43 DeletePrinterDataA(HANDLE hPrinter, PSTR pValueName)
44 {
45     LPWSTR  valuenameW = NULL;
46     INT     len;
47     DWORD   res;
48 
49     TRACE("DeletePrinterDataA(%p, %s)\n", hPrinter, pValueName);
50 
51     if (pValueName)
52     {
53         len = MultiByteToWideChar(CP_ACP, 0, pValueName, -1, NULL, 0);
54         valuenameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
55         MultiByteToWideChar(CP_ACP, 0, pValueName, -1, valuenameW, len);
56     }
57 
58     res = DeletePrinterDataW( hPrinter, valuenameW );
59 
60     if (valuenameW) HeapFree(GetProcessHeap(), 0, valuenameW);
61 
62     return res;
63 
64 }
65 
66 DWORD WINAPI
67 DeletePrinterDataExA(HANDLE hPrinter, PCSTR pKeyName, PCSTR pValueName)
68 {
69     LPWSTR  keynameW = NULL;
70     LPWSTR  valuenameW = NULL;
71     INT     len;
72     DWORD   res;
73 
74     TRACE("DeletePrinterDataExA(%p, %s, %s)\n", hPrinter, pKeyName, pValueName);
75 
76     if (pKeyName)
77     {
78         len = MultiByteToWideChar(CP_ACP, 0, pKeyName, -1, NULL, 0);
79         keynameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
80         MultiByteToWideChar(CP_ACP, 0, pKeyName, -1, keynameW, len);
81     }
82 
83     if (pValueName)
84     {
85         len = MultiByteToWideChar(CP_ACP, 0, pValueName, -1, NULL, 0);
86         valuenameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
87         MultiByteToWideChar(CP_ACP, 0, pValueName, -1, valuenameW, len);
88     }
89 
90     res = DeletePrinterDataExW( hPrinter, keynameW, valuenameW );
91 
92     if (keynameW) HeapFree(GetProcessHeap(), 0, keynameW);
93     if (valuenameW) HeapFree(GetProcessHeap(), 0, valuenameW);
94 
95     return res;
96 }
97 
98 DWORD WINAPI
99 DeletePrinterDataExW(HANDLE hPrinter, PCWSTR pKeyName, PCWSTR pValueName)
100 {
101     TRACE("DeletePrinterDataExW(%p, %S, %S)\n", hPrinter, pKeyName, pValueName);
102     UNIMPLEMENTED;
103     return ERROR_NOT_SUPPORTED;
104 }
105 
106 DWORD WINAPI
107 DeletePrinterDataW(HANDLE hPrinter, PWSTR pValueName)
108 {
109     TRACE("DeletePrinterDataW(%p, %S)\n", hPrinter, pValueName);
110     UNIMPLEMENTED;
111     return ERROR_NOT_SUPPORTED;
112 }
113 
114 DWORD WINAPI
115 DeletePrinterKeyA(HANDLE hPrinter, PCSTR pKeyName)
116 {
117     LPWSTR  keynameW = NULL;
118     INT     len;
119     DWORD   res;
120 
121     TRACE("DeletePrinterKeyA(%p, %s)\n", hPrinter, pKeyName);
122 
123     if (pKeyName)
124     {
125         len = MultiByteToWideChar(CP_ACP, 0, pKeyName, -1, NULL, 0);
126         keynameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
127         MultiByteToWideChar(CP_ACP, 0, pKeyName, -1, keynameW, len);
128     }
129 
130     res = DeletePrinterKeyW( hPrinter, keynameW );
131 
132     if (keynameW) HeapFree(GetProcessHeap(), 0, keynameW);
133 
134     return res;
135 }
136 
137 DWORD WINAPI
138 DeletePrinterKeyW(HANDLE hPrinter, PCWSTR pKeyName)
139 {
140     TRACE("DeletePrinterKeyW(%p, %S)\n", hPrinter, pKeyName);
141     UNIMPLEMENTED;
142     return ERROR_NOT_SUPPORTED;
143 }
144 
145 DWORD WINAPI
146 EnumPrinterDataA(HANDLE hPrinter, DWORD dwIndex, PSTR pValueName, DWORD cbValueName, PDWORD pcbValueName, PDWORD pType, PBYTE pData, DWORD cbData, PDWORD pcbData)
147 {
148     TRACE("EnumPrinterDataA(%p, %lu, %s, %lu, %p, %p, %p, %lu, %p)\n", hPrinter, dwIndex, pValueName, cbValueName, pcbValueName, pType, pData, cbData, pcbData);
149     UNIMPLEMENTED;
150     return ERROR_NOT_SUPPORTED;
151 }
152 
153 DWORD WINAPI
154 EnumPrinterDataExA(HANDLE hPrinter, PCSTR pKeyName, PBYTE pEnumValues, DWORD cbEnumValues, PDWORD pcbEnumValues, PDWORD pnEnumValues)
155 {
156     INT	    len;
157     LPWSTR  pKeyNameW;
158     DWORD   ret, dwIndex, dwBufSize;
159     HANDLE  hHeap;
160     LPSTR   pBuffer;
161 
162     TRACE("EnumPrinterDataExA(%p, %s, %p, %lu, %p, %p)\n", hPrinter, pKeyName, pEnumValues, cbEnumValues, pcbEnumValues, pnEnumValues);
163 
164     if (pKeyName == NULL || *pKeyName == 0)
165 	return ERROR_INVALID_PARAMETER;
166 
167     len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
168     if (len == 0)
169     {
170 	ret = GetLastError ();
171 	ERR ("MultiByteToWideChar failed with code %i\n", ret);
172 	return ret;
173     }
174 
175     hHeap = GetProcessHeap ();
176     if (hHeap == NULL)
177     {
178 	ERR ("GetProcessHeap failed\n");
179 	return ERROR_OUTOFMEMORY;
180     }
181 
182     pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
183     if (pKeyNameW == NULL)
184     {
185 	ERR ("Failed to allocate %i bytes from process heap\n",
186              (LONG)(len * sizeof (WCHAR)));
187 	return ERROR_OUTOFMEMORY;
188     }
189 
190     if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
191     {
192 	ret = GetLastError ();
193 	ERR ("MultiByteToWideChar failed with code %i\n", ret);
194 	if (HeapFree (hHeap, 0, pKeyNameW) == 0)
195 	    WARN ("HeapFree failed with code %i\n", GetLastError ());
196 	return ret;
197     }
198 
199     ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues, pcbEnumValues, pnEnumValues);
200 
201     if (ret != ERROR_SUCCESS)
202     {
203 	if (HeapFree (hHeap, 0, pKeyNameW) == 0)
204 	    WARN ("HeapFree failed with code %i\n", GetLastError ());
205 	TRACE ("EnumPrinterDataExW returned %i\n", ret);
206 	return ret;
207     }
208 
209     if (HeapFree (hHeap, 0, pKeyNameW) == 0)
210     {
211 	ret = GetLastError ();
212 	ERR ("HeapFree failed with code %i\n", ret);
213 	return ret;
214     }
215 
216     if (*pnEnumValues == 0)	/* empty key */
217 	return ERROR_SUCCESS;
218 
219     dwBufSize = 0;
220     for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
221     {
222 	PPRINTER_ENUM_VALUESW ppev = &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
223 
224 	if (dwBufSize < ppev->cbValueName)
225 	    dwBufSize = ppev->cbValueName;
226 
227 	if ( dwBufSize < ppev->cbData &&
228 	    (ppev->dwType == REG_SZ || ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
229 	    dwBufSize = ppev->cbData;
230     }
231 
232     FIXME ("Largest Unicode name or value is %i bytes\n", dwBufSize);
233 
234     pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
235     if (pBuffer == NULL)
236     {
237 	ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
238 	return ERROR_OUTOFMEMORY;
239     }
240 
241     for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
242     {
243 	PPRINTER_ENUM_VALUESW ppev =
244 		&((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
245 
246 	len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
247 		ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
248 		NULL);
249 	if (len == 0)
250 	{
251 	    ret = GetLastError ();
252 	    ERR ("WideCharToMultiByte failed with code %i\n", ret);
253 	    if (HeapFree (hHeap, 0, pBuffer) == 0)
254 		WARN ("HeapFree failed with code %i\n", GetLastError ());
255 	    return ret;
256 	}
257 
258 	memcpy (ppev->pValueName, pBuffer, len);
259 
260 	TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
261 
262 	if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
263 		ppev->dwType != REG_MULTI_SZ)
264 	    continue;
265 
266 	len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
267 		ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
268 	if (len == 0)
269 	{
270 	    ret = GetLastError ();
271 	    ERR ("WideCharToMultiByte failed with code %i\n", ret);
272 	    if (HeapFree (hHeap, 0, pBuffer) == 0)
273 		WARN ("HeapFree failed with code %i\n", GetLastError ());
274 	    return ret;
275 	}
276 
277 	memcpy (ppev->pData, pBuffer, len);
278 
279 	TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
280 	TRACE ("  (only first string of REG_MULTI_SZ printed)\n");
281     }
282 
283     if (HeapFree (hHeap, 0, pBuffer) == 0)
284     {
285 	ret = GetLastError ();
286 	ERR ("HeapFree failed with code %i\n", ret);
287 	return ret;
288     }
289 
290     return ERROR_SUCCESS;
291 }
292 
293 DWORD WINAPI
294 EnumPrinterDataExW(HANDLE hPrinter, PCWSTR pKeyName, PBYTE pEnumValues, DWORD cbEnumValues, PDWORD pcbEnumValues, PDWORD pnEnumValues)
295 {
296     TRACE("EnumPrinterDataExW(%p, %S, %p, %lu, %p, %p)\n", hPrinter, pKeyName, pEnumValues, cbEnumValues, pcbEnumValues, pnEnumValues);
297     UNIMPLEMENTED;
298     return ERROR_NOT_SUPPORTED;
299 }
300 
301 DWORD WINAPI
302 EnumPrinterDataW(HANDLE hPrinter, DWORD dwIndex, PWSTR pValueName, DWORD cbValueName, PDWORD pcbValueName, PDWORD pType, PBYTE pData, DWORD cbData, PDWORD pcbData)
303 {
304     TRACE("EnumPrinterDataW(%p, %lu, %S, %lu, %p, %p, %p, %lu, %p)\n", hPrinter, dwIndex, pValueName, cbValueName, pcbValueName, pType, pData, cbData, pcbData);
305     UNIMPLEMENTED;
306     return ERROR_NOT_SUPPORTED;
307 }
308 
309 DWORD WINAPI
310 EnumPrinterKeyA(HANDLE hPrinter, PCSTR pKeyName, PSTR pSubkey, DWORD cbSubkey, PDWORD pcbSubkey)
311 {
312     TRACE("EnumPrinterKeyA(%p, %s, %s, %lu, %p)\n", hPrinter, pKeyName, pSubkey, cbSubkey, pcbSubkey);
313     UNIMPLEMENTED;
314     return ERROR_NOT_SUPPORTED;
315 }
316 
317 DWORD WINAPI
318 EnumPrinterKeyW(HANDLE hPrinter, PCWSTR pKeyName, PWSTR pSubkey, DWORD cbSubkey, PDWORD pcbSubkey)
319 {
320     TRACE("EnumPrinterKeyW(%p, %S, %S, %lu, %p)\n", hPrinter, pKeyName, pSubkey, cbSubkey, pcbSubkey);
321     UNIMPLEMENTED;
322     return ERROR_NOT_SUPPORTED;
323 }
324 
325 DWORD WINAPI
326 GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
327 {
328     TRACE("GetPrinterDataA(%p, %s, %p, %p, %lu, %p)\n", hPrinter, pValueName, pType, pData, nSize, pcbNeeded);
329     return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType, pData, nSize, pcbNeeded);
330 }
331 
332 DWORD WINAPI
333 GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName, LPCSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
334 {
335     DWORD cbUnicodeData;
336     DWORD cch;
337     DWORD dwReturnValue;
338     DWORD dwType;
339     POSVERSIONINFOEXA pInfoA;
340     POSVERSIONINFOEXW pInfoW;
341     PVOID pUnicodeData = NULL;
342     PWSTR pwszKeyName = NULL;
343     PWSTR pwszValueName = NULL;
344 
345     TRACE("GetPrinterDataExA(%p, %s, %s, %p, %p, %lu, %p)\n", hPrinter, pKeyName, pValueName, pType, pData, nSize, pcbNeeded);
346 
347     if (pKeyName)
348     {
349         // Convert pKeyName to a Unicode string pwszKeyName
350         cch = strlen(pKeyName);
351 
352         pwszKeyName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
353         if (!pwszKeyName)
354         {
355             dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
356             ERR("HeapAlloc failed!\n");
357             goto Cleanup;
358         }
359 
360         MultiByteToWideChar(CP_ACP, 0, pKeyName, -1, pwszKeyName, cch + 1);
361     }
362 
363     if (pValueName)
364     {
365         // Convert pValueName to a Unicode string pwszValueName
366         cch = strlen(pValueName);
367 
368         pwszValueName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
369         if (!pwszValueName)
370         {
371             dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
372             ERR("HeapAlloc failed!\n");
373             goto Cleanup;
374         }
375 
376         MultiByteToWideChar(CP_ACP, 0, pValueName, -1, pwszValueName, cch + 1);
377     }
378 
379     // We need the data type information, even if no pData was passed.
380     if (!pType)
381         pType = &dwType;
382 
383     // Call GetPrinterDataExW for the first time.
384     // If we're lucky, the supplied buffer is already large enough and we don't need to do the expensive RPC call a second time.
385     dwReturnValue = GetPrinterDataExW(hPrinter, pwszKeyName, pwszValueName, pType, pData, nSize, pcbNeeded);
386 
387     // If a critical error occurred, just return it. We cannot do anything else in this case.
388     if (dwReturnValue != ERROR_SUCCESS && dwReturnValue != ERROR_MORE_DATA)
389         goto Cleanup;
390 
391     // Save the needed buffer size for the Unicode data. We may alter *pcbNeeded for an ANSI buffer size.
392     cbUnicodeData = *pcbNeeded;
393 
394     if (*pType == REG_SZ || *pType == REG_MULTI_SZ || *pType == REG_EXPAND_SZ)
395     {
396         // This is a string that needs to be converted from Unicode to ANSI.
397         // Output the required buffer size for the ANSI string.
398         *pcbNeeded /= sizeof(WCHAR);
399     }
400     else if (*pType == REG_NONE)
401     {
402         if (cbUnicodeData == sizeof(OSVERSIONINFOW) && _wcsicmp(pwszValueName, SPLREG_OS_VERSION) == 0)
403         {
404             // This is a Unicode OSVERSIONINFOW structure that needs to be converted to an ANSI OSVERSIONINFOA.
405             *pcbNeeded = sizeof(OSVERSIONINFOA);
406         }
407         else if (cbUnicodeData == sizeof(OSVERSIONINFOEXW) && _wcsicmp(pwszValueName, SPLREG_OS_VERSIONEX) == 0)
408         {
409             // This is a Unicode OSVERSIONINFOEXW structure that needs to be converted to an ANSI OSVERSIONINFOEXA.
410             *pcbNeeded = sizeof(OSVERSIONINFOEXA);
411         }
412         else
413         {
414             // Other REG_NONE value, nothing to do.
415             goto Cleanup;
416         }
417     }
418 
419     // Check if the supplied buffer is large enough for the ANSI data.
420     if (nSize < *pcbNeeded)
421     {
422         dwReturnValue = ERROR_MORE_DATA;
423         goto Cleanup;
424     }
425 
426     // Allocate a temporary buffer for the Unicode data.
427     pUnicodeData = HeapAlloc(hProcessHeap, 0, cbUnicodeData);
428     if (!pUnicodeData)
429     {
430         dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
431         ERR("HeapAlloc failed!\n");
432         goto Cleanup;
433     }
434 
435     if (dwReturnValue == ERROR_SUCCESS)
436     {
437         // ERROR_SUCCESS: The buffer is large enough for the ANSI and the Unicode string,
438         // so the Unicode string has been copied into pData. Copy it to pUnicodeData.
439         CopyMemory(pUnicodeData, pData, cbUnicodeData);
440     }
441     else
442     {
443         // ERROR_MORE_DATA: The buffer is large enough for the ANSI string, but not for the Unicode string.
444         // We have to call GetPrinterDataExW again with the temporary buffer.
445         dwReturnValue = GetPrinterDataExW(hPrinter, pwszKeyName, pwszValueName, NULL, (PBYTE)pUnicodeData, cbUnicodeData, &cbUnicodeData);
446         if (dwReturnValue != ERROR_SUCCESS)
447             goto Cleanup;
448     }
449 
450     if (*pType == REG_SZ || *pType == REG_MULTI_SZ || *pType == REG_EXPAND_SZ)
451     {
452         // Convert the Unicode string to ANSI.
453         WideCharToMultiByte(CP_ACP, 0, (PWSTR)pUnicodeData, -1, (PSTR)pData, *pcbNeeded, NULL, NULL);
454     }
455     else
456     {
457         // This is a REG_NONE with either OSVERSIONINFOW or OSVERSIONINFOEXW.
458         // Copy the fields and convert the Unicode CSD Version string to ANSI.
459         pInfoW = (POSVERSIONINFOEXW)pUnicodeData;
460         pInfoA = (POSVERSIONINFOEXA)pData;
461         pInfoA->dwMajorVersion = pInfoW->dwMajorVersion;
462         pInfoA->dwMinorVersion = pInfoW->dwMinorVersion;
463         pInfoA->dwBuildNumber = pInfoW->dwBuildNumber;
464         pInfoA->dwPlatformId = pInfoW->dwPlatformId;
465         WideCharToMultiByte(CP_ACP, 0, pInfoW->szCSDVersion, -1, pInfoA->szCSDVersion, sizeof(pInfoA->szCSDVersion), NULL, NULL);
466 
467         if (cbUnicodeData == sizeof(OSVERSIONINFOW))
468         {
469             pInfoA->dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
470         }
471         else
472         {
473             pInfoA->dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXA);
474             pInfoA->wServicePackMajor = pInfoW->wServicePackMajor;
475             pInfoA->wServicePackMinor = pInfoW->wServicePackMinor;
476             pInfoA->wSuiteMask = pInfoW->wSuiteMask;
477             pInfoA->wProductType = pInfoW->wProductType;
478             pInfoA->wReserved = pInfoW->wReserved;
479         }
480     }
481 
482 Cleanup:
483     if (pwszKeyName)
484         HeapFree(hProcessHeap, 0, pwszKeyName);
485 
486     if (pwszValueName)
487         HeapFree(hProcessHeap, 0, pwszValueName);
488 
489     if (pUnicodeData)
490         HeapFree(hProcessHeap, 0, pUnicodeData);
491 
492     return dwReturnValue;
493 }
494 
495 DWORD WINAPI
496 GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName, LPCWSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
497 {
498     const WCHAR wszEmptyString[] = L"";
499 
500     BYTE DummyData;
501     DWORD dwErrorCode;
502     DWORD dwType = REG_NONE;
503     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
504 
505     TRACE("GetPrinterDataExW(%p, %S, %S, %p, %p, %lu, %p)\n", hPrinter, pKeyName, pValueName, pType, pData, nSize, pcbNeeded);
506 
507     // Sanity checks
508     if (!pHandle)
509         return ERROR_INVALID_HANDLE;
510 
511     // Yes, instead of declaring these pointers unique in the IDL file (and perfectly accepting NULL pointers this way),
512     // Windows does it differently for GetPrinterDataExW and points them to empty variables.
513     if (!pKeyName)
514         pKeyName = wszEmptyString;
515 
516     if (!pType)
517         pType = &dwType;
518 
519     if (!pData && !nSize)
520         pData = &DummyData;
521 
522     // Do the RPC call
523     RpcTryExcept
524     {
525         dwErrorCode = _RpcGetPrinterDataEx(pHandle->hPrinter, pKeyName, pValueName, pType, pData, nSize, pcbNeeded);
526     }
527     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
528     {
529         dwErrorCode = RpcExceptionCode();
530     }
531     RpcEndExcept;
532 
533     return dwErrorCode;
534 }
535 
536 DWORD WINAPI
537 GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
538 {
539     TRACE("GetPrinterDataW(%p, %S, %p, %p, %lu, %p)\n", hPrinter, pValueName, pType, pData, nSize, pcbNeeded);
540     return GetPrinterDataExW(hPrinter, L"PrinterDriverData", pValueName, pType, pData, nSize, pcbNeeded);
541 }
542 
543 DWORD WINAPI
544 SetPrinterDataA(HANDLE hPrinter, PSTR pValueName, DWORD Type, PBYTE pData, DWORD cbData)
545 {
546     TRACE("SetPrinterDataA(%p, %s, %lu, %p, %lu)\n", hPrinter, pValueName, Type, pData, cbData);
547     return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type, pData, cbData);
548 }
549 
550 DWORD WINAPI
551 SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName, LPCSTR pValueName, DWORD Type, LPBYTE pData, DWORD cbData)
552 {
553     DWORD cch;
554     DWORD dwReturnValue;
555     PWSTR pwszKeyName = NULL;
556     PWSTR pwszValueName = NULL;
557     PWSTR pUnicodeData = NULL;
558 
559     TRACE("SetPrinterDataExA(%p, %s, %s, %lu, %p, %lu)\n", hPrinter, pKeyName, pValueName, Type, pData, cbData);
560 
561     if (pKeyName)
562     {
563         // Convert pKeyName to a Unicode string pwszKeyName
564         cch = strlen(pKeyName);
565 
566         pwszKeyName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
567         if (!pwszKeyName)
568         {
569             dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
570             ERR("HeapAlloc failed!\n");
571             goto Cleanup;
572         }
573 
574         MultiByteToWideChar(CP_ACP, 0, pKeyName, -1, pwszKeyName, cch + 1);
575     }
576 
577     if (pValueName)
578     {
579         // Convert pValueName to a Unicode string pwszValueName
580         cch = strlen(pValueName);
581 
582         pwszValueName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
583         if (!pwszValueName)
584         {
585             dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
586             ERR("HeapAlloc failed!\n");
587             goto Cleanup;
588         }
589 
590         MultiByteToWideChar(CP_ACP, 0, pValueName, -1, pwszValueName, cch + 1);
591     }
592 
593     if (Type == REG_SZ || Type == REG_MULTI_SZ || Type == REG_EXPAND_SZ)
594     {
595         // Convert pData to a Unicode string pUnicodeData.
596         pUnicodeData = HeapAlloc(hProcessHeap, 0, cbData * sizeof(WCHAR));
597         if (!pUnicodeData)
598         {
599             dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
600             ERR("HeapAlloc failed!\n");
601             goto Cleanup;
602         }
603 
604         MultiByteToWideChar(CP_ACP, 0, (PCSTR)pData, -1, pUnicodeData, cbData);
605 
606         pData = (PBYTE)pUnicodeData;
607         cbData *= sizeof(WCHAR);
608     }
609 
610     dwReturnValue = SetPrinterDataExW(hPrinter, pwszKeyName, pwszValueName, Type, pData, cbData);
611 
612 Cleanup:
613     if (pwszKeyName)
614         HeapFree(hProcessHeap, 0, pwszKeyName);
615 
616     if (pwszValueName)
617         HeapFree(hProcessHeap, 0, pwszValueName);
618 
619     if (pUnicodeData)
620         HeapFree(hProcessHeap, 0, pUnicodeData);
621 
622     return dwReturnValue;
623 }
624 
625 DWORD WINAPI
626 SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName, LPCWSTR pValueName, DWORD Type, LPBYTE pData, DWORD cbData)
627 {
628     const WCHAR wszEmptyString[] = L"";
629 
630     DWORD dwErrorCode;
631     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
632 
633     TRACE("SetPrinterDataExW(%p, %S, %S, %lu, %p, %lu)\n", hPrinter, pKeyName, pValueName, Type, pData, cbData);
634 
635     // Sanity checks
636     if (!pHandle)
637         return ERROR_INVALID_HANDLE;
638 
639     if (!pKeyName)
640         pKeyName = wszEmptyString;
641 
642     // Do the RPC call
643     RpcTryExcept
644     {
645         dwErrorCode = _RpcSetPrinterDataEx(pHandle->hPrinter, pKeyName, pValueName, Type, pData, cbData);
646     }
647     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
648     {
649         dwErrorCode = RpcExceptionCode();
650     }
651     RpcEndExcept;
652 
653     return dwErrorCode;
654 }
655 
656 DWORD WINAPI
657 SetPrinterDataW(HANDLE hPrinter, PWSTR pValueName, DWORD Type, PBYTE pData, DWORD cbData)
658 {
659     TRACE("SetPrinterDataW(%p, %S, %lu, %p, %lu)\n", hPrinter, pValueName, Type, pData, cbData);
660     return SetPrinterDataExW(hPrinter, L"PrinterDriverData", pValueName, Type, pData, cbData);
661 }
662