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
AdvancedSetupDialog(HWND hWnd,INT Unknown,PDEVMODEA pDevModeInput,PDEVMODEA pDevModeOutput)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
AdvancedDocumentPropertiesA(HWND hWnd,HANDLE hPrinter,PSTR pDeviceName,PDEVMODEA pDevModeOutput,PDEVMODEA pDevModeInput)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
AdvancedDocumentPropertiesW(HWND hWnd,HANDLE hPrinter,PWSTR pDeviceName,PDEVMODEW pDevModeOutput,PDEVMODEW pDevModeInput)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
DeletePrinterDataA(HANDLE hPrinter,PSTR pValueName)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
DeletePrinterDataExA(HANDLE hPrinter,PCSTR pKeyName,PCSTR pValueName)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
DeletePrinterDataExW(HANDLE hPrinter,PCWSTR pKeyName,PCWSTR pValueName)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
DeletePrinterDataW(HANDLE hPrinter,PWSTR pValueName)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
DeletePrinterKeyA(HANDLE hPrinter,PCSTR pKeyName)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
DeletePrinterKeyW(HANDLE hPrinter,PCWSTR pKeyName)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
EnumPrinterDataA(HANDLE hPrinter,DWORD dwIndex,PSTR pValueName,DWORD cbValueName,PDWORD pcbValueName,PDWORD pType,PBYTE pData,DWORD cbData,PDWORD pcbData)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
EnumPrinterDataExA(HANDLE hPrinter,PCSTR pKeyName,PBYTE pEnumValues,DWORD cbEnumValues,PDWORD pcbEnumValues,PDWORD pnEnumValues)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
EnumPrinterDataExW(HANDLE hPrinter,PCWSTR pKeyName,PBYTE pEnumValues,DWORD cbEnumValues,PDWORD pcbEnumValues,PDWORD pnEnumValues)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
EnumPrinterDataW(HANDLE hPrinter,DWORD dwIndex,PWSTR pValueName,DWORD cbValueName,PDWORD pcbValueName,PDWORD pType,PBYTE pData,DWORD cbData,PDWORD pcbData)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
EnumPrinterKeyA(HANDLE hPrinter,PCSTR pKeyName,PSTR pSubkey,DWORD cbSubkey,PDWORD pcbSubkey)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
EnumPrinterKeyW(HANDLE hPrinter,PCWSTR pKeyName,PWSTR pSubkey,DWORD cbSubkey,PDWORD pcbSubkey)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
GetPrinterDataA(HANDLE hPrinter,LPSTR pValueName,LPDWORD pType,LPBYTE pData,DWORD nSize,LPDWORD pcbNeeded)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
GetPrinterDataExA(HANDLE hPrinter,LPCSTR pKeyName,LPCSTR pValueName,LPDWORD pType,LPBYTE pData,DWORD nSize,LPDWORD pcbNeeded)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
GetPrinterDataExW(HANDLE hPrinter,LPCWSTR pKeyName,LPCWSTR pValueName,LPDWORD pType,LPBYTE pData,DWORD nSize,LPDWORD pcbNeeded)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
GetPrinterDataW(HANDLE hPrinter,LPWSTR pValueName,LPDWORD pType,LPBYTE pData,DWORD nSize,LPDWORD pcbNeeded)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
SetPrinterDataA(HANDLE hPrinter,PSTR pValueName,DWORD Type,PBYTE pData,DWORD cbData)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
SetPrinterDataExA(HANDLE hPrinter,LPCSTR pKeyName,LPCSTR pValueName,DWORD Type,LPBYTE pData,DWORD cbData)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
SetPrinterDataExW(HANDLE hPrinter,LPCWSTR pKeyName,LPCWSTR pValueName,DWORD Type,LPBYTE pData,DWORD cbData)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
SetPrinterDataW(HANDLE hPrinter,PWSTR pValueName,DWORD Type,PBYTE pData,DWORD cbData)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