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