1 /* 2 * PROJECT: ReactOS Spooler API 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Functions for managing print jobs 5 * COPYRIGHT: Copyright 2015-2018 Colin Finck (colin@reactos.org) 6 */ 7 8 #include "precomp.h" 9 #include <marshalling/jobs.h> 10 11 BOOL WINAPI 12 AddJobA(HANDLE hPrinter, DWORD Level, PBYTE pData, DWORD cbBuf, PDWORD pcbNeeded) 13 { 14 BOOL ret; 15 16 FIXME("AddJobA(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded); 17 18 if (Level != 1) 19 { 20 ERR("Level = %d, unsupported!\n", Level); 21 SetLastError(ERROR_INVALID_LEVEL); 22 return FALSE; 23 } 24 25 ret = AddJobW(hPrinter, Level, pData, cbBuf, pcbNeeded); 26 27 if (ret) 28 { 29 DWORD dwErrorCode; 30 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)pData; 31 dwErrorCode = UnicodeToAnsiInPlace(addjobW->Path); 32 if (dwErrorCode != ERROR_SUCCESS) 33 { 34 ret = FALSE; 35 } 36 } 37 return ret; 38 } 39 40 BOOL WINAPI 41 AddJobW(HANDLE hPrinter, DWORD Level, PBYTE pData, DWORD cbBuf, PDWORD pcbNeeded) 42 { 43 DWORD dwErrorCode; 44 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 45 46 FIXME("AddJobW(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded); 47 48 if (!pHandle) 49 { 50 dwErrorCode = ERROR_INVALID_HANDLE; 51 goto Cleanup; 52 } 53 54 // Do the RPC call 55 RpcTryExcept 56 { 57 dwErrorCode = _RpcAddJob(pHandle->hPrinter, Level, pData, cbBuf, pcbNeeded); 58 } 59 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 60 { 61 dwErrorCode = RpcExceptionCode(); 62 ERR("_RpcAddJob failed with exception code %lu!\n", dwErrorCode); 63 } 64 RpcEndExcept; 65 66 if (dwErrorCode == ERROR_SUCCESS) 67 { 68 JOB_INFO_1W* pji1w = (JOB_INFO_1W*)pData; 69 70 // Replace relative offset addresses in the output by absolute pointers. 71 MarshallUpStructure(cbBuf, pData, AddJobInfo1Marshalling.pInfo, AddJobInfo1Marshalling.cbStructureSize, TRUE); 72 pHandle->bJob = TRUE; 73 UpdateTrayIcon( hPrinter, pji1w->JobId ); 74 } 75 76 Cleanup: 77 SetLastError(dwErrorCode); 78 return (dwErrorCode == ERROR_SUCCESS); 79 } 80 81 BOOL WINAPI 82 EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) 83 { 84 DWORD dwErrorCode, i; 85 JOB_INFO_1W* pji1w = (JOB_INFO_1W*)pJob; 86 JOB_INFO_2A* pji2a = (JOB_INFO_2A*)pJob; 87 JOB_INFO_2W* pji2w = (JOB_INFO_2W*)pJob; 88 89 TRACE("EnumJobsA(%p, %lu, %lu, %lu, %p, %lu, %p, %p)\n", hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned); 90 91 if ( Level == 3 ) 92 return EnumJobsW( hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned ); 93 94 if ( EnumJobsW( hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned ) ) 95 { 96 switch ( Level ) 97 { 98 case 1: 99 { 100 for ( i = 0; i < *pcReturned; i++ ) 101 { 102 dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pPrinterName); 103 if (dwErrorCode != ERROR_SUCCESS) 104 { 105 goto Cleanup; 106 } 107 dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pMachineName); 108 if (dwErrorCode != ERROR_SUCCESS) 109 { 110 goto Cleanup; 111 } 112 dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pUserName); 113 if (dwErrorCode != ERROR_SUCCESS) 114 { 115 goto Cleanup; 116 } 117 dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pDocument); 118 if (dwErrorCode != ERROR_SUCCESS) 119 { 120 goto Cleanup; 121 } 122 dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pDatatype); 123 if (dwErrorCode != ERROR_SUCCESS) 124 { 125 goto Cleanup; 126 } 127 dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pStatus); 128 if (dwErrorCode != ERROR_SUCCESS) 129 { 130 goto Cleanup; 131 } 132 } 133 } 134 break; 135 136 case 2: 137 { 138 for ( i = 0; i < *pcReturned; i++ ) 139 { 140 dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pPrinterName); 141 if (dwErrorCode != ERROR_SUCCESS) 142 { 143 goto Cleanup; 144 } 145 dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pMachineName); 146 if (dwErrorCode != ERROR_SUCCESS) 147 { 148 goto Cleanup; 149 } 150 dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pUserName); 151 if (dwErrorCode != ERROR_SUCCESS) 152 { 153 goto Cleanup; 154 } 155 dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pDocument); 156 if (dwErrorCode != ERROR_SUCCESS) 157 { 158 goto Cleanup; 159 } 160 dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pNotifyName); 161 if (dwErrorCode != ERROR_SUCCESS) 162 { 163 goto Cleanup; 164 } 165 dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pDatatype); 166 if (dwErrorCode != ERROR_SUCCESS) 167 { 168 goto Cleanup; 169 } 170 dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pPrintProcessor); 171 if (dwErrorCode != ERROR_SUCCESS) 172 { 173 goto Cleanup; 174 } 175 dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pParameters); 176 if (dwErrorCode != ERROR_SUCCESS) 177 { 178 goto Cleanup; 179 } 180 dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pStatus); 181 if (dwErrorCode != ERROR_SUCCESS) 182 { 183 goto Cleanup; 184 } 185 if ( pji2w[i].pDevMode ) 186 { 187 RosConvertUnicodeDevModeToAnsiDevmode( pji2w[i].pDevMode, pji2a[i].pDevMode ); 188 } 189 } 190 } 191 break; 192 } 193 return TRUE; 194 } 195 Cleanup: 196 return FALSE; 197 } 198 199 BOOL WINAPI 200 EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) 201 { 202 DWORD dwErrorCode; 203 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 204 205 TRACE("EnumJobsW(%p, %lu, %lu, %lu, %p, %lu, %p, %p)\n", hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned); 206 207 if (!pHandle) 208 { 209 dwErrorCode = ERROR_INVALID_HANDLE; 210 goto Cleanup; 211 } 212 213 // Do the RPC call 214 RpcTryExcept 215 { 216 dwErrorCode = _RpcEnumJobs(pHandle->hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned); 217 } 218 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 219 { 220 dwErrorCode = RpcExceptionCode(); 221 ERR("_RpcEnumJobs failed with exception code %lu!\n", dwErrorCode); 222 } 223 RpcEndExcept; 224 225 if (dwErrorCode == ERROR_SUCCESS) 226 { 227 // Replace relative offset addresses in the output by absolute pointers for JOB_INFO_1W and JOB_INFO_2W. 228 if (Level <= 2) 229 { 230 ASSERT(Level >= 1); 231 MarshallUpStructuresArray(cbBuf, pJob, *pcReturned, pJobInfoMarshalling[Level]->pInfo, pJobInfoMarshalling[Level]->cbStructureSize, TRUE); 232 } 233 } 234 235 Cleanup: 236 SetLastError(dwErrorCode); 237 return (dwErrorCode == ERROR_SUCCESS); 238 } 239 240 BOOL WINAPI 241 GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD pcbNeeded) 242 { 243 DWORD dwErrorCode; 244 JOB_INFO_1W* pji1w = (JOB_INFO_1W*)pJob; 245 JOB_INFO_2A* pji2a = (JOB_INFO_2A*)pJob; 246 JOB_INFO_2W* pji2w = (JOB_INFO_2W*)pJob; 247 248 FIXME("GetJobA(%p, %lu, %lu, %p, %lu, %p)\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded); 249 250 if ( Level == 3 ) 251 return GetJobW( hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded ); 252 253 if ( GetJobW( hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded ) ) 254 { 255 switch ( Level ) 256 { 257 case 1: 258 dwErrorCode = UnicodeToAnsiInPlace(pji1w->pPrinterName); 259 if (dwErrorCode != ERROR_SUCCESS) 260 { 261 goto Cleanup; 262 } 263 dwErrorCode = UnicodeToAnsiInPlace(pji1w->pMachineName); 264 if (dwErrorCode != ERROR_SUCCESS) 265 { 266 goto Cleanup; 267 } 268 dwErrorCode = UnicodeToAnsiInPlace(pji1w->pUserName); 269 if (dwErrorCode != ERROR_SUCCESS) 270 { 271 goto Cleanup; 272 } 273 dwErrorCode = UnicodeToAnsiInPlace(pji1w->pDocument); 274 if (dwErrorCode != ERROR_SUCCESS) 275 { 276 goto Cleanup; 277 } 278 dwErrorCode = UnicodeToAnsiInPlace(pji1w->pDatatype); 279 if (dwErrorCode != ERROR_SUCCESS) 280 { 281 goto Cleanup; 282 } 283 dwErrorCode = UnicodeToAnsiInPlace(pji1w->pStatus); 284 if (dwErrorCode != ERROR_SUCCESS) 285 { 286 goto Cleanup; 287 } 288 break; 289 290 case 2: 291 dwErrorCode = UnicodeToAnsiInPlace(pji2w->pPrinterName); 292 if (dwErrorCode != ERROR_SUCCESS) 293 { 294 goto Cleanup; 295 } 296 dwErrorCode = UnicodeToAnsiInPlace(pji2w->pMachineName); 297 if (dwErrorCode != ERROR_SUCCESS) 298 { 299 goto Cleanup; 300 } 301 dwErrorCode = UnicodeToAnsiInPlace(pji2w->pUserName); 302 if (dwErrorCode != ERROR_SUCCESS) 303 { 304 goto Cleanup; 305 } 306 dwErrorCode = UnicodeToAnsiInPlace(pji2w->pDocument); 307 if (dwErrorCode != ERROR_SUCCESS) 308 { 309 goto Cleanup; 310 } 311 dwErrorCode = UnicodeToAnsiInPlace(pji2w->pNotifyName); 312 if (dwErrorCode != ERROR_SUCCESS) 313 { 314 goto Cleanup; 315 } 316 dwErrorCode = UnicodeToAnsiInPlace(pji2w->pDatatype); 317 if (dwErrorCode != ERROR_SUCCESS) 318 { 319 goto Cleanup; 320 } 321 dwErrorCode = UnicodeToAnsiInPlace(pji2w->pPrintProcessor); 322 if (dwErrorCode != ERROR_SUCCESS) 323 { 324 goto Cleanup; 325 } 326 dwErrorCode = UnicodeToAnsiInPlace(pji2w->pParameters); 327 if (dwErrorCode != ERROR_SUCCESS) 328 { 329 goto Cleanup; 330 } 331 dwErrorCode = UnicodeToAnsiInPlace(pji2w->pStatus); 332 if (dwErrorCode != ERROR_SUCCESS) 333 { 334 goto Cleanup; 335 } 336 if ( pji2w->pDevMode ) 337 { 338 RosConvertUnicodeDevModeToAnsiDevmode( pji2w->pDevMode, pji2a->pDevMode ); 339 } 340 break; 341 } 342 return TRUE; 343 } 344 Cleanup: 345 return FALSE; 346 } 347 348 BOOL WINAPI 349 GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD pcbNeeded) 350 { 351 DWORD dwErrorCode; 352 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 353 354 FIXME("GetJobW(%p, %lu, %lu, %p, %lu, %p)\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded); 355 356 if (!pHandle) 357 { 358 dwErrorCode = ERROR_INVALID_HANDLE; 359 goto Cleanup; 360 } 361 362 // Do the RPC call 363 RpcTryExcept 364 { 365 dwErrorCode = _RpcGetJob(pHandle->hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded); 366 } 367 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 368 { 369 dwErrorCode = RpcExceptionCode(); 370 ERR("_RpcGetJob failed with exception code %lu!\n", dwErrorCode); 371 } 372 RpcEndExcept; 373 374 if (dwErrorCode == ERROR_SUCCESS) 375 { 376 // Replace relative offset addresses in the output by absolute pointers. 377 ASSERT(Level >= 1 && Level <= 2); 378 MarshallUpStructure(cbBuf, pJob, pJobInfoMarshalling[Level]->pInfo, pJobInfoMarshalling[Level]->cbStructureSize, TRUE); 379 } 380 381 Cleanup: 382 SetLastError(dwErrorCode); 383 return (dwErrorCode == ERROR_SUCCESS); 384 } 385 386 BOOL WINAPI 387 ScheduleJob(HANDLE hPrinter, DWORD dwJobID) 388 { 389 DWORD dwErrorCode; 390 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 391 392 TRACE("ScheduleJob(%p, %lu)\n", hPrinter, dwJobID); 393 394 if (!pHandle) 395 { 396 dwErrorCode = ERROR_INVALID_HANDLE; 397 goto Cleanup; 398 } 399 400 // Do the RPC call 401 RpcTryExcept 402 { 403 dwErrorCode = _RpcScheduleJob(pHandle->hPrinter, dwJobID); 404 } 405 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 406 { 407 dwErrorCode = RpcExceptionCode(); 408 ERR("_RpcScheduleJob failed with exception code %lu!\n", dwErrorCode); 409 } 410 RpcEndExcept; 411 412 if ( dwErrorCode == ERROR_SUCCESS ) 413 pHandle->bJob = FALSE; 414 415 Cleanup: 416 SetLastError(dwErrorCode); 417 return (dwErrorCode == ERROR_SUCCESS); 418 } 419 420 BOOL WINAPI 421 SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Command) 422 { 423 BOOL ret; 424 LPBYTE JobW; 425 UNICODE_STRING usBuffer; 426 427 TRACE("SetJobA(%p, %lu, %lu, %p, %lu)\n", hPrinter, JobId, Level, pJobInfo, Command); 428 429 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages 430 are all ignored by SetJob, so we don't bother copying them */ 431 switch(Level) 432 { 433 case 0: 434 JobW = NULL; 435 break; 436 case 1: 437 { 438 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJobInfo; 439 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W)); 440 ZeroMemory( info1W, sizeof(JOB_INFO_1W) ); 441 442 JobW = (LPBYTE)info1W; 443 info1W->pUserName = AsciiToUnicode(&usBuffer, info1A->pUserName); 444 info1W->pDocument = AsciiToUnicode(&usBuffer, info1A->pDocument); 445 info1W->pDatatype = AsciiToUnicode(&usBuffer, info1A->pDatatype); 446 info1W->pStatus = AsciiToUnicode(&usBuffer, info1A->pStatus); 447 info1W->Status = info1A->Status; 448 info1W->Priority = info1A->Priority; 449 info1W->Position = info1A->Position; 450 info1W->PagesPrinted = info1A->PagesPrinted; 451 break; 452 } 453 case 2: 454 { 455 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJobInfo; 456 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W)); 457 ZeroMemory( info2W, sizeof(JOB_INFO_2W) ); 458 459 JobW = (LPBYTE)info2W; 460 info2W->pUserName = AsciiToUnicode(&usBuffer, info2A->pUserName); 461 info2W->pDocument = AsciiToUnicode(&usBuffer, info2A->pDocument); 462 info2W->pNotifyName = AsciiToUnicode(&usBuffer, info2A->pNotifyName); 463 info2W->pDatatype = AsciiToUnicode(&usBuffer, info2A->pDatatype); 464 info2W->pPrintProcessor = AsciiToUnicode(&usBuffer, info2A->pPrintProcessor); 465 info2W->pParameters = AsciiToUnicode(&usBuffer, info2A->pParameters); 466 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL; 467 info2W->pStatus = AsciiToUnicode(&usBuffer, info2A->pStatus); 468 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor; 469 info2W->Status = info2A->Status; 470 info2W->Priority = info2A->Priority; 471 info2W->Position = info2A->Position; 472 info2W->StartTime = info2A->StartTime; 473 info2W->UntilTime = info2A->UntilTime; 474 info2W->PagesPrinted = info2A->PagesPrinted; 475 break; 476 } 477 case 3: 478 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3)); 479 memcpy(JobW, pJobInfo, sizeof(JOB_INFO_3)); 480 break; 481 default: 482 ERR("Level = %d, unsupported!\n", Level); 483 SetLastError(ERROR_INVALID_LEVEL); 484 return FALSE; 485 } 486 487 ret = SetJobW(hPrinter, JobId, Level, JobW, Command); 488 489 switch(Level) 490 { 491 case 1: 492 { 493 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW; 494 if (info1W->pUserName) HeapFree(GetProcessHeap(), 0, info1W->pUserName); 495 if (info1W->pDocument) HeapFree(GetProcessHeap(), 0, info1W->pDocument); 496 if (info1W->pDatatype) HeapFree(GetProcessHeap(), 0, info1W->pDatatype); 497 if (info1W->pStatus) HeapFree(GetProcessHeap(), 0, info1W->pStatus); 498 break; 499 } 500 case 2: 501 { 502 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW; 503 if (info2W->pUserName) HeapFree(GetProcessHeap(), 0, info2W->pUserName); 504 if (info2W->pDocument) HeapFree(GetProcessHeap(), 0, info2W->pDocument); 505 if (info2W->pNotifyName) HeapFree(GetProcessHeap(), 0, info2W->pNotifyName); 506 if (info2W->pDatatype) HeapFree(GetProcessHeap(), 0, info2W->pDatatype); 507 if (info2W->pPrintProcessor) HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor); 508 if (info2W->pParameters) HeapFree(GetProcessHeap(), 0, info2W->pParameters); 509 if (info2W->pDevMode) HeapFree(GetProcessHeap(), 0, info2W->pDevMode); 510 if (info2W->pStatus) HeapFree(GetProcessHeap(), 0, info2W->pStatus); 511 break; 512 } 513 } 514 HeapFree(GetProcessHeap(), 0, JobW); 515 516 return ret; 517 } 518 519 BOOL WINAPI 520 SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Command) 521 { 522 DWORD dwErrorCode; 523 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 524 WINSPOOL_JOB_CONTAINER JobContainer; 525 526 TRACE("SetJobW(%p, %lu, %lu, %p, %lu)\n", hPrinter, JobId, Level, pJobInfo, Command); 527 528 if (!pHandle) 529 { 530 dwErrorCode = ERROR_INVALID_HANDLE; 531 goto Cleanup; 532 } 533 534 // pJobContainer->JobInfo is a union of pointers, so we can just set any element to our BYTE pointer. 535 JobContainer.Level = Level; 536 JobContainer.JobInfo.Level1 = (WINSPOOL_JOB_INFO_1*)pJobInfo; 537 538 // Do the RPC call 539 RpcTryExcept 540 { 541 dwErrorCode = _RpcSetJob(pHandle->hPrinter, JobId, &JobContainer, Command); 542 } 543 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 544 { 545 dwErrorCode = RpcExceptionCode(); 546 ERR("_RpcSetJob failed with exception code %lu!\n", dwErrorCode); 547 } 548 RpcEndExcept; 549 550 Cleanup: 551 SetLastError(dwErrorCode); 552 return (dwErrorCode == ERROR_SUCCESS); 553 } 554