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 AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, PSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
12 {
13     TRACE("AdvancedDocumentPropertiesA(%p, %p, %s, %p, %p)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput);
14     UNIMPLEMENTED;
15     return 0;
16 }
17 
18 LONG WINAPI
19 AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, PWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
20 {
21     TRACE("AdvancedDocumentPropertiesW(%p, %p, %S, %p, %p)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput);
22     UNIMPLEMENTED;
23     return 0;
24 }
25 
26 DWORD WINAPI
27 DeletePrinterDataA(HANDLE hPrinter, PSTR pValueName)
28 {
29     TRACE("DeletePrinterDataA(%p, %s)\n", hPrinter, pValueName);
30     UNIMPLEMENTED;
31     return ERROR_NOT_SUPPORTED;
32 }
33 
34 DWORD WINAPI
35 DeletePrinterDataExA(HANDLE hPrinter, PCSTR pKeyName, PCSTR pValueName)
36 {
37     TRACE("DeletePrinterDataExA(%p, %s, %s)\n", hPrinter, pKeyName, pValueName);
38     UNIMPLEMENTED;
39     return ERROR_NOT_SUPPORTED;
40 }
41 
42 DWORD WINAPI
43 DeletePrinterDataExW(HANDLE hPrinter, PCWSTR pKeyName, PCWSTR pValueName)
44 {
45     TRACE("DeletePrinterDataExW(%p, %S, %S)\n", hPrinter, pKeyName, pValueName);
46     UNIMPLEMENTED;
47     return ERROR_NOT_SUPPORTED;
48 }
49 
50 DWORD WINAPI
51 DeletePrinterDataW(HANDLE hPrinter, PWSTR pValueName)
52 {
53     TRACE("DeletePrinterDataW(%p, %S)\n", hPrinter, pValueName);
54     UNIMPLEMENTED;
55     return ERROR_NOT_SUPPORTED;
56 }
57 
58 DWORD WINAPI
59 DeletePrinterKeyA(HANDLE hPrinter, PCSTR pKeyName)
60 {
61     TRACE("DeletePrinterKeyA(%p, %s)\n", hPrinter, pKeyName);
62     UNIMPLEMENTED;
63     return ERROR_NOT_SUPPORTED;
64 }
65 
66 DWORD WINAPI
67 DeletePrinterKeyW(HANDLE hPrinter, PCWSTR pKeyName)
68 {
69     TRACE("DeletePrinterKeyW(%p, %S)\n", hPrinter, pKeyName);
70     UNIMPLEMENTED;
71     return ERROR_NOT_SUPPORTED;
72 }
73 
74 DWORD WINAPI
75 EnumPrinterDataA(HANDLE hPrinter, DWORD dwIndex, PSTR pValueName, DWORD cbValueName, PDWORD pcbValueName, PDWORD pType, PBYTE pData, DWORD cbData, PDWORD pcbData)
76 {
77     TRACE("EnumPrinterDataA(%p, %lu, %s, %lu, %p, %p, %p, %lu, %p)\n", hPrinter, dwIndex, pValueName, cbValueName, pcbValueName, pType, pData, cbData, pcbData);
78     UNIMPLEMENTED;
79     return ERROR_NOT_SUPPORTED;
80 }
81 
82 DWORD WINAPI
83 EnumPrinterDataExA(HANDLE hPrinter, PCSTR pKeyName, PBYTE pEnumValues, DWORD cbEnumValues, PDWORD pcbEnumValues, PDWORD pnEnumValues)
84 {
85     TRACE("EnumPrinterDataExA(%p, %s, %p, %lu, %p, %p)\n", hPrinter, pKeyName, pEnumValues, cbEnumValues, pcbEnumValues, pnEnumValues);
86     UNIMPLEMENTED;
87     return ERROR_NOT_SUPPORTED;
88 }
89 
90 DWORD WINAPI
91 EnumPrinterDataExW(HANDLE hPrinter, PCWSTR pKeyName, PBYTE pEnumValues, DWORD cbEnumValues, PDWORD pcbEnumValues, PDWORD pnEnumValues)
92 {
93     TRACE("EnumPrinterDataExW(%p, %S, %p, %lu, %p, %p)\n", hPrinter, pKeyName, pEnumValues, cbEnumValues, pcbEnumValues, pnEnumValues);
94     UNIMPLEMENTED;
95     return ERROR_NOT_SUPPORTED;
96 }
97 
98 DWORD WINAPI
99 EnumPrinterDataW(HANDLE hPrinter, DWORD dwIndex, PWSTR pValueName, DWORD cbValueName, PDWORD pcbValueName, PDWORD pType, PBYTE pData, DWORD cbData, PDWORD pcbData)
100 {
101     TRACE("EnumPrinterDataW(%p, %lu, %S, %lu, %p, %p, %p, %lu, %p)\n", hPrinter, dwIndex, pValueName, cbValueName, pcbValueName, pType, pData, cbData, pcbData);
102     UNIMPLEMENTED;
103     return ERROR_NOT_SUPPORTED;
104 }
105 
106 DWORD WINAPI
107 EnumPrinterKeyA(HANDLE hPrinter, PCSTR pKeyName, PSTR pSubkey, DWORD cbSubkey, PDWORD pcbSubkey)
108 {
109     TRACE("EnumPrinterKeyA(%p, %s, %s, %lu, %p)\n", hPrinter, pKeyName, pSubkey, cbSubkey, pcbSubkey);
110     UNIMPLEMENTED;
111     return ERROR_NOT_SUPPORTED;
112 }
113 
114 DWORD WINAPI
115 EnumPrinterKeyW(HANDLE hPrinter, PCWSTR pKeyName, PWSTR pSubkey, DWORD cbSubkey, PDWORD pcbSubkey)
116 {
117     TRACE("EnumPrinterKeyW(%p, %S, %S, %lu, %p)\n", hPrinter, pKeyName, pSubkey, cbSubkey, pcbSubkey);
118     UNIMPLEMENTED;
119     return ERROR_NOT_SUPPORTED;
120 }
121 
122 DWORD WINAPI
123 GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
124 {
125     TRACE("GetPrinterDataA(%p, %s, %p, %p, %lu, %p)\n", hPrinter, pValueName, pType, pData, nSize, pcbNeeded);
126     return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType, pData, nSize, pcbNeeded);
127 }
128 
129 DWORD WINAPI
130 GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName, LPCSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
131 {
132     DWORD cbUnicodeData;
133     DWORD cch;
134     DWORD dwReturnValue;
135     DWORD dwType;
136     POSVERSIONINFOEXA pInfoA;
137     POSVERSIONINFOEXW pInfoW;
138     PVOID pUnicodeData = NULL;
139     PWSTR pwszKeyName = NULL;
140     PWSTR pwszValueName = NULL;
141 
142     TRACE("GetPrinterDataExA(%p, %s, %s, %p, %p, %lu, %p)\n", hPrinter, pKeyName, pValueName, pType, pData, nSize, pcbNeeded);
143 
144     if (pKeyName)
145     {
146         // Convert pKeyName to a Unicode string pwszKeyName
147         cch = strlen(pKeyName);
148 
149         pwszKeyName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
150         if (!pwszKeyName)
151         {
152             dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
153             ERR("HeapAlloc failed!\n");
154             goto Cleanup;
155         }
156 
157         MultiByteToWideChar(CP_ACP, 0, pKeyName, -1, pwszKeyName, cch + 1);
158     }
159 
160     if (pValueName)
161     {
162         // Convert pValueName to a Unicode string pwszValueName
163         cch = strlen(pValueName);
164 
165         pwszValueName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
166         if (!pwszValueName)
167         {
168             dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
169             ERR("HeapAlloc failed!\n");
170             goto Cleanup;
171         }
172 
173         MultiByteToWideChar(CP_ACP, 0, pValueName, -1, pwszValueName, cch + 1);
174     }
175 
176     // We need the data type information, even if no pData was passed.
177     if (!pType)
178         pType = &dwType;
179 
180     // Call GetPrinterDataExW for the first time.
181     // 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.
182     dwReturnValue = GetPrinterDataExW(hPrinter, pwszKeyName, pwszValueName, pType, pData, nSize, pcbNeeded);
183 
184     // If a critical error occurred, just return it. We cannot do anything else in this case.
185     if (dwReturnValue != ERROR_SUCCESS && dwReturnValue != ERROR_MORE_DATA)
186         goto Cleanup;
187 
188     // Save the needed buffer size for the Unicode data. We may alter *pcbNeeded for an ANSI buffer size.
189     cbUnicodeData = *pcbNeeded;
190 
191     if (*pType == REG_SZ || *pType == REG_MULTI_SZ || *pType == REG_EXPAND_SZ)
192     {
193         // This is a string that needs to be converted from Unicode to ANSI.
194         // Output the required buffer size for the ANSI string.
195         *pcbNeeded /= sizeof(WCHAR);
196     }
197     else if (*pType == REG_NONE)
198     {
199         if (cbUnicodeData == sizeof(OSVERSIONINFOW) && wcsicmp(pwszValueName, SPLREG_OS_VERSION) == 0)
200         {
201             // This is a Unicode OSVERSIONINFOW structure that needs to be converted to an ANSI OSVERSIONINFOA.
202             *pcbNeeded = sizeof(OSVERSIONINFOA);
203         }
204         else if (cbUnicodeData == sizeof(OSVERSIONINFOEXW) && wcsicmp(pwszValueName, SPLREG_OS_VERSIONEX) == 0)
205         {
206             // This is a Unicode OSVERSIONINFOEXW structure that needs to be converted to an ANSI OSVERSIONINFOEXA.
207             *pcbNeeded = sizeof(OSVERSIONINFOEXA);
208         }
209         else
210         {
211             // Other REG_NONE value, nothing to do.
212             goto Cleanup;
213         }
214     }
215 
216     // Check if the supplied buffer is large enough for the ANSI data.
217     if (nSize < *pcbNeeded)
218     {
219         dwReturnValue = ERROR_MORE_DATA;
220         goto Cleanup;
221     }
222 
223     // Allocate a temporary buffer for the Unicode data.
224     pUnicodeData = HeapAlloc(hProcessHeap, 0, cbUnicodeData);
225     if (!pUnicodeData)
226     {
227         dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
228         ERR("HeapAlloc failed!\n");
229         goto Cleanup;
230     }
231 
232     if (dwReturnValue == ERROR_SUCCESS)
233     {
234         // ERROR_SUCCESS: The buffer is large enough for the ANSI and the Unicode string,
235         // so the Unicode string has been copied into pData. Copy it to pUnicodeData.
236         CopyMemory(pUnicodeData, pData, cbUnicodeData);
237     }
238     else
239     {
240         // ERROR_MORE_DATA: The buffer is large enough for the ANSI string, but not for the Unicode string.
241         // We have to call GetPrinterDataExW again with the temporary buffer.
242         dwReturnValue = GetPrinterDataExW(hPrinter, pwszKeyName, pwszValueName, NULL, (PBYTE)pUnicodeData, cbUnicodeData, &cbUnicodeData);
243         if (dwReturnValue != ERROR_SUCCESS)
244             goto Cleanup;
245     }
246 
247     if (*pType == REG_SZ || *pType == REG_MULTI_SZ || *pType == REG_EXPAND_SZ)
248     {
249         // Convert the Unicode string to ANSI.
250         WideCharToMultiByte(CP_ACP, 0, (PWSTR)pUnicodeData, -1, (PSTR)pData, *pcbNeeded, NULL, NULL);
251     }
252     else
253     {
254         // This is a REG_NONE with either OSVERSIONINFOW or OSVERSIONINFOEXW.
255         // Copy the fields and convert the Unicode CSD Version string to ANSI.
256         pInfoW = (POSVERSIONINFOEXW)pUnicodeData;
257         pInfoA = (POSVERSIONINFOEXA)pData;
258         pInfoA->dwMajorVersion = pInfoW->dwMajorVersion;
259         pInfoA->dwMinorVersion = pInfoW->dwMinorVersion;
260         pInfoA->dwBuildNumber = pInfoW->dwBuildNumber;
261         pInfoA->dwPlatformId = pInfoW->dwPlatformId;
262         WideCharToMultiByte(CP_ACP, 0, pInfoW->szCSDVersion, -1, pInfoA->szCSDVersion, sizeof(pInfoA->szCSDVersion), NULL, NULL);
263 
264         if (cbUnicodeData == sizeof(OSVERSIONINFOW))
265         {
266             pInfoA->dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
267         }
268         else
269         {
270             pInfoA->dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXA);
271             pInfoA->wServicePackMajor = pInfoW->wServicePackMajor;
272             pInfoA->wServicePackMinor = pInfoW->wServicePackMinor;
273             pInfoA->wSuiteMask = pInfoW->wSuiteMask;
274             pInfoA->wProductType = pInfoW->wProductType;
275             pInfoA->wReserved = pInfoW->wReserved;
276         }
277     }
278 
279 Cleanup:
280     if (pwszKeyName)
281         HeapFree(hProcessHeap, 0, pwszKeyName);
282 
283     if (pwszValueName)
284         HeapFree(hProcessHeap, 0, pwszValueName);
285 
286     if (pUnicodeData)
287         HeapFree(hProcessHeap, 0, pUnicodeData);
288 
289     return dwReturnValue;
290 }
291 
292 DWORD WINAPI
293 GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName, LPCWSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
294 {
295     const WCHAR wszEmptyString[] = L"";
296 
297     BYTE DummyData;
298     DWORD dwErrorCode;
299     DWORD dwType = REG_NONE;
300     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
301 
302     TRACE("GetPrinterDataExW(%p, %S, %S, %p, %p, %lu, %p)\n", hPrinter, pKeyName, pValueName, pType, pData, nSize, pcbNeeded);
303 
304     // Sanity checks
305     if (!pHandle)
306         return ERROR_INVALID_HANDLE;
307 
308     // Yes, instead of declaring these pointers unique in the IDL file (and perfectly accepting NULL pointers this way),
309     // Windows does it differently for GetPrinterDataExW and points them to empty variables.
310     if (!pKeyName)
311         pKeyName = wszEmptyString;
312 
313     if (!pType)
314         pType = &dwType;
315 
316     if (!pData && !nSize)
317         pData = &DummyData;
318 
319     // Do the RPC call
320     RpcTryExcept
321     {
322         dwErrorCode = _RpcGetPrinterDataEx(pHandle->hPrinter, pKeyName, pValueName, pType, pData, nSize, pcbNeeded);
323     }
324     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
325     {
326         dwErrorCode = RpcExceptionCode();
327     }
328     RpcEndExcept;
329 
330     return dwErrorCode;
331 }
332 
333 DWORD WINAPI
334 GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
335 {
336     TRACE("GetPrinterDataW(%p, %S, %p, %p, %lu, %p)\n", hPrinter, pValueName, pType, pData, nSize, pcbNeeded);
337     return GetPrinterDataExW(hPrinter, L"PrinterDriverData", pValueName, pType, pData, nSize, pcbNeeded);
338 }
339 
340 DWORD WINAPI
341 SetPrinterDataA(HANDLE hPrinter, PSTR pValueName, DWORD Type, PBYTE pData, DWORD cbData)
342 {
343     TRACE("SetPrinterDataA(%p, %s, %lu, %p, %lu)\n", hPrinter, pValueName, Type, pData, cbData);
344     return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type, pData, cbData);
345 }
346 
347 DWORD WINAPI
348 SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName, LPCSTR pValueName, DWORD Type, LPBYTE pData, DWORD cbData)
349 {
350     DWORD cch;
351     DWORD dwReturnValue;
352     PWSTR pwszKeyName = NULL;
353     PWSTR pwszValueName = NULL;
354     PWSTR pUnicodeData = NULL;
355 
356     TRACE("SetPrinterDataExA(%p, %s, %s, %lu, %p, %lu)\n", hPrinter, pKeyName, pValueName, Type, pData, cbData);
357 
358     if (pKeyName)
359     {
360         // Convert pKeyName to a Unicode string pwszKeyName
361         cch = strlen(pKeyName);
362 
363         pwszKeyName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
364         if (!pwszKeyName)
365         {
366             dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
367             ERR("HeapAlloc failed!\n");
368             goto Cleanup;
369         }
370 
371         MultiByteToWideChar(CP_ACP, 0, pKeyName, -1, pwszKeyName, cch + 1);
372     }
373 
374     if (pValueName)
375     {
376         // Convert pValueName to a Unicode string pwszValueName
377         cch = strlen(pValueName);
378 
379         pwszValueName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
380         if (!pwszValueName)
381         {
382             dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
383             ERR("HeapAlloc failed!\n");
384             goto Cleanup;
385         }
386 
387         MultiByteToWideChar(CP_ACP, 0, pValueName, -1, pwszValueName, cch + 1);
388     }
389 
390     if (Type == REG_SZ || Type == REG_MULTI_SZ || Type == REG_EXPAND_SZ)
391     {
392         // Convert pData to a Unicode string pUnicodeData.
393         pUnicodeData = HeapAlloc(hProcessHeap, 0, cbData * sizeof(WCHAR));
394         if (!pUnicodeData)
395         {
396             dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
397             ERR("HeapAlloc failed!\n");
398             goto Cleanup;
399         }
400 
401         MultiByteToWideChar(CP_ACP, 0, (PCSTR)pData, -1, pUnicodeData, cbData);
402 
403         pData = (PBYTE)pUnicodeData;
404         cbData *= sizeof(WCHAR);
405     }
406 
407     dwReturnValue = SetPrinterDataExW(hPrinter, pwszKeyName, pwszValueName, Type, pData, cbData);
408 
409 Cleanup:
410     if (pwszKeyName)
411         HeapFree(hProcessHeap, 0, pwszKeyName);
412 
413     if (pwszValueName)
414         HeapFree(hProcessHeap, 0, pwszValueName);
415 
416     if (pUnicodeData)
417         HeapFree(hProcessHeap, 0, pUnicodeData);
418 
419     return dwReturnValue;
420 }
421 
422 DWORD WINAPI
423 SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName, LPCWSTR pValueName, DWORD Type, LPBYTE pData, DWORD cbData)
424 {
425     const WCHAR wszEmptyString[] = L"";
426 
427     DWORD dwErrorCode;
428     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
429 
430     TRACE("SetPrinterDataExW(%p, %S, %S, %lu, %p, %lu)\n", hPrinter, pKeyName, pValueName, Type, pData, cbData);
431 
432     // Sanity checks
433     if (!pHandle)
434         return ERROR_INVALID_HANDLE;
435 
436     if (!pKeyName)
437         pKeyName = wszEmptyString;
438 
439     // Do the RPC call
440     RpcTryExcept
441     {
442         dwErrorCode = _RpcSetPrinterDataEx(pHandle->hPrinter, pKeyName, pValueName, Type, pData, cbData);
443     }
444     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
445     {
446         dwErrorCode = RpcExceptionCode();
447     }
448     RpcEndExcept;
449 
450     return dwErrorCode;
451 }
452 
453 DWORD WINAPI
454 SetPrinterDataW(HANDLE hPrinter, PWSTR pValueName, DWORD Type, PBYTE pData, DWORD cbData)
455 {
456     TRACE("SetPrinterDataW(%p, %S, %lu, %p, %lu)\n", hPrinter, pValueName, Type, pData, cbData);
457     return SetPrinterDataExW(hPrinter, L"PrinterDriverData", pValueName, Type, pData, cbData);
458 }
459