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 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 } 342