90806422b8fb4ec1f1f08e7ba47dd71693443b4d
[reactos.git] / reactos / win32ss / printing / base / winspool / printerdata.c
1 /*
2 * PROJECT: ReactOS Spooler API
3 * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
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 AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, PWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
12 {
13 UNIMPLEMENTED;
14 return FALSE;
15 }
16
17 DWORD WINAPI
18 GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
19 {
20 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType, pData, nSize, pcbNeeded);
21 }
22
23 DWORD WINAPI
24 GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName, LPCSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
25 {
26 DWORD cbUnicodeData;
27 DWORD cch;
28 DWORD dwReturnValue;
29 DWORD dwType;
30 POSVERSIONINFOEXA pInfoA;
31 POSVERSIONINFOEXW pInfoW;
32 PVOID pUnicodeData = NULL;
33 PWSTR pwszKeyName = NULL;
34 PWSTR pwszValueName = NULL;
35
36 if (pKeyName)
37 {
38 // Convert pKeyName to a Unicode string pwszKeyName
39 cch = strlen(pKeyName);
40
41 pwszKeyName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
42 if (!pwszKeyName)
43 {
44 dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
45 ERR("HeapAlloc failed!\n");
46 goto Cleanup;
47 }
48
49 MultiByteToWideChar(CP_ACP, 0, pKeyName, -1, pwszKeyName, cch + 1);
50 }
51
52 if (pValueName)
53 {
54 // Convert pValueName to a Unicode string pwszValueName
55 cch = strlen(pValueName);
56
57 pwszValueName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
58 if (!pwszValueName)
59 {
60 dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
61 ERR("HeapAlloc failed!\n");
62 goto Cleanup;
63 }
64
65 MultiByteToWideChar(CP_ACP, 0, pValueName, -1, pwszValueName, cch + 1);
66 }
67
68 // We need the data type information, even if no pData was passed.
69 if (!pType)
70 pType = &dwType;
71
72 // Call GetPrinterDataExW for the first time.
73 // 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.
74 dwReturnValue = GetPrinterDataExW(hPrinter, pwszKeyName, pwszValueName, pType, pData, nSize, pcbNeeded);
75
76 // If a critical error occurred, just return it. We cannot do anything else in this case.
77 if (dwReturnValue != ERROR_SUCCESS && dwReturnValue != ERROR_MORE_DATA)
78 goto Cleanup;
79
80 // Save the needed buffer size for the Unicode data. We may alter *pcbNeeded for an ANSI buffer size.
81 cbUnicodeData = *pcbNeeded;
82
83 if (*pType == REG_SZ || *pType == REG_MULTI_SZ || *pType == REG_EXPAND_SZ)
84 {
85 // This is a string that needs to be converted from Unicode to ANSI.
86 // Output the required buffer size for the ANSI string.
87 *pcbNeeded /= sizeof(WCHAR);
88 }
89 else if (*pType == REG_NONE)
90 {
91 if (cbUnicodeData == sizeof(OSVERSIONINFOW) && wcsicmp(pwszValueName, SPLREG_OS_VERSION) == 0)
92 {
93 // This is a Unicode OSVERSIONINFOW structure that needs to be converted to an ANSI OSVERSIONINFOA.
94 *pcbNeeded = sizeof(OSVERSIONINFOA);
95 }
96 else if (cbUnicodeData == sizeof(OSVERSIONINFOEXW) && wcsicmp(pwszValueName, SPLREG_OS_VERSIONEX) == 0)
97 {
98 // This is a Unicode OSVERSIONINFOEXW structure that needs to be converted to an ANSI OSVERSIONINFOEXA.
99 *pcbNeeded = sizeof(OSVERSIONINFOEXA);
100 }
101 else
102 {
103 // Other REG_NONE value, nothing to do.
104 goto Cleanup;
105 }
106 }
107
108 // Check if the supplied buffer is large enough for the ANSI data.
109 if (nSize < *pcbNeeded)
110 {
111 dwReturnValue = ERROR_MORE_DATA;
112 goto Cleanup;
113 }
114
115 // Allocate a temporary buffer for the Unicode data.
116 pUnicodeData = HeapAlloc(hProcessHeap, 0, cbUnicodeData);
117 if (!pUnicodeData)
118 {
119 dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
120 ERR("HeapAlloc failed!\n");
121 goto Cleanup;
122 }
123
124 if (dwReturnValue == ERROR_SUCCESS)
125 {
126 // ERROR_SUCCESS: The buffer is large enough for the ANSI and the Unicode string,
127 // so the Unicode string has been copied into pData. Copy it to pUnicodeData.
128 CopyMemory(pUnicodeData, pData, cbUnicodeData);
129 }
130 else
131 {
132 // ERROR_MORE_DATA: The buffer is large enough for the ANSI string, but not for the Unicode string.
133 // We have to call GetPrinterDataExW again with the temporary buffer.
134 dwReturnValue = GetPrinterDataExW(hPrinter, pwszKeyName, pwszValueName, NULL, (PBYTE)pUnicodeData, cbUnicodeData, &cbUnicodeData);
135 if (dwReturnValue != ERROR_SUCCESS)
136 goto Cleanup;
137 }
138
139 if (*pType == REG_SZ || *pType == REG_MULTI_SZ || *pType == REG_EXPAND_SZ)
140 {
141 // Convert the Unicode string to ANSI.
142 WideCharToMultiByte(CP_ACP, 0, (PWSTR)pUnicodeData, -1, (PSTR)pData, *pcbNeeded, NULL, NULL);
143 }
144 else
145 {
146 // This is a REG_NONE with either OSVERSIONINFOW or OSVERSIONINFOEXW.
147 // Copy the fields and convert the Unicode CSD Version string to ANSI.
148 pInfoW = (POSVERSIONINFOEXW)pUnicodeData;
149 pInfoA = (POSVERSIONINFOEXA)pData;
150 pInfoA->dwMajorVersion = pInfoW->dwMajorVersion;
151 pInfoA->dwMinorVersion = pInfoW->dwMinorVersion;
152 pInfoA->dwBuildNumber = pInfoW->dwBuildNumber;
153 pInfoA->dwPlatformId = pInfoW->dwPlatformId;
154 WideCharToMultiByte(CP_ACP, 0, pInfoW->szCSDVersion, -1, pInfoA->szCSDVersion, sizeof(pInfoA->szCSDVersion), NULL, NULL);
155
156 if (cbUnicodeData == sizeof(OSVERSIONINFOW))
157 {
158 pInfoA->dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
159 }
160 else
161 {
162 pInfoA->dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXA);
163 pInfoA->wServicePackMajor = pInfoW->wServicePackMajor;
164 pInfoA->wServicePackMinor = pInfoW->wServicePackMinor;
165 pInfoA->wSuiteMask = pInfoW->wSuiteMask;
166 pInfoA->wProductType = pInfoW->wProductType;
167 pInfoA->wReserved = pInfoW->wReserved;
168 }
169 }
170
171 Cleanup:
172 if (pwszKeyName)
173 HeapFree(hProcessHeap, 0, pwszKeyName);
174
175 if (pwszValueName)
176 HeapFree(hProcessHeap, 0, pwszValueName);
177
178 if (pUnicodeData)
179 HeapFree(hProcessHeap, 0, pUnicodeData);
180
181 return dwReturnValue;
182 }
183
184 DWORD WINAPI
185 GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName, LPCWSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
186 {
187 const WCHAR wszEmptyString[] = L"";
188
189 BYTE DummyData;
190 DWORD dwErrorCode;
191 DWORD dwType = REG_NONE;
192 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
193
194 // Sanity checks
195 if (!pHandle)
196 return ERROR_INVALID_HANDLE;
197
198 // Yes, instead of declaring these pointers unique in the IDL file (and perfectly accepting NULL pointers this way),
199 // Windows does it differently for GetPrinterDataExW and points them to empty variables.
200 if (!pKeyName)
201 pKeyName = wszEmptyString;
202
203 if (!pType)
204 pType = &dwType;
205
206 if (!pData && !nSize)
207 pData = &DummyData;
208
209 // Do the RPC call
210 RpcTryExcept
211 {
212 dwErrorCode = _RpcGetPrinterDataEx(pHandle->hPrinter, pKeyName, pValueName, pType, pData, nSize, pcbNeeded);
213 }
214 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
215 {
216 dwErrorCode = RpcExceptionCode();
217 }
218 RpcEndExcept;
219
220 return dwErrorCode;
221 }
222
223 DWORD WINAPI
224 GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
225 {
226 return GetPrinterDataExW(hPrinter, L"PrinterDriverData", pValueName, pType, pData, nSize, pcbNeeded);
227 }
228
229 DWORD WINAPI
230 SetPrinterDataA(HANDLE hPrinter, PSTR pValueName, DWORD Type, PBYTE pData, DWORD cbData)
231 {
232 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type, pData, cbData);
233 }
234
235 DWORD WINAPI
236 SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName, LPCSTR pValueName, DWORD Type, LPBYTE pData, DWORD cbData)
237 {
238 DWORD cch;
239 DWORD dwReturnValue;
240 PWSTR pwszKeyName = NULL;
241 PWSTR pwszValueName = NULL;
242 PWSTR pUnicodeData = NULL;
243
244 if (pKeyName)
245 {
246 // Convert pKeyName to a Unicode string pwszKeyName
247 cch = strlen(pKeyName);
248
249 pwszKeyName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
250 if (!pwszKeyName)
251 {
252 dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
253 ERR("HeapAlloc failed!\n");
254 goto Cleanup;
255 }
256
257 MultiByteToWideChar(CP_ACP, 0, pKeyName, -1, pwszKeyName, cch + 1);
258 }
259
260 if (pValueName)
261 {
262 // Convert pValueName to a Unicode string pwszValueName
263 cch = strlen(pValueName);
264
265 pwszValueName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
266 if (!pwszValueName)
267 {
268 dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
269 ERR("HeapAlloc failed!\n");
270 goto Cleanup;
271 }
272
273 MultiByteToWideChar(CP_ACP, 0, pValueName, -1, pwszValueName, cch + 1);
274 }
275
276 if (Type == REG_SZ || Type == REG_MULTI_SZ || Type == REG_EXPAND_SZ)
277 {
278 // Convert pData to a Unicode string pUnicodeData.
279 pUnicodeData = HeapAlloc(hProcessHeap, 0, cbData * sizeof(WCHAR));
280 if (!pUnicodeData)
281 {
282 dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
283 ERR("HeapAlloc failed!\n");
284 goto Cleanup;
285 }
286
287 MultiByteToWideChar(CP_ACP, 0, (PCSTR)pData, -1, pUnicodeData, cbData);
288
289 pData = (PBYTE)pUnicodeData;
290 cbData *= sizeof(WCHAR);
291 }
292
293 dwReturnValue = SetPrinterDataExW(hPrinter, pwszKeyName, pwszValueName, Type, pData, cbData);
294
295 Cleanup:
296 if (pwszKeyName)
297 HeapFree(hProcessHeap, 0, pwszKeyName);
298
299 if (pwszValueName)
300 HeapFree(hProcessHeap, 0, pwszValueName);
301
302 if (pUnicodeData)
303 HeapFree(hProcessHeap, 0, pUnicodeData);
304
305 return dwReturnValue;
306 }
307
308 DWORD WINAPI
309 SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName, LPCWSTR pValueName, DWORD Type, LPBYTE pData, DWORD cbData)
310 {
311 const WCHAR wszEmptyString[] = L"";
312
313 DWORD dwErrorCode;
314 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
315
316 // Sanity checks
317 if (!pHandle)
318 return ERROR_INVALID_HANDLE;
319
320 if (!pKeyName)
321 pKeyName = wszEmptyString;
322
323 // Do the RPC call
324 RpcTryExcept
325 {
326 dwErrorCode = _RpcSetPrinterDataEx(pHandle->hPrinter, pKeyName, pValueName, Type, pData, cbData);
327 }
328 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
329 {
330 dwErrorCode = RpcExceptionCode();
331 }
332 RpcEndExcept;
333
334 return dwErrorCode;
335 }
336
337 DWORD WINAPI
338 SetPrinterDataW(HANDLE hPrinter, PWSTR pValueName, DWORD Type, PBYTE pData, DWORD cbData)
339 {
340 return SetPrinterDataExW(hPrinter, L"PrinterDriverData", pValueName, Type, pData, cbData);
341 }