1 /* 2 * PROJECT: ReactOS Spooler API 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Functions related to Print Processors 5 * COPYRIGHT: Copyright 2015-2018 Colin Finck (colin@reactos.org) 6 */ 7 8 #include "precomp.h" 9 #include <marshalling/printprocessors.h> 10 #include <prtprocenv.h> 11 12 BOOL WINAPI 13 AddPrintProcessorA(PSTR pName, PSTR pEnvironment, PSTR pPathName, PSTR pPrintProcessorName) 14 { 15 UNICODE_STRING NameW, EnvW, PathW, ProcessorW; 16 BOOL Ret; 17 18 TRACE("AddPrintProcessorA(%s, %s, %s, %s)\n", pName, pEnvironment, pPathName, pPrintProcessorName); 19 20 AsciiToUnicode(&NameW, pName); 21 AsciiToUnicode(&EnvW, pEnvironment); 22 AsciiToUnicode(&PathW, pPathName); 23 AsciiToUnicode(&ProcessorW, pPrintProcessorName); 24 25 Ret = AddPrintProcessorW(NameW.Buffer, EnvW.Buffer, PathW.Buffer, ProcessorW.Buffer); 26 27 RtlFreeUnicodeString(&ProcessorW); 28 RtlFreeUnicodeString(&PathW); 29 RtlFreeUnicodeString(&EnvW); 30 RtlFreeUnicodeString(&NameW); 31 32 return Ret; 33 } 34 35 BOOL WINAPI 36 AddPrintProcessorW(PWSTR pName, PWSTR pEnvironment, PWSTR pPathName, PWSTR pPrintProcessorName) 37 { 38 DWORD dwErrorCode; 39 40 TRACE("AddPrintProcessorW(%S, %S, %S, %S)\n", pName, pEnvironment, pPathName, pPrintProcessorName); 41 42 RpcTryExcept 43 { 44 dwErrorCode = _RpcAddPrintProcessor( pName, pEnvironment, pPathName, pPrintProcessorName ); 45 } 46 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 47 { 48 dwErrorCode = RpcExceptionCode(); 49 ERR("_RpcPrintProcessor failed with exception code %lu!\n", dwErrorCode); 50 } 51 RpcEndExcept; 52 53 SetLastError(dwErrorCode); 54 return (dwErrorCode == ERROR_SUCCESS); 55 } 56 57 BOOL WINAPI 58 DeletePrintProcessorA(PSTR pName, PSTR pEnvironment, PSTR pPrintProcessorName) 59 { 60 UNICODE_STRING NameW, EnvW, ProcessorW; 61 BOOL Ret; 62 63 TRACE("DeletePrintProcessorA(%s, %s, %s)\n", pName, pEnvironment, pPrintProcessorName); 64 65 AsciiToUnicode(&NameW, pName); 66 AsciiToUnicode(&EnvW, pEnvironment); 67 AsciiToUnicode(&ProcessorW, pPrintProcessorName); 68 69 Ret = DeletePrintProcessorW(NameW.Buffer, EnvW.Buffer, ProcessorW.Buffer); 70 71 RtlFreeUnicodeString(&ProcessorW); 72 RtlFreeUnicodeString(&EnvW); 73 RtlFreeUnicodeString(&NameW); 74 75 return Ret; 76 } 77 78 BOOL WINAPI 79 DeletePrintProcessorW(PWSTR pName, PWSTR pEnvironment, PWSTR pPrintProcessorName) 80 { 81 DWORD dwErrorCode; 82 83 TRACE("DeletePrintProcessorW(%S, %S, %S)\n", pName, pEnvironment, pPrintProcessorName); 84 85 RpcTryExcept 86 { 87 dwErrorCode = _RpcDeletePrintProcessor( pName, pEnvironment, pPrintProcessorName ); 88 } 89 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 90 { 91 dwErrorCode = RpcExceptionCode(); 92 ERR("_RpcDeletePrintProcessor failed with exception code %lu!\n", dwErrorCode); 93 } 94 RpcEndExcept; 95 96 SetLastError(dwErrorCode); 97 return (dwErrorCode == ERROR_SUCCESS); 98 } 99 100 BOOL WINAPI 101 EnumPrintProcessorDatatypesA(PSTR pName, LPSTR pPrintProcessorName, DWORD Level, PBYTE pDatatypes, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) 102 { 103 TRACE("EnumPrintProcessorDatatypesA(%s, %s, %lu, %p, %lu, %p, %p)\n", pName, pPrintProcessorName, Level, pDatatypes, cbBuf, pcbNeeded, pcReturned); 104 UNIMPLEMENTED; 105 return FALSE; 106 } 107 108 BOOL WINAPI 109 EnumPrintProcessorDatatypesW(PWSTR pName, LPWSTR pPrintProcessorName, DWORD Level, PBYTE pDatatypes, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) 110 { 111 DWORD dwErrorCode; 112 113 TRACE("EnumPrintProcessorDatatypesW(%S, %S, %lu, %p, %lu, %p, %p)\n", pName, pPrintProcessorName, Level, pDatatypes, cbBuf, pcbNeeded, pcReturned); 114 115 // Sanity checks 116 if (Level != 1) 117 { 118 dwErrorCode = ERROR_INVALID_LEVEL; 119 goto Cleanup; 120 } 121 122 // Do the RPC call 123 RpcTryExcept 124 { 125 dwErrorCode = _RpcEnumPrintProcessorDatatypes(pName, pPrintProcessorName, Level, pDatatypes, cbBuf, pcbNeeded, pcReturned); 126 } 127 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 128 { 129 dwErrorCode = RpcExceptionCode(); 130 ERR("_RpcEnumPrintProcessorDatatypes failed with exception code %lu!\n", dwErrorCode); 131 } 132 RpcEndExcept; 133 134 if (dwErrorCode == ERROR_SUCCESS) 135 { 136 // Replace relative offset addresses in the output by absolute pointers. 137 MarshallUpStructuresArray(cbBuf, pDatatypes, *pcReturned, DatatypesInfo1Marshalling.pInfo, DatatypesInfo1Marshalling.cbStructureSize, TRUE); 138 } 139 140 Cleanup: 141 SetLastError(dwErrorCode); 142 return (dwErrorCode == ERROR_SUCCESS); 143 } 144 145 BOOL WINAPI 146 EnumPrintProcessorsA(PSTR pName, PSTR pEnvironment, DWORD Level, PBYTE pPrintProcessorInfo, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) 147 { 148 BOOL res; 149 LPBYTE bufferW = NULL; 150 LPWSTR nameW = NULL; 151 LPWSTR envW = NULL; 152 DWORD needed = 0; 153 DWORD numentries = 0; 154 INT len; 155 156 TRACE("EnumPrintProcessorsA(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment), Level, pPrintProcessorInfo, cbBuf, pcbNeeded, pcReturned); 157 158 /* convert names to unicode */ 159 if (pName) 160 { 161 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0); 162 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 163 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len); 164 } 165 if (pEnvironment) 166 { 167 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0); 168 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 169 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len); 170 } 171 172 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */ 173 needed = cbBuf * sizeof(WCHAR); 174 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed); 175 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned); 176 177 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) 178 { 179 if (pcbNeeded) needed = *pcbNeeded; 180 /* HeapReAlloc return NULL, when bufferW was NULL */ 181 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) : 182 HeapAlloc(GetProcessHeap(), 0, needed); 183 184 /* Try again with the large Buffer */ 185 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned); 186 } 187 numentries = pcReturned ? *pcReturned : 0; 188 needed = 0; 189 190 if (res) 191 { 192 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */ 193 DWORD index; 194 LPSTR ptr; 195 PPRINTPROCESSOR_INFO_1W ppiw; 196 PPRINTPROCESSOR_INFO_1A ppia; 197 198 /* First pass: calculate the size for all Entries */ 199 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW; 200 ppia = (PPRINTPROCESSOR_INFO_1A) pPrintProcessorInfo; 201 index = 0; 202 while (index < numentries) 203 { 204 index++; 205 needed += sizeof(PRINTPROCESSOR_INFO_1A); 206 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName)); 207 208 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1, 209 NULL, 0, NULL, NULL); 210 211 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W)); 212 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A)); 213 } 214 215 /* check for errors and quit on failure */ 216 if (cbBuf < needed) 217 { 218 SetLastError(ERROR_INSUFFICIENT_BUFFER); 219 res = FALSE; 220 goto epp_cleanup; 221 } 222 223 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */ 224 ptr = (LPSTR) &pPrintProcessorInfo[len]; /* start of strings */ 225 cbBuf -= len ; /* free Bytes in the user-Buffer */ 226 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW; 227 ppia = (PPRINTPROCESSOR_INFO_1A) pPrintProcessorInfo; 228 index = 0; 229 /* Second Pass: Fill the User Buffer (if we have one) */ 230 while ((index < numentries) && pPrintProcessorInfo) 231 { 232 index++; 233 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index); 234 ppia->pName = ptr; 235 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1, 236 ptr, cbBuf , NULL, NULL); 237 ptr += len; 238 cbBuf -= len; 239 240 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W)); 241 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A)); 242 243 } 244 } 245 epp_cleanup: 246 if (pcbNeeded) *pcbNeeded = needed; 247 if (pcReturned) *pcReturned = (res) ? numentries : 0; 248 249 if (nameW) HeapFree(GetProcessHeap(), 0, nameW); 250 if (envW) HeapFree(GetProcessHeap(), 0, envW); 251 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW); 252 253 TRACE("returning %d with %d (%d byte for %d entries)\n", (res), GetLastError(), needed, numentries); 254 255 return (res); 256 257 } 258 259 BOOL WINAPI 260 EnumPrintProcessorsW(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pPrintProcessorInfo, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) 261 { 262 DWORD dwErrorCode; 263 264 TRACE("EnumPrintProcessorsW(%S, %S, %lu, %p, %lu, %p, %p)\n", pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded, pcReturned); 265 266 // Choose our current environment if the caller didn't give any. 267 if (!pEnvironment) 268 pEnvironment = (PWSTR)wszCurrentEnvironment; 269 270 // Do the RPC call 271 RpcTryExcept 272 { 273 dwErrorCode = _RpcEnumPrintProcessors(pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded, pcReturned); 274 } 275 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 276 { 277 dwErrorCode = RpcExceptionCode(); 278 } 279 RpcEndExcept; 280 281 if (dwErrorCode == ERROR_SUCCESS) 282 { 283 // Replace relative offset addresses in the output by absolute pointers. 284 MarshallUpStructuresArray(cbBuf, pPrintProcessorInfo, *pcReturned, PrintProcessorInfo1Marshalling.pInfo, PrintProcessorInfo1Marshalling.cbStructureSize, TRUE); 285 } 286 287 SetLastError(dwErrorCode); 288 return (dwErrorCode == ERROR_SUCCESS); 289 } 290 291 BOOL WINAPI 292 GetPrintProcessorDirectoryA(PSTR pName, PSTR pEnvironment, DWORD Level, PBYTE pPrintProcessorInfo, DWORD cbBuf, PDWORD pcbNeeded) 293 { 294 BOOL bReturnValue = FALSE; 295 DWORD cch; 296 PWSTR pwszName = NULL; 297 PWSTR pwszEnvironment = NULL; 298 PWSTR pwszPrintProcessorInfo = NULL; 299 300 TRACE("GetPrintProcessorDirectoryA(%s, %s, %lu, %p, %lu, %p)\n", pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded); 301 302 if (pName) 303 { 304 // Convert pName to a Unicode string pwszName. 305 cch = strlen(pName); 306 307 pwszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 308 if (!pwszName) 309 { 310 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 311 ERR("HeapAlloc failed!\n"); 312 goto Cleanup; 313 } 314 315 MultiByteToWideChar(CP_ACP, 0, pName, -1, pwszName, cch + 1); 316 } 317 318 if (pEnvironment) 319 { 320 // Convert pEnvironment to a Unicode string pwszEnvironment. 321 cch = strlen(pEnvironment); 322 323 pwszEnvironment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 324 if (!pwszEnvironment) 325 { 326 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 327 ERR("HeapAlloc failed!\n"); 328 goto Cleanup; 329 } 330 331 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, pwszEnvironment, cch + 1); 332 } 333 334 if (cbBuf && pPrintProcessorInfo) 335 { 336 // Allocate a temporary buffer for the Unicode result. 337 // We can just go with cbBuf here. The user should have set it based on pcbNeeded returned in a previous call and our 338 // pcbNeeded is the same for the A and W functions. 339 pwszPrintProcessorInfo = HeapAlloc(hProcessHeap, 0, cbBuf); 340 if (!pwszPrintProcessorInfo) 341 { 342 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 343 ERR("HeapAlloc failed!\n"); 344 goto Cleanup; 345 } 346 } 347 348 bReturnValue = GetPrintProcessorDirectoryW(pwszName, pwszEnvironment, Level, (PBYTE)pwszPrintProcessorInfo, cbBuf, pcbNeeded); 349 350 if (bReturnValue) 351 { 352 // Convert pwszPrintProcessorInfo to an ANSI string pPrintProcessorInfo. 353 WideCharToMultiByte(CP_ACP, 0, pwszPrintProcessorInfo, -1, (PSTR)pPrintProcessorInfo, cbBuf, NULL, NULL); 354 } 355 356 Cleanup: 357 if (pwszName) 358 HeapFree(hProcessHeap, 0, pwszName); 359 360 if (pwszEnvironment) 361 HeapFree(hProcessHeap, 0, pwszEnvironment); 362 363 if (pwszPrintProcessorInfo) 364 HeapFree(hProcessHeap, 0, pwszPrintProcessorInfo); 365 366 return bReturnValue; 367 } 368 369 BOOL WINAPI 370 GetPrintProcessorDirectoryW(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pPrintProcessorInfo, DWORD cbBuf, PDWORD pcbNeeded) 371 { 372 DWORD dwErrorCode; 373 374 TRACE("GetPrintProcessorDirectoryW(%S, %S, %lu, %p, %lu, %p)\n", pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded); 375 376 // Sanity checks 377 if (Level != 1) 378 { 379 dwErrorCode = ERROR_INVALID_LEVEL; 380 goto Cleanup; 381 } 382 383 // Choose our current environment if the caller didn't give any. 384 if (!pEnvironment) 385 pEnvironment = (PWSTR)wszCurrentEnvironment; 386 387 // Do the RPC call 388 RpcTryExcept 389 { 390 dwErrorCode = _RpcGetPrintProcessorDirectory(pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded); 391 } 392 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 393 { 394 dwErrorCode = RpcExceptionCode(); 395 } 396 RpcEndExcept; 397 398 Cleanup: 399 SetLastError(dwErrorCode); 400 return (dwErrorCode == ERROR_SUCCESS); 401 } 402