[LOCALUI] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / win32ss / printing / base / winspool / printerdata.c
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 }