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